Compare commits

...
Author SHA1 Message Date
StandardNotes CI 8553914d08 chore(release): publish
- @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-10-12 19:22:17 +00:00
Mo 18c821d8eb feat: replace private workspaces with private usernames (#1783) 2022-10-12 13:52:34 -05:00
StandardNotes CI 038e456c6a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-10-12 17:11:49 +00:00
Aman Harwara 37abac2ec2 fix: bidirectional linking indicator for files 2022-10-12 22:01:42 +05:30
Aman Harwara 81532f2f20 refactor: item linking (#1781) 2022-10-12 21:57:51 +05:30
StandardNotes CI 2b89ad488f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-10-12 15:57:21 +00:00
Aman Harwara 075d7f444d fix: css variable fallback 2022-10-12 20:58:02 +05:30
StandardNotes CI a2dc739686 chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-10-12 12:41:26 +00:00
Karol Sójko fabce1f7ac feat(api): add keyshare initiation for workspaces 2022-10-12 14:05:11 +02:00
StandardNotes CI 3fbbacfc25 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-10-11 19:52:04 +00:00
Aman Harwara 990939318f fix: viewport height-related issue on mobile 2022-10-12 00:54:15 +05:30
StandardNotes CI 46e3cae804 chore(release): publish
- @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-10-11 18:53:18 +00:00
Aman Harwara e3f28421ff feat: item linking (#1779) 2022-10-11 23:54:00 +05:30
StandardNotes CI d22c164e5d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
2022-10-11 14:53:46 +00:00
Mo 5cf37037b7 chore(mobile): podfile.lock 2022-10-11 09:23:31 -05:00
Mo 9fc77d861e fix(mobile): issue with black screen on iOS (#1777) 2022-10-11 09:08:34 -05:00
StandardNotes CI b80b04d374 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
2022-10-11 13:04:23 +00:00
Mo b82eac09a8 fix: package import location 2022-10-11 07:30:49 -05:00
StandardNotes CI 7c9f0d3143 chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].7
2022-10-11 10:54:24 +00:00
Karol Sójko fb41f651ec feat(api): add listing workspace users 2022-10-11 12:21:06 +02:00
StandardNotes CI 7a43e2d368 chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-10-11 10:20:35 +00:00
Karol Sójko 49b3d2714f feat(api): add access level to invitation requests 2022-10-11 11:46:27 +02:00
StandardNotes CI 1540143dad chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-10-11 09:26:07 +00:00
Karol Sójko 8376381981 feat(api): add listing workspaces 2022-10-11 10:57:24 +02:00
Karol Sójko 15e2c82e65 feat(api): add accepting invites to workspace 2022-10-11 10:33:23 +02:00
StandardNotes CI 1c22c1ab0c chore(release): publish
- @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-10-10 16:50:35 +00:00
Aman Harwara 27d2c95b5b fix: dark mode not working in editors (#1773) 2022-10-10 21:47:57 +05:30
StandardNotes CI dcb8024deb chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-10-10 11:26:23 +00:00
Karol Sójko 85d2415625 fix(api): specs 2022-10-10 12:54:22 +02:00
Karol Sójko e2e7605414 fix: linter issues 2022-10-10 12:24:03 +02:00
Karol Sójko 158ca6ac6a feat(api): add inviting to workspace 2022-10-10 11:57:44 +02:00
Karol Sójko a275a45753 fix(api): workspace creation arguments 2022-10-10 10:40:46 +02:00
StandardNotes CI 8863ee82bb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-10-09 15:47:24 +00:00
Aman Harwara 6a4b5c5cdc fix: move viewport early return above 2022-10-09 20:39:48 +05:30
Aman Harwara cd1669f56f fix: potential fix for viewport height issue (#1772) 2022-10-09 20:37:44 +05:30
StandardNotes CI 037007f0ec chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-10-08 08:12:13 +00:00
Aman Harwara e7ca12babe fix: open upgrade page in new tab if user has account 2022-10-08 13:12:32 +05:30
StandardNotes CI c4c33db1a4 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-10-07 20:41:32 +00:00
Aman Harwara 734b986294 feat: open purchase flow when clicking upgrade cta with no account (#1771) 2022-10-08 01:39:40 +05:30
Aman Harwara 59db63f052 feat: change quick settings menu layout (#1770) 2022-10-08 01:08:54 +05:30
Mo 20226c3269 fix(desktop): use different method to send messages across main and render without node integration in preload (#1769) 2022-10-07 14:30:07 -05:00
StandardNotes CI a1352d9f65 chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
2022-10-07 13:57:12 +00:00
Mo 7d21046b51 feat(mobile): delete account option in settings (#1768) 2022-10-07 08:23:18 -05:00
Mo a365c17c46 fix(mobile): disable landscape for iPhone 2022-10-07 07:27:37 -05:00
StandardNotes CI c1981334e1 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-10-07 10:51:03 +00:00
Aman Harwara 1e3acd50e9 fix: add fallback for viewport height on mobile (#1766) 2022-10-07 15:41:45 +05:30
StandardNotes CI 8de6023848 chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-10-07 09:13:30 +00:00
Karol Sójko 01ba715eba feat(api): add workspaces api (#1765)
* feat(api): add workspaces api

* fix(api): lint issues
2022-10-07 10:36:30 +02:00
204 changed files with 4560 additions and 1792 deletions
+55
View File
@@ -3,6 +3,61 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.16.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/api
# [1.16.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
### Features
* **api:** add keyshare initiation for workspaces ([fabce1f](https://github.com/standardnotes/app/commit/fabce1f7aca5c9caaa5bb3908b2dc68063c690d0))
## [1.15.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/api
# [1.15.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
# [1.14.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add access level to invitation requests ([49b3d27](https://github.com/standardnotes/app/commit/49b3d2714fbe4ac9f9242097b8df6b4e3d604513))
# [1.13.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add accepting invites to workspace ([15e2c82](https://github.com/standardnotes/app/commit/15e2c82e654ce3f983cd42b01f14d18435b3e939))
* **api:** add listing workspaces ([8376381](https://github.com/standardnotes/app/commit/837638198112df24c30e53803a7ddf5f841975b0))
## [1.12.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/api
# [1.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** specs ([85d2415](https://github.com/standardnotes/app/commit/85d24156254015914c684f900c77c080caa52eb7))
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
* linter issues ([e2e7605](https://github.com/standardnotes/app/commit/e2e76054142e8d67cac69280e2a3efcb15cf67f1))
### Features
* **api:** add inviting to workspace ([158ca6a](https://github.com/standardnotes/app/commit/158ca6ac6a428e082c8f984791f80fcaadcb3e34))
# [1.11.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
### Features
* **api:** add workspaces api ([#1765](https://github.com/standardnotes/app/issues/1765)) ([01ba715](https://github.com/standardnotes/app/commit/01ba715eba987a7da1ee062fec0b3593a7a453ed))
# [1.10.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features
+4 -4
View File
@@ -10,10 +10,10 @@ module.exports = {
},
coverageThreshold: {
global: {
branches: 20,
functions: 66,
lines: 63,
statements: 63
branches: 22,
functions: 69,
lines: 67,
statements: 67
}
}
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.10.0",
"version": "1.16.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -36,7 +36,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
@@ -0,0 +1,8 @@
export enum WorkspaceApiOperations {
Creating,
Inviting,
Accepting,
ListingWorkspaces,
ListingWorkspaceUsers,
InitiatingKeyshare,
}
@@ -0,0 +1,368 @@
import { WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { HttpStatusCode } from '../../Http'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
import { WorkspaceApiService } from './WorkspaceApiService'
describe('WorkspaceApiService', () => {
let workspaceServer: WorkspaceServerInterface
const createService = () => new WorkspaceApiService(workspaceServer)
beforeEach(() => {
workspaceServer = {} as jest.Mocked<WorkspaceServerInterface>
workspaceServer.createWorkspace = jest.fn().mockReturnValue({
data: { uuid: '1-2-3' },
} as jest.Mocked<WorkspaceCreationResponse>)
workspaceServer.inviteToWorkspace = jest.fn().mockReturnValue({
data: { uuid: 'i-1-2-3' },
} as jest.Mocked<WorkspaceInvitationResponse>)
workspaceServer.acceptInvite = jest.fn().mockReturnValue({
data: { success: true },
} as jest.Mocked<WorkspaceInvitationAcceptingResponse>)
workspaceServer.listWorkspaces = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
} as jest.Mocked<WorkspaceListResponse>)
workspaceServer.listWorkspaceUsers = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { users: [] },
} as jest.Mocked<WorkspaceUserListResponse>)
workspaceServer.initiateKeyshare = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { success: true },
} as jest.Mocked<WorkspaceKeyshareInitiatingResponse>)
})
it('should create a workspace', async () => {
const response = await createService().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
})
expect(response).toEqual({
data: {
uuid: '1-2-3',
},
})
expect(workspaceServer.createWorkspace).toHaveBeenCalledWith({
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
workspaceType: 'private',
})
})
it('should not create a workspace if it is already creating', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.Creating, true]]),
})
let error = null
try {
await service.createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not create a workspace if the server fails', async () => {
workspaceServer.createWorkspace = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should invite to a workspace', async () => {
const response = await createService().inviteToWorkspace({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
accessLevel: WorkspaceAccessLevel.WriteAndRead,
})
expect(response).toEqual({
data: {
uuid: 'i-1-2-3',
},
})
expect(workspaceServer.inviteToWorkspace).toHaveBeenCalledWith({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
accessLevel: 'write-and-read',
})
})
it('should not invite to a workspace if it is already inviting', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.Inviting, true]]),
})
let error = null
try {
await service.inviteToWorkspace({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
accessLevel: WorkspaceAccessLevel.WriteAndRead,
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not invite to a workspace if the server fails', async () => {
workspaceServer.inviteToWorkspace = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().inviteToWorkspace({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
accessLevel: WorkspaceAccessLevel.WriteAndRead,
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should accept invite to a workspace', async () => {
const response = await createService().acceptInvite({
userUuid: 'u-1-2-3',
inviteUuid: 'i-1-2-3',
publicKey: 'foo',
encryptedPrivateKey: 'bar',
})
expect(response).toEqual({
data: {
success: true,
},
})
expect(workspaceServer.acceptInvite).toHaveBeenCalledWith({
userUuid: 'u-1-2-3',
inviteUuid: 'i-1-2-3',
publicKey: 'foo',
encryptedPrivateKey: 'bar',
})
})
it('should not accept invite to a workspace if it is already accepting', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.Accepting, true]]),
})
let error = null
try {
await service.acceptInvite({
userUuid: 'u-1-2-3',
inviteUuid: 'i-1-2-3',
publicKey: 'foo',
encryptedPrivateKey: 'bar',
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not accept invite to a workspace if the server fails', async () => {
workspaceServer.acceptInvite = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().acceptInvite({
userUuid: 'u-1-2-3',
inviteUuid: 'i-1-2-3',
publicKey: 'foo',
encryptedPrivateKey: 'bar',
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should list workspaces', async () => {
const response = await createService().listWorkspaces()
expect(response).toEqual({
status: 200,
data: {
ownedWorkspaces: [],
joinedWorkspaces: [],
},
})
expect(workspaceServer.listWorkspaces).toHaveBeenCalled()
})
it('should not list workspaces if it is already listing them', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.ListingWorkspaces, true]]),
})
let error = null
try {
await service.listWorkspaces()
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not list workspaces if the server fails', async () => {
workspaceServer.listWorkspaces = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().listWorkspaces()
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should list workspace users', async () => {
const response = await createService().listWorkspaceUsers({ workspaceUuid: 'w-1-2-3' })
expect(response).toEqual({
status: 200,
data: {
users: [],
},
})
expect(workspaceServer.listWorkspaceUsers).toHaveBeenCalledWith({ workspaceUuid: 'w-1-2-3' })
})
it('should not list workspace users if it is already listing them', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.ListingWorkspaceUsers, true]]),
})
let error = null
try {
await service.listWorkspaceUsers({ workspaceUuid: 'w-1-2-3' })
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not list workspace users if the server fails', async () => {
workspaceServer.listWorkspaceUsers = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().listWorkspaceUsers({ workspaceUuid: 'w-1-2-3' })
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should initiate keyshare in workspace for user', async () => {
const response = await createService().initiateKeyshare({
workspaceUuid: 'w-1-2-3',
userUuid: 'u-1-2-3',
encryptedWorkspaceKey: 'foobar',
})
expect(response).toEqual({
status: 200,
data: {
success: true,
},
})
expect(workspaceServer.initiateKeyshare).toHaveBeenCalledWith({
workspaceUuid: 'w-1-2-3',
userUuid: 'u-1-2-3',
encryptedWorkspaceKey: 'foobar',
})
})
it('should not initiate keyshare in workspace if it is already initiating', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WorkspaceApiOperations.InitiatingKeyshare, true]]),
})
let error = null
try {
await service.initiateKeyshare({ workspaceUuid: 'w-1-2-3', userUuid: 'u-1-2-3', encryptedWorkspaceKey: 'foobar' })
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not initiate keyshare in workspace if the server fails', async () => {
workspaceServer.initiateKeyshare = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().initiateKeyshare({
workspaceUuid: 'w-1-2-3',
userUuid: 'u-1-2-3',
encryptedWorkspaceKey: 'foobar',
})
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
})
@@ -0,0 +1,156 @@
import { Uuid, WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { ErrorMessage } from '../../Error/ErrorMessage'
import { ApiCallError } from '../../Error/ApiCallError'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
import { WorkspaceApiServiceInterface } from './WorkspaceApiServiceInterface'
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
export class WorkspaceApiService implements WorkspaceApiServiceInterface {
private operationsInProgress: Map<WorkspaceApiOperations, boolean>
constructor(private workspaceServer: WorkspaceServerInterface) {
this.operationsInProgress = new Map()
}
async initiateKeyshare(dto: {
workspaceUuid: string
userUuid: string
encryptedWorkspaceKey: string
}): Promise<WorkspaceKeyshareInitiatingResponse> {
this.lockOperation(WorkspaceApiOperations.InitiatingKeyshare)
try {
const response = await this.workspaceServer.initiateKeyshare({
workspaceUuid: dto.workspaceUuid,
userUuid: dto.userUuid,
encryptedWorkspaceKey: dto.encryptedWorkspaceKey,
})
this.unlockOperation(WorkspaceApiOperations.InitiatingKeyshare)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
async listWorkspaceUsers(dto: { workspaceUuid: string }): Promise<WorkspaceUserListResponse> {
this.lockOperation(WorkspaceApiOperations.ListingWorkspaceUsers)
try {
const response = await this.workspaceServer.listWorkspaceUsers({ workspaceUuid: dto.workspaceUuid })
this.unlockOperation(WorkspaceApiOperations.ListingWorkspaceUsers)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
async listWorkspaces(): Promise<WorkspaceListResponse> {
this.lockOperation(WorkspaceApiOperations.ListingWorkspaces)
try {
const response = await this.workspaceServer.listWorkspaces({})
this.unlockOperation(WorkspaceApiOperations.ListingWorkspaces)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
async acceptInvite(dto: {
inviteUuid: string
userUuid: string
publicKey: string
encryptedPrivateKey: string
}): Promise<WorkspaceInvitationAcceptingResponse> {
this.lockOperation(WorkspaceApiOperations.Accepting)
try {
const response = await this.workspaceServer.acceptInvite({
encryptedPrivateKey: dto.encryptedPrivateKey,
publicKey: dto.publicKey,
inviteUuid: dto.inviteUuid,
userUuid: dto.userUuid,
})
this.unlockOperation(WorkspaceApiOperations.Accepting)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
async inviteToWorkspace(dto: {
inviteeEmail: string
workspaceUuid: Uuid
accessLevel: WorkspaceAccessLevel
}): Promise<WorkspaceInvitationResponse> {
this.lockOperation(WorkspaceApiOperations.Inviting)
try {
const response = await this.workspaceServer.inviteToWorkspace({
inviteeEmail: dto.inviteeEmail,
workspaceUuid: dto.workspaceUuid,
accessLevel: dto.accessLevel,
})
this.unlockOperation(WorkspaceApiOperations.Inviting)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
async createWorkspace(dto: {
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<WorkspaceCreationResponse> {
this.lockOperation(WorkspaceApiOperations.Creating)
try {
const response = await this.workspaceServer.createWorkspace({
workspaceType: dto.workspaceType,
encryptedPrivateKey: dto.encryptedPrivateKey,
encryptedWorkspaceKey: dto.encryptedWorkspaceKey,
publicKey: dto.publicKey,
workspaceName: dto.workspaceName,
})
this.unlockOperation(WorkspaceApiOperations.Creating)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
private lockOperation(operation: WorkspaceApiOperations): void {
if (this.operationsInProgress.get(operation)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(operation, true)
}
private unlockOperation(operation: WorkspaceApiOperations): void {
this.operationsInProgress.set(operation, false)
}
}
@@ -0,0 +1,36 @@
import { Uuid, WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
export interface WorkspaceApiServiceInterface {
createWorkspace(dto: {
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<WorkspaceCreationResponse>
inviteToWorkspace(dto: {
inviteeEmail: string
workspaceUuid: Uuid
accessLevel: WorkspaceAccessLevel
}): Promise<WorkspaceInvitationResponse>
acceptInvite(dto: {
inviteUuid: Uuid
userUuid: Uuid
publicKey: string
encryptedPrivateKey: string
}): Promise<WorkspaceInvitationAcceptingResponse>
listWorkspaces(): Promise<WorkspaceListResponse>
listWorkspaceUsers(dto: { workspaceUuid: Uuid }): Promise<WorkspaceUserListResponse>
initiateKeyshare(dto: {
workspaceUuid: Uuid
userUuid: Uuid
encryptedWorkspaceKey: string
}): Promise<WorkspaceKeyshareInitiatingResponse>
}
+2
View File
@@ -5,3 +5,5 @@ export * from './User/UserApiService'
export * from './User/UserApiServiceInterface'
export * from './WebSocket/WebSocketApiService'
export * from './WebSocket/WebSocketApiServiceInterface'
export * from './Workspace/WorkspaceApiService'
export * from './Workspace/WorkspaceApiServiceInterface'
@@ -0,0 +1,10 @@
import { WorkspaceType } from '@standardnotes/common'
export type WorkspaceCreationRequestParams = {
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
[additionalParam: string]: unknown
}
@@ -0,0 +1,9 @@
import { Uuid } from '@standardnotes/common'
export type WorkspaceInvitationAcceptingRequestParams = {
inviteUuid: Uuid
userUuid: Uuid
publicKey: string
encryptedPrivateKey: string
[additionalParam: string]: unknown
}
@@ -0,0 +1,8 @@
import { Uuid, WorkspaceAccessLevel } from '@standardnotes/common'
export type WorkspaceInvitationRequestParams = {
workspaceUuid: Uuid
inviteeEmail: string
accessLevel: WorkspaceAccessLevel
[additionalParam: string]: unknown
}
@@ -0,0 +1,8 @@
import { Uuid } from '@standardnotes/common'
export type WorkspaceKeyshareInitiatingRequestParams = {
userUuid: Uuid
workspaceUuid: Uuid
encryptedWorkspaceKey: string
[additionalParam: string]: unknown
}
@@ -0,0 +1,3 @@
export type WorkspaceListRequestParams = {
[additionalParam: string]: unknown
}
@@ -0,0 +1,6 @@
import { Uuid } from '@standardnotes/common'
export type WorkspaceUserListRequestParams = {
workspaceUuid: Uuid
[additionalParam: string]: unknown
}
+6
View File
@@ -6,3 +6,9 @@ export * from './Subscription/SubscriptionInviteListRequestParams'
export * from './Subscription/SubscriptionInviteRequestParams'
export * from './User/UserRegistrationRequestParams'
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
export * from './Workspace/WorkspaceCreationRequestParams'
export * from './Workspace/WorkspaceInvitationAcceptingRequestParams'
export * from './Workspace/WorkspaceInvitationRequestParams'
export * from './Workspace/WorkspaceKeyshareInitiatingRequestParams'
export * from './Workspace/WorkspaceListRequestParams'
export * from './Workspace/WorkspaceUserListRequestParams'
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceCreationResponseBody } from './WorkspaceCreationResponseBody'
export interface WorkspaceCreationResponse extends HttpResponse {
data: Either<WorkspaceCreationResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,3 @@
export type WorkspaceCreationResponseBody = {
uuid: string
}
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceInvitationAcceptingResponseBody } from './WorkspaceInvitationAcceptingResponseBody'
export interface WorkspaceInvitationAcceptingResponse extends HttpResponse {
data: Either<WorkspaceInvitationAcceptingResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,3 @@
export type WorkspaceInvitationAcceptingResponseBody = {
success: boolean
}
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceInvitationResponseBody } from './WorkspaceInvitationResponseBody'
export interface WorkspaceInvitationResponse extends HttpResponse {
data: Either<WorkspaceInvitationResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,3 @@
export type WorkspaceInvitationResponseBody = {
uuid: string
}
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceKeyshareInitiatingResponseBody } from './WorkspaceKeyshareInitiatingResponseBody'
export interface WorkspaceKeyshareInitiatingResponse extends HttpResponse {
data: Either<WorkspaceKeyshareInitiatingResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,3 @@
export type WorkspaceKeyshareInitiatingResponseBody = {
success: boolean
}
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceListResponseBody } from './WorkspaceListResponseBody'
export interface WorkspaceListResponse extends HttpResponse {
data: Either<WorkspaceListResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,6 @@
import { Workspace } from '@standardnotes/models'
export type WorkspaceListResponseBody = {
ownedWorkspaces: Array<Workspace>
joinedWorkspaces: Array<Workspace>
}
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WorkspaceUserListResponseBody } from './WorkspaceUserListResponseBody'
export interface WorkspaceUserListResponse extends HttpResponse {
data: Either<WorkspaceUserListResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,5 @@
import { WorkspaceUser } from '@standardnotes/models'
export type WorkspaceUserListResponseBody = {
users: Array<WorkspaceUser>
}
+12
View File
@@ -12,3 +12,15 @@ export * from './User/UserRegistrationResponse'
export * from './User/UserRegistrationResponseBody'
export * from './WebSocket/WebSocketConnectionTokenResponse'
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
export * from './Workspace/WorkspaceCreationResponse'
export * from './Workspace/WorkspaceCreationResponseBody'
export * from './Workspace/WorkspaceInvitationAcceptingResponse'
export * from './Workspace/WorkspaceInvitationAcceptingResponseBody'
export * from './Workspace/WorkspaceKeyshareInitiatingResponse'
export * from './Workspace/WorkspaceKeyshareInitiatingResponseBody'
export * from './Workspace/WorkspaceInvitationResponse'
export * from './Workspace/WorkspaceInvitationResponseBody'
export * from './Workspace/WorkspaceListResponse'
export * from './Workspace/WorkspaceListResponseBody'
export * from './Workspace/WorkspaceUserListResponse'
export * from './Workspace/WorkspaceUserListResponseBody'
@@ -0,0 +1,17 @@
import { Uuid } from '@standardnotes/common'
const WorkspacePaths = {
createWorkspace: '/v1/workspaces',
listWorkspaces: '/v1/workspaces',
listWorkspaceUsers: (uuid: Uuid) => `/v1/workspaces/${uuid}/users`,
initiateKeyshare: (worksapceUuid: Uuid, userUuid: Uuid) =>
`/v1/workspaces/${worksapceUuid}/users/${userUuid}/keyshare`,
inviteToWorkspace: (uuid: Uuid) => `/v1/workspaces/${uuid}/invites`,
acceptInvite: (uuid: Uuid) => `/v1/invites/${uuid}/accept`,
}
export const Paths = {
v1: {
...WorkspacePaths,
},
}
@@ -0,0 +1,124 @@
import { WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { HttpServiceInterface, HttpStatusCode } from '../../Http'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
import { WorkspaceServer } from './WorkspaceServer'
describe('WorkspaceServer', () => {
let httpService: HttpServiceInterface
const createServer = () => new WorkspaceServer(httpService)
beforeEach(() => {
httpService = {} as jest.Mocked<HttpServiceInterface>
httpService.post = jest.fn().mockReturnValue({
data: { uuid: '1-2-3' },
} as jest.Mocked<WorkspaceCreationResponse>)
})
it('should create a workspace', async () => {
const response = await createServer().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
})
expect(response).toEqual({
data: {
uuid: '1-2-3',
},
})
})
it('should inivte to a workspace', async () => {
httpService.post = jest.fn().mockReturnValue({
data: { uuid: 'i-1-2-3' },
} as jest.Mocked<WorkspaceInvitationResponse>)
const response = await createServer().inviteToWorkspace({
inviteeEmail: '[email protected]',
workspaceUuid: 'w-1-2-3',
accessLevel: WorkspaceAccessLevel.WriteAndRead,
})
expect(response).toEqual({
data: {
uuid: 'i-1-2-3',
},
})
})
it('should accept invitation to a workspace', async () => {
httpService.post = jest.fn().mockReturnValue({
data: { success: true },
} as jest.Mocked<WorkspaceInvitationAcceptingResponse>)
const response = await createServer().acceptInvite({
encryptedPrivateKey: 'foo',
inviteUuid: 'i-1-2-3',
publicKey: 'bar',
userUuid: 'u-1-2-3',
})
expect(response).toEqual({
data: {
success: true,
},
})
})
it('should list workspaces', async () => {
httpService.get = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
} as jest.Mocked<WorkspaceListResponse>)
const response = await createServer().listWorkspaces({})
expect(response).toEqual({
status: 200,
data: { ownedWorkspaces: [], joinedWorkspaces: [] },
})
})
it('should list workspace users', async () => {
httpService.get = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { users: [] },
} as jest.Mocked<WorkspaceUserListResponse>)
const response = await createServer().listWorkspaceUsers({ workspaceUuid: 'w-1-2-3' })
expect(response).toEqual({
status: 200,
data: { users: [] },
})
})
it('should initiate keyshare for user in a workspace', async () => {
httpService.post = jest.fn().mockReturnValue({
status: HttpStatusCode.Success,
data: { success: true },
} as jest.Mocked<WorkspaceKeyshareInitiatingResponse>)
const response = await createServer().initiateKeyshare({
workspaceUuid: 'w-1-2-3',
userUuid: 'u-1-2-3',
encryptedWorkspaceKey: 'foobar',
})
expect(response).toEqual({
status: 200,
data: {
success: true,
},
})
})
})
@@ -0,0 +1,61 @@
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
import { WorkspaceInvitationRequestParams } from '../../Request/Workspace/WorkspaceInvitationRequestParams'
import { WorkspaceCreationRequestParams } from '../../Request/Workspace/WorkspaceCreationRequestParams'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceListRequestParams } from '../../Request/Workspace/WorkspaceListRequestParams'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListRequestParams } from '../../Request/Workspace/WorkspaceUserListRequestParams'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
import { WorkspaceKeyshareInitiatingRequestParams } from '../../Request/Workspace/WorkspaceKeyshareInitiatingRequestParams'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
import { Paths } from './Paths'
import { WorkspaceServerInterface } from './WorkspaceServerInterface'
export class WorkspaceServer implements WorkspaceServerInterface {
constructor(private httpService: HttpServiceInterface) {}
async initiateKeyshare(
params: WorkspaceKeyshareInitiatingRequestParams,
): Promise<WorkspaceKeyshareInitiatingResponse> {
const response = await this.httpService.post(
Paths.v1.initiateKeyshare(params.workspaceUuid, params.userUuid),
params,
)
return response as WorkspaceKeyshareInitiatingResponse
}
async listWorkspaceUsers(params: WorkspaceUserListRequestParams): Promise<WorkspaceUserListResponse> {
const response = await this.httpService.get(Paths.v1.listWorkspaceUsers(params.workspaceUuid), params)
return response as WorkspaceUserListResponse
}
async listWorkspaces(params: WorkspaceListRequestParams): Promise<WorkspaceListResponse> {
const response = await this.httpService.get(Paths.v1.listWorkspaces, params)
return response as WorkspaceListResponse
}
async acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse> {
const response = await this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params)
return response as WorkspaceInvitationAcceptingResponse
}
async inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise<WorkspaceInvitationResponse> {
const response = await this.httpService.post(Paths.v1.inviteToWorkspace(params.workspaceUuid), params)
return response as WorkspaceInvitationResponse
}
async createWorkspace(params: WorkspaceCreationRequestParams): Promise<WorkspaceCreationResponse> {
const response = await this.httpService.post(Paths.v1.createWorkspace, params)
return response as WorkspaceCreationResponse
}
}
@@ -0,0 +1,21 @@
import { WorkspaceInvitationRequestParams } from '../../Request/Workspace/WorkspaceInvitationRequestParams'
import { WorkspaceCreationRequestParams } from '../../Request/Workspace/WorkspaceCreationRequestParams'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingRequestParams } from '../../Request/Workspace/WorkspaceInvitationAcceptingRequestParams'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceListRequestParams } from '../../Request/Workspace/WorkspaceListRequestParams'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceUserListRequestParams } from '../../Request/Workspace/WorkspaceUserListRequestParams'
import { WorkspaceUserListResponse } from '../../Response/Workspace/WorkspaceUserListResponse'
import { WorkspaceKeyshareInitiatingRequestParams } from '../../Request/Workspace/WorkspaceKeyshareInitiatingRequestParams'
import { WorkspaceKeyshareInitiatingResponse } from '../../Response/Workspace/WorkspaceKeyshareInitiatingResponse'
export interface WorkspaceServerInterface {
createWorkspace(params: WorkspaceCreationRequestParams): Promise<WorkspaceCreationResponse>
listWorkspaces(params: WorkspaceListRequestParams): Promise<WorkspaceListResponse>
listWorkspaceUsers(params: WorkspaceUserListRequestParams): Promise<WorkspaceUserListResponse>
inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise<WorkspaceInvitationResponse>
acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse>
initiateKeyshare(params: WorkspaceKeyshareInitiatingRequestParams): Promise<WorkspaceKeyshareInitiatingResponse>
}
+2
View File
@@ -4,3 +4,5 @@ export * from './User/UserServer'
export * from './User/UserServerInterface'
export * from './WebSocket/WebSocketServer'
export * from './WebSocket/WebSocketServerInterface'
export * from './Workspace/WorkspaceServer'
export * from './Workspace/WorkspaceServerInterface'
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.7.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/components-meta
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.16",
"version": "2.7.19",
"private": true,
"author": "Standard Notes.",
"main": "dist",
+70
View File
@@ -3,6 +3,76 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.212](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.211](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.210](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.209](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.208](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.207](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.206](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.205](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.204](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.203](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.202](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.201](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.200](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-09)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.199](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-08)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.198](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
### Bug Fixes
* **desktop:** use different method to send messages across main and render without node integration in preload ([#1769](https://github.com/standardnotes/app/issues/1769)) ([20226c3](https://github.com/standardnotes/app/commit/20226c326945ad9dc524f6dcbfc1c1274befb652))
## [3.23.197](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.196](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.195](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
**Note:** Version bump only for package @standardnotes/desktop
@@ -5,6 +5,7 @@ import { autoUpdater } from 'electron-updater'
import { action, autorun, computed, makeObservable, observable } from 'mobx'
import { MessageType } from '../../../test/TestIpcMessage'
import { AppState } from '../../AppState'
import { MessageToWebApp } from '../Shared/IpcMessages'
import { BackupsManagerInterface } from './Backups/BackupsManagerInterface'
import { StoreKeys } from './Store/StoreKeys'
import { updates as str } from './Strings'
@@ -113,12 +114,12 @@ export function setupUpdates(window: BrowserWindow, appState: AppState, backupsM
setInterval(checkUpdateSafety, oneHour)
autoUpdater.on('update-downloaded', (info: { version?: string }) => {
window.webContents.send('update-available', null)
window.webContents.send(MessageToWebApp.UpdateAvailable, null)
updateState.autoUpdateHasBeenDownloaded(info.version || null)
})
autoUpdater.on('error', logError)
autoUpdater.on('update-available', (info: { version?: string }) => {
autoUpdater.on(MessageToWebApp.UpdateAvailable, (info: { version?: string }) => {
updateState.checkedForUpdate(info.version || null)
if (updateState.enableAutoUpdate) {
const canUpdate = checkUpdateSafety()
@@ -166,6 +166,7 @@ async function createWindow(store: Store): Promise<Electron.BrowserWindow> {
spellcheck: true,
nodeIntegration: isTesting(),
contextIsolation: true,
sandbox: true,
preload: Paths.preloadJs,
},
})
@@ -1,42 +1,28 @@
import { IpcRendererEvent } from 'electron/renderer'
import { MessageToWebApp } from '../Shared/IpcMessages'
const { ipcRenderer } = require('electron')
const path = require('path')
const rendererPath = path.join('file://', __dirname, '/renderer.js')
const RemoteBridge = require('@electron/remote').getGlobal('RemoteBridge')
const { contextBridge } = require('electron')
type MainEventCallback = (event: IpcRendererEvent, value: any) => void
process.once('loaded', function () {
contextBridge.exposeInMainWorld('electronRemoteBridge', RemoteBridge.exposableValue)
listenForIpcEventsFromMainProcess()
contextBridge.exposeInMainWorld('electronMainEvents', {
handleUpdateAvailable: (callback: MainEventCallback) => ipcRenderer.on(MessageToWebApp.UpdateAvailable, callback),
handlePerformAutomatedBackup: (callback: MainEventCallback) =>
ipcRenderer.on(MessageToWebApp.PerformAutomatedBackup, callback),
handleFinishedSavingBackup: (callback: MainEventCallback) =>
ipcRenderer.on(MessageToWebApp.FinishedSavingBackup, callback),
handleWindowBlurred: (callback: MainEventCallback) => ipcRenderer.on(MessageToWebApp.WindowBlurred, callback),
handleWindowFocused: (callback: MainEventCallback) => ipcRenderer.on(MessageToWebApp.WindowFocused, callback),
handleInstallComponentComplete: (callback: MainEventCallback) =>
ipcRenderer.on(MessageToWebApp.InstallComponentComplete, callback),
})
})
function listenForIpcEventsFromMainProcess() {
const sendMessageToRenderProcess = (message: string, payload = {}) => {
window.postMessage(JSON.stringify({ message, data: payload }), rendererPath)
}
ipcRenderer.on(MessageToWebApp.UpdateAvailable, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.UpdateAvailable, data)
})
ipcRenderer.on(MessageToWebApp.PerformAutomatedBackup, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.PerformAutomatedBackup, data)
})
ipcRenderer.on(MessageToWebApp.FinishedSavingBackup, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.FinishedSavingBackup, data)
})
ipcRenderer.on(MessageToWebApp.WindowBlurred, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.WindowBlurred, data)
})
ipcRenderer.on(MessageToWebApp.WindowFocused, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.WindowFocused, data)
})
ipcRenderer.on(MessageToWebApp.InstallComponentComplete, function (_event, data) {
sendMessageToRenderProcess(MessageToWebApp.InstallComponentComplete, data)
})
}
@@ -1,6 +1,6 @@
import { DesktopClientRequiresWebMethods } from '@web/Application/Device/DesktopSnjsExports'
import { StartApplication } from '@web/Application/Device/StartApplication'
import { MessageToWebApp } from '../Shared/IpcMessages'
import { IpcRendererEvent } from 'electron/renderer'
import { CrossProcessBridge } from './CrossProcessBridge'
import { DesktopDevice } from './DesktopDevice'
@@ -23,6 +23,7 @@ declare global {
purchaseUrl: string
startApplication: StartApplication
zip: any
electronMainEvents: any
}
}
@@ -41,8 +42,6 @@ const loadAndStartApplication = async () => {
window.device = await createDesktopDevice(remoteBridge)
window.startApplication(DEFAULT_SYNC_SERVER, window.device, window.enableUnfinishedFeatures, WEBSOCKET_URL)
listenForMessagesSentFromMainToPreloadToUs(window.device)
}
window.onload = () => {
@@ -134,35 +133,26 @@ async function configureWindow(remoteBridge: CrossProcessBridge) {
}
}
function listenForMessagesSentFromMainToPreloadToUs(device: DesktopDevice) {
window.addEventListener('message', async (event) => {
// We don't have access to the full file path.
if (event.origin !== 'file://') {
return
}
let payload
try {
payload = JSON.parse(event.data)
} catch (e) {
// message doesn't belong to us
return
}
const receiver = window.webClient
const message = payload.message
const data = payload.data
window.electronMainEvents.handleUpdateAvailable(() => {
window.webClient.updateAvailable()
})
if (message === MessageToWebApp.WindowBlurred) {
receiver.windowLostFocus()
} else if (message === MessageToWebApp.WindowFocused) {
receiver.windowGainedFocus()
} else if (message === MessageToWebApp.InstallComponentComplete) {
receiver.onComponentInstallationComplete(data.component, undefined)
} else if (message === MessageToWebApp.UpdateAvailable) {
receiver.updateAvailable()
} else if (message === MessageToWebApp.PerformAutomatedBackup) {
void device.downloadBackup()
} else if (message === MessageToWebApp.FinishedSavingBackup) {
receiver.didFinishBackup(data.success)
}
})
}
window.electronMainEvents.handlePerformAutomatedBackup(() => {
void window.device.downloadBackup()
})
window.electronMainEvents.handleFinishedSavingBackup((_: IpcRendererEvent, data: any) => {
window.webClient.didFinishBackup(data.success)
})
window.electronMainEvents.handleWindowBlurred(() => {
window.webClient.windowLostFocus()
})
window.electronMainEvents.handleWindowFocused(() => {
window.webClient.windowGainedFocus()
})
window.electronMainEvents.handleInstallComponentComplete((_: IpcRendererEvent, data: any) => {
window.webClient.onComponentInstallationComplete(data.component, undefined)
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.195",
"version": "3.23.212",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+30
View File
@@ -3,6 +3,36 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.18.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
### Features
* replace private workspaces with private usernames ([#1783](https://github.com/standardnotes/app/issues/1783)) ([18c821d](https://github.com/standardnotes/app/commit/18c821d8eb51beb6f54211eb1d6eb454303044f5))
## [1.17.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/encryption
# [1.17.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [1.16.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/encryption
## [1.16.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/encryption
## [1.16.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
# [1.16.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.16.0",
"version": "1.18.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -35,7 +35,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/sncrypto-common": "workspace:*",
@@ -0,0 +1,19 @@
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
const PrivateUserNameV1 = 'StandardNotes-PrivateUsername-V1'
export async function ComputePrivateUsername(
crypto: PureCryptoInterface,
usernameInput: string,
): Promise<string | undefined> {
const result = await crypto.hmac256(
await crypto.sha256(PrivateUserNameV1),
await crypto.sha256(usernameInput.trim().toLowerCase()),
)
if (result == undefined) {
return undefined
}
return result
}
@@ -1,18 +0,0 @@
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
export async function ComputePrivateWorkspaceIdentifier(
crypto: PureCryptoInterface,
userphrase: string,
name: string,
): Promise<string | undefined> {
const identifier = await crypto.hmac256(
await crypto.sha256(name.trim().toLowerCase()),
await crypto.sha256(userphrase.trim().toLowerCase()),
)
if (identifier == undefined) {
return undefined
}
return identifier
}
+1 -1
View File
@@ -34,4 +34,4 @@ export * from './Types/EncryptedParameters'
export * from './Types/ItemAuthenticatedData'
export * from './Types/LegacyAttachedData'
export * from './Types/RootKeyEncryptedAuthenticatedData'
export * from './Workspace/PrivateWorkspace'
export * from './Username/PrivateUsername'
+18
View File
@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.53.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [1.52.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* dark mode not working in editors ([#1773](https://github.com/standardnotes/app/issues/1773)) ([27d2c95](https://github.com/standardnotes/app/commit/27d2c95b5b82645bf6c0372979f05236c83a10f6))
## [1.52.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
## [1.52.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/features
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/features",
"version": "1.52.2",
"version": "1.53.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -26,7 +26,7 @@
},
"dependencies": {
"@standardnotes/auth": "^3.19.4",
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/security": "^1.2.0",
"reflect-metadata": "^0.1.13"
},
@@ -21,7 +21,7 @@ export enum FeatureIdentifier {
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
DynamicTheme = 'org.standardnotes.theme-dynamic',
FocusedTheme = 'org.standardnotes.theme-focus',
DarkTheme = 'org.standardnotes.theme-focus',
FocusMode = 'org.standardnotes.focus-mode',
FuturaTheme = 'org.standardnotes.theme-futura',
MidnightTheme = 'org.standardnotes.theme-midnight',
+4 -4
View File
@@ -68,10 +68,10 @@ export function themes(): ThemeFeatureDescription[] {
},
})
const focus: ThemeFeatureDescription = FillThemeComponentDefaults({
const dark: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Focus',
identifier: FeatureIdentifier.FocusedTheme,
name: 'Dark',
identifier: FeatureIdentifier.DarkTheme,
permission_name: PermissionName.FocusedTheme,
description: 'For when you need to go in.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
@@ -109,5 +109,5 @@ export function themes(): ThemeFeatureDescription[] {
description: 'A smart theme that minimizes the tags and notes panels when they are not in use.',
})
return [midnight, futura, solarizedDark, autobiography, focus, titanium, dynamic]
return [midnight, futura, solarizedDark, autobiography, dark, titanium, dynamic]
}
+28
View File
@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.24.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.24.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/filepicker
# [1.24.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [1.23.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
## [1.23.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
**Note:** Version bump only for package @standardnotes/filepicker
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.23.12",
"version": "1.24.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -31,7 +31,7 @@
"ts-node": "^10.5.0"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/files": "workspace:*",
"@standardnotes/utils": "workspace:*",
"@types/wicg-file-system-access": "^2020.9.5",
+28
View File
@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/files
## [1.11.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/files
# [1.11.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [1.10.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/files
## [1.10.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/files
## [1.10.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
## [1.10.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
**Note:** Version bump only for package @standardnotes/files
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.10.12",
"version": "1.11.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -30,7 +30,7 @@
"ts-jest": "^28.0.5"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
+86
View File
@@ -3,6 +3,92 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.42.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/mobile
## [3.42.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/mobile
## [3.42.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/mobile
## [3.42.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/mobile
## [3.42.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/mobile
# [3.42.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* item linking ([#1779](https://github.com/standardnotes/app/issues/1779)) ([e3f2842](https://github.com/standardnotes/app/commit/e3f28421ff042c635ad2ae645c102c27e3e3f9c7))
## [3.41.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Bug Fixes
* **mobile:** issue with black screen on iOS ([#1777](https://github.com/standardnotes/app/issues/1777)) ([9fc77d8](https://github.com/standardnotes/app/commit/9fc77d861e501d63ee97875bba2ddda51d14fd0b))
## [3.41.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-09)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-08)
**Note:** Version bump only for package @standardnotes/mobile
## [3.41.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/mobile
# [3.41.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
### Bug Fixes
* **mobile:** disable landscape for iPhone ([a365c17](https://github.com/standardnotes/app/commit/a365c17c46f38e6d8cacade47542fd4ec625bc0d))
### Features
* **mobile:** delete account option in settings ([#1768](https://github.com/standardnotes/app/issues/1768)) ([7d21046](https://github.com/standardnotes/app/commit/7d21046b5189eb14a5957bda6fa788d743d8ebb6))
## [3.40.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/mobile
## [3.40.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/mobile
# [3.40.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features
+2 -2
View File
@@ -302,7 +302,7 @@ PODS:
- React
- react-native-version-info (1.1.1):
- React-Core
- react-native-webview (11.17.2):
- react-native-webview (11.23.1):
- React-Core
- React-perflogger (0.67.4)
- React-RCTActionSheet (0.67.4):
@@ -719,7 +719,7 @@ SPEC CHECKSUMS:
react-native-sodium-jsi: c8901320767d00385f9111bc95ba25aaa9a29890
react-native-static-server: 880d9b697ef68722e6fa06ae06e6b843e906ed0b
react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9
react-native-webview: 380c1a03ec94b7ed764dac8db1e7c9952d08c93a
react-native-webview: d33e2db8925d090871ffeb232dfa50cb3a727581
React-perflogger: 0afaf2f01a47fd0fc368a93bfbb5bd3b26db6e7f
React-RCTActionSheet: 59f35c4029e0b532fc42114241a06e170b7431a2
React-RCTAnimation: aae4f4bed122e78bdab72f7118d291d70a932ce2
@@ -138,6 +138,10 @@
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~iphone</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>supportsAlternateIcons</key>
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.40.0",
"version": "3.42.5",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
@@ -80,7 +80,7 @@
"react-native-url-polyfill": "^1.3.0",
"react-native-vector-icons": "^9.1.0",
"react-native-version-info": "^1.1.1",
"react-native-webview": "11.17.2",
"react-native-webview": "11.23.1",
"react-native-zip-archive": "^6.0.6",
"react-navigation-header-buttons": "^9.0.1",
"styled-components": "5.3.5"
+1 -1
View File
@@ -68,7 +68,7 @@ export const useFiles = ({ note }: Props) => {
const filesService = application.getFilesService()
const reloadAttachedFiles = useCallback(() => {
setAttachedFiles(application.items.getFilesForNote(note).sort(filesService.sortByName))
setAttachedFiles(application.items.getSortedFilesLinkingToItem(note).sort(filesService.sortByName))
}, [application.items, filesService.sortByName, note])
const reloadAllFiles = useCallback(() => {
@@ -204,6 +204,12 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
onError={(err) => console.error('An error has occurred', err)}
onHttpError={() => console.error('An HTTP error occurred')}
onMessage={onMessage}
onContentProcessDidTerminate={() => {
webViewRef.current?.reload()
}}
onRenderProcessGone={() => {
webViewRef.current?.reload()
}}
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
injectedJavaScriptBeforeContentLoaded={injectedJS}
@@ -0,0 +1,50 @@
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
import { SectionHeader } from '@Root/Components/SectionHeader'
import { TableSection } from '@Root/Components/TableSection'
import { ButtonType } from '@standardnotes/snjs'
import React, { useContext, useState } from 'react'
import { RegularView } from './AuthSection.styled'
export const DeleteSection = () => {
const application = useContext(ApplicationContext)
const [deleting, setDeleting] = useState(false)
const deleteAccount = async () => {
const message =
"This action is irreversible. After deletion completes, you will be signed out on all devices, and this application will exit. If you have an active paid subscription, cancel the subscription first. Otherwise, if you'd like to keep the subscription, you can re-register with the same email after deletion, and your subscription will be linked back up with your account."
const confirmed = await application!.alertService.confirm(
message,
'Are you sure?',
'Delete Account',
ButtonType.Danger,
)
if (!confirmed) {
return
}
setDeleting(true)
const result = await application!.user.deleteAccount()
if (result.error) {
void application!.alertService.alert('An error occurred while deleting your account. Please try again.')
}
}
return (
<RegularView>
<SectionHeader />
<TableSection>
<ButtonCell
first
last
important
leftAligned={true}
title={deleting ? 'Deleting...' : 'Delete Account'}
onPress={deleteAccount}
></ButtonCell>
</TableSection>
</RegularView>
)
}
@@ -153,7 +153,7 @@ export const WorkspacesSection = () => {
}
await appGroup.unloadCurrentAndCreateNewDescriptor()
}, [WorkspaceAction.AddAnother, appGroup, applicationDescriptors, getWorkspaceActionConfirmation])
}, [WorkspaceAction.AddAnother, appGroup, getWorkspaceActionConfirmation])
const signOutAllWorkspaces = useCallback(async () => {
try {
@@ -8,6 +8,7 @@ import { ApplicationEvent, FeatureIdentifier, FeatureStatus } from '@standardnot
import React, { useCallback, useEffect, useState } from 'react'
import { AuthSection } from './Sections/AuthSection'
import { CompanySection } from './Sections/CompanySection'
import { DeleteSection } from './Sections/DeleteSection'
import { EncryptionSection } from './Sections/EncryptionSection'
import { NewMobileSection } from './Sections/NewMobilePreview'
import { OptionsSection } from './Sections/OptionsSection'
@@ -68,6 +69,7 @@ export const Settings = (props: Props) => {
<ProtectionsSection title="Protections" protectionsAvailable={protectionsAvailable} />
<EncryptionSection encryptionAvailable={!!encryptionAvailable} title={'Encryption Status'} />
<CompanySection title="Standard Notes" />
{application.hasAccount() && <DeleteSection />}
</Container>
)
}
@@ -139,7 +139,7 @@ export const NoteSideMenu = React.memo((props: Props) => {
setAttachedFilesLength(0)
return
}
setAttachedFilesLength(application.items.getFilesForNote(note).length)
setAttachedFilesLength(application.items.getSortedFilesLinkingToItem(note).length)
}, [application, note])
useEffect(() => {
@@ -147,7 +147,7 @@ export const NoteSideMenu = React.memo((props: Props) => {
return
}
const removeFilesObserver = application.streamItems(ContentType.File, () => {
setAttachedFilesLength(application.items.getFilesForNote(note).length)
setAttachedFilesLength(application.items.getSortedFilesLinkingToItem(note).length)
})
return () => {
removeFilesObserver()
+28
View File
@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.27.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* item linking ([#1779](https://github.com/standardnotes/app/issues/1779)) ([e3f2842](https://github.com/standardnotes/app/commit/e3f28421ff042c635ad2ae645c102c27e3e3f9c7))
# [1.26.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
# [1.25.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspaces ([8376381](https://github.com/standardnotes/app/commit/837638198112df24c30e53803a7ddf5f841975b0))
## [1.24.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/models
## [1.24.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
# [1.24.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.24.0",
"version": "1.27.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -31,7 +31,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/utils": "workspace:*",
@@ -1,8 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { ContenteReferenceType } from './ContenteReferenceType'
import { ContentReferenceType } from './ContenteReferenceType'
export interface AnonymousReference {
uuid: string
content_type: ContentType
reference_type: ContenteReferenceType
reference_type: ContentReferenceType
}
@@ -1,5 +1,7 @@
export enum ContenteReferenceType {
export enum ContentReferenceType {
TagToParentTag = 'TagToParentTag',
FileToNote = 'FileToNote',
TagToFile = 'TagToFile',
FileToNote = 'FileToNote',
FileToFile = 'FileToFile',
NoteToNote = 'NoteToNote',
}
@@ -0,0 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContentReferenceType } from './ContenteReferenceType'
export interface FileToFileReference extends AnonymousReference {
content_type: ContentType.File
reference_type: ContentReferenceType.FileToFile
}
@@ -1,8 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContenteReferenceType } from './ContenteReferenceType'
import { ContentReferenceType } from './ContenteReferenceType'
export interface FileToNoteReference extends AnonymousReference {
content_type: ContentType.Note
reference_type: ContenteReferenceType.FileToNote
reference_type: ContentReferenceType.FileToNote
}
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ContentType } from '@standardnotes/common'
import { ItemInterface } from '../Item/Interfaces/ItemInterface'
import { ContenteReferenceType } from './ContenteReferenceType'
import { ContentReferenceType } from './ContenteReferenceType'
import { ContentReference } from './ContentReference'
import { LegacyAnonymousReference } from './LegacyAnonymousReference'
import { LegacyTagToNoteReference } from './LegacyTagToNoteReference'
@@ -26,5 +26,5 @@ export const isLegacyTagToNoteReference = (
}
export const isTagToParentTagReference = (x: ContentReference): x is TagToParentTagReference => {
return isReference(x) && x.reference_type === ContenteReferenceType.TagToParentTag
return isReference(x) && x.reference_type === ContentReferenceType.TagToParentTag
}
@@ -0,0 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContentReferenceType } from './ContenteReferenceType'
export interface NoteToNoteReference extends AnonymousReference {
content_type: ContentType.Note
reference_type: ContentReferenceType.NoteToNote
}
@@ -1,8 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContenteReferenceType } from './ContenteReferenceType'
import { ContentReferenceType } from './ContenteReferenceType'
export interface TagToFileReference extends AnonymousReference {
content_type: ContentType.File
reference_type: ContenteReferenceType.TagToFile
reference_type: ContentReferenceType.TagToFile
}
@@ -1,8 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContenteReferenceType } from './ContenteReferenceType'
import { ContentReferenceType } from './ContenteReferenceType'
export interface TagToParentTagReference extends AnonymousReference {
content_type: ContentType.Tag
reference_type: ContenteReferenceType.TagToParentTag
reference_type: ContentReferenceType.TagToParentTag
}
@@ -0,0 +1,10 @@
import { WorkspaceType } from '@standardnotes/common'
export type Workspace = {
uuid: string
type: WorkspaceType
name: string | null
keyRotationIndex: number
createdAt: number
updatedAt: number
}
@@ -0,0 +1,16 @@
import { Uuid, WorkspaceAccessLevel, WorkspaceUserStatus } from '@standardnotes/common'
export type WorkspaceUser = {
uuid: Uuid
accessLevel: WorkspaceAccessLevel
userUuid: Uuid
userDisplayName: string | null
workspaceUuid: Uuid
encryptedWorkspaceKey: string | null
publicKey: string | null
encryptedPrivateKey: string | null
status: WorkspaceUserStatus
keyRotationIndex: number
createdAt: number
updatedAt: number
}
@@ -1,10 +1,10 @@
import { NoteContent } from './../../../Syncable/Note/NoteContent'
import { NoteContent } from '../../../Syncable/Note/NoteContent'
import { ContentType } from '@standardnotes/common'
import { DecryptedItem, EncryptedItem } from '../../../Abstract/Item'
import { DecryptedPayload, EncryptedPayload, PayloadTimestampDefaults } from '../../../Abstract/Payload'
import { ItemCollection } from './ItemCollection'
import { FillItemContent } from '../../../Abstract/Content/ItemContent'
import { TagNotesIndex } from './TagNotesIndex'
import { TagItemsIndex } from './TagItemsIndex'
import { ItemDelta } from '../../Index/ItemDelta'
import { AnyItemInterface } from '../../../Abstract/Item/Interfaces/UnionTypes'
@@ -24,10 +24,10 @@ describe('tag notes index', () => {
return new EncryptedItem(payload)
}
const createDecryptedItem = (uuid?: string) => {
const createDecryptedItem = (uuid?: string, content_type = ContentType.Note) => {
const payload = new DecryptedPayload({
uuid: uuid || String(Math.random()),
content_type: ContentType.Note,
content_type,
content: FillItemContent<NoteContent>({
title: 'foo',
}),
@@ -46,20 +46,33 @@ describe('tag notes index', () => {
}
}
it('should count both notes and files', () => {
const collection = new ItemCollection()
const index = new TagItemsIndex(collection)
const decryptedNote = createDecryptedItem('note')
const decryptedFile = createDecryptedItem('file')
collection.set([decryptedNote, decryptedFile])
index.onChange(createChangeDelta(decryptedNote))
index.onChange(createChangeDelta(decryptedFile))
expect(index.allCountableItemsCount()).toEqual(2)
})
it('should decrement count after decrypted note becomes errored', () => {
const collection = new ItemCollection()
const index = new TagNotesIndex(collection)
const index = new TagItemsIndex(collection)
const decryptedItem = createDecryptedItem()
collection.set(decryptedItem)
index.onChange(createChangeDelta(decryptedItem))
expect(index.allCountableNotesCount()).toEqual(1)
expect(index.allCountableItemsCount()).toEqual(1)
const encryptedItem = createEncryptedItem(decryptedItem.uuid)
collection.set(encryptedItem)
index.onChange(createChangeDelta(encryptedItem))
expect(index.allCountableNotesCount()).toEqual(0)
expect(index.allCountableItemsCount()).toEqual(0)
})
})
@@ -7,22 +7,22 @@ import { ItemDelta } from '../../Index/ItemDelta'
import { isDecryptedItem, ItemInterface } from '../../../Abstract/Item'
type AllNotesUuidSignifier = undefined
export type TagNoteCountChangeObserver = (tagUuid: Uuid | AllNotesUuidSignifier) => void
export type TagItemCountChangeObserver = (tagUuid: Uuid | AllNotesUuidSignifier) => void
export class TagNotesIndex implements SNIndex {
private tagToNotesMap: Partial<Record<Uuid, Set<Uuid>>> = {}
private allCountableNotes = new Set<Uuid>()
export class TagItemsIndex implements SNIndex {
private tagToItemsMap: Partial<Record<Uuid, Set<Uuid>>> = {}
private allCountableItems = new Set<Uuid>()
constructor(private collection: ItemCollection, public observers: TagNoteCountChangeObserver[] = []) {}
constructor(private collection: ItemCollection, public observers: TagItemCountChangeObserver[] = []) {}
private isNoteCountable = (note: ItemInterface) => {
if (isDecryptedItem(note)) {
return !note.archived && !note.trashed
private isItemCountable = (item: ItemInterface) => {
if (isDecryptedItem(item)) {
return !item.archived && !item.trashed
}
return false
}
public addCountChangeObserver(observer: TagNoteCountChangeObserver): () => void {
public addCountChangeObserver(observer: TagItemCountChangeObserver): () => void {
this.observers.push(observer)
const thislessEventObservers = this.observers
@@ -37,30 +37,32 @@ export class TagNotesIndex implements SNIndex {
}
}
public allCountableNotesCount(): number {
return this.allCountableNotes.size
public allCountableItemsCount(): number {
return this.allCountableItems.size
}
public countableNotesForTag(tag: SNTag): number {
return this.tagToNotesMap[tag.uuid]?.size || 0
public countableItemsForTag(tag: SNTag): number {
return this.tagToItemsMap[tag.uuid]?.size || 0
}
public onChange(delta: ItemDelta): void {
const notes = [...delta.changed, ...delta.inserted, ...delta.discarded].filter(
(i) => i.content_type === ContentType.Note,
const items = [...delta.changed, ...delta.inserted, ...delta.discarded].filter(
(i) => i.content_type === ContentType.Note || i.content_type === ContentType.File,
)
const tags = [...delta.changed, ...delta.inserted].filter(isDecryptedItem).filter(isTag)
this.receiveNoteChanges(notes)
this.receiveItemChanges(items)
this.receiveTagChanges(tags)
}
private receiveTagChanges(tags: SNTag[]): void {
for (const tag of tags) {
const uuids = tag.noteReferences.map((ref) => ref.uuid)
const countableUuids = uuids.filter((uuid) => this.allCountableNotes.has(uuid))
const previousSet = this.tagToNotesMap[tag.uuid]
this.tagToNotesMap[tag.uuid] = new Set(countableUuids)
const uuids = tag.references
.filter((ref) => ref.content_type === ContentType.Note || ref.content_type === ContentType.File)
.map((ref) => ref.uuid)
const countableUuids = uuids.filter((uuid) => this.allCountableItems.has(uuid))
const previousSet = this.tagToItemsMap[tag.uuid]
this.tagToItemsMap[tag.uuid] = new Set(countableUuids)
if (previousSet?.size !== countableUuids.length) {
this.notifyObservers(tag.uuid)
@@ -68,26 +70,26 @@ export class TagNotesIndex implements SNIndex {
}
}
private receiveNoteChanges(notes: ItemInterface[]): void {
const previousAllCount = this.allCountableNotes.size
private receiveItemChanges(items: ItemInterface[]): void {
const previousAllCount = this.allCountableItems.size
for (const note of notes) {
const isCountable = this.isNoteCountable(note)
for (const item of items) {
const isCountable = this.isItemCountable(item)
if (isCountable) {
this.allCountableNotes.add(note.uuid)
this.allCountableItems.add(item.uuid)
} else {
this.allCountableNotes.delete(note.uuid)
this.allCountableItems.delete(item.uuid)
}
const associatedTagUuids = this.collection.uuidsThatReferenceUuid(note.uuid)
const associatedTagUuids = this.collection.uuidsThatReferenceUuid(item.uuid)
for (const tagUuid of associatedTagUuids) {
const set = this.setForTag(tagUuid)
const previousCount = set.size
if (isCountable) {
set.add(note.uuid)
set.add(item.uuid)
} else {
set.delete(note.uuid)
set.delete(item.uuid)
}
if (previousCount !== set.size) {
this.notifyObservers(tagUuid)
@@ -95,16 +97,16 @@ export class TagNotesIndex implements SNIndex {
}
}
if (previousAllCount !== this.allCountableNotes.size) {
if (previousAllCount !== this.allCountableItems.size) {
this.notifyObservers(undefined)
}
}
private setForTag(uuid: Uuid): Set<Uuid> {
let set = this.tagToNotesMap[uuid]
let set = this.tagToItemsMap[uuid]
if (!set) {
set = new Set()
this.tagToNotesMap[uuid] = set
this.tagToItemsMap[uuid] = set
}
return set
}
@@ -1,9 +1,10 @@
import { ContentType } from '@standardnotes/common'
import { SNNote } from '../Note/Note'
import { FileContent } from './File'
import { FileContent, FileItem } from './File'
import { FileToNoteReference } from '../../Abstract/Reference/FileToNoteReference'
import { ContenteReferenceType } from '../../Abstract/Reference/ContenteReferenceType'
import { ContentReferenceType } from '../../Abstract/Reference/ContenteReferenceType'
import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemMutator'
import { FileToFileReference } from '../../Abstract/Reference/FileToFileReference'
export class FileMutator extends DecryptedItemMutator<FileContent> {
set name(newName: string) {
@@ -16,7 +17,7 @@ export class FileMutator extends DecryptedItemMutator<FileContent> {
public addNote(note: SNNote): void {
const reference: FileToNoteReference = {
reference_type: ContenteReferenceType.FileToNote,
reference_type: ContentReferenceType.FileToNote,
content_type: ContentType.Note,
uuid: note.uuid,
}
@@ -30,4 +31,22 @@ export class FileMutator extends DecryptedItemMutator<FileContent> {
const references = this.immutableItem.references.filter((ref) => ref.uuid !== note.uuid)
this.mutableContent.references = references
}
public addFile(file: FileItem): void {
if (this.immutableItem.isReferencingItem(file)) {
return
}
const reference: FileToFileReference = {
uuid: file.uuid,
content_type: ContentType.File,
reference_type: ContentReferenceType.FileToFile,
}
this.mutableContent.references.push(reference)
}
public removeFile(file: FileItem): void {
this.mutableContent.references = this.mutableContent.references.filter((r) => r.uuid !== file.uuid)
}
}
@@ -1,6 +1,10 @@
import { AppDataField } from '../../Abstract/Item/Types/AppDataField'
import { NoteContent } from './NoteContent'
import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemMutator'
import { SNNote } from './Note'
import { NoteToNoteReference } from '../../Abstract/Reference/NoteToNoteReference'
import { ContentType } from '@standardnotes/common'
import { ContentReferenceType } from '../../Abstract/Item'
export class NoteMutator extends DecryptedItemMutator<NoteContent> {
set title(title: string) {
@@ -38,4 +42,22 @@ export class NoteMutator extends DecryptedItemMutator<NoteContent> {
this.mutableContent.spellcheck = !this.mutableContent.spellcheck
}
}
public addNote(note: SNNote): void {
if (this.immutableItem.isReferencingItem(note)) {
return
}
const reference: NoteToNoteReference = {
uuid: note.uuid,
content_type: ContentType.Note,
reference_type: ContentReferenceType.NoteToNote,
}
this.mutableContent.references.push(reference)
}
public removeNote(note: SNNote): void {
this.mutableContent.references = this.mutableContent.references.filter((r) => r.uuid !== note.uuid)
}
}
@@ -1,5 +1,5 @@
import { ContentType } from '@standardnotes/common'
import { ContenteReferenceType, MutationType } from '../../Abstract/Item'
import { ContentReferenceType, MutationType } from '../../Abstract/Item'
import { createFile, createTag } from '../../Utilities/Test/SpecUtils'
import { SNTag } from './Tag'
import { TagMutator } from './TagMutator'
@@ -16,7 +16,7 @@ describe('tag mutator', () => {
expect(result.content.references[0]).toEqual({
uuid: file.uuid,
content_type: ContentType.File,
reference_type: ContenteReferenceType.TagToFile,
reference_type: ContentReferenceType.TagToFile,
})
})
@@ -4,7 +4,7 @@ import { FileItem } from '../File'
import { SNNote } from '../Note'
import { isTagToParentTagReference } from '../../Abstract/Reference/Functions'
import { TagToParentTagReference } from '../../Abstract/Reference/TagToParentTagReference'
import { ContenteReferenceType } from '../../Abstract/Reference/ContenteReferenceType'
import { ContentReferenceType } from '../../Abstract/Reference/ContenteReferenceType'
import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemMutator'
import { TagToFileReference } from '../../Abstract/Reference/TagToFileReference'
@@ -21,7 +21,7 @@ export class TagMutator extends DecryptedItemMutator<TagContent> {
const references = this.immutableItem.references.filter((ref) => !isTagToParentTagReference(ref))
const reference: TagToParentTagReference = {
reference_type: ContenteReferenceType.TagToParentTag,
reference_type: ContentReferenceType.TagToParentTag,
content_type: ContentType.Tag,
uuid: tag.uuid,
}
@@ -41,7 +41,7 @@ export class TagMutator extends DecryptedItemMutator<TagContent> {
}
const reference: TagToFileReference = {
reference_type: ContenteReferenceType.TagToFile,
reference_type: ContentReferenceType.TagToFile,
content_type: ContentType.File,
uuid: file.uuid,
}
+3 -1
View File
@@ -28,6 +28,8 @@ export * from './Api/Subscription/Invitation'
export * from './Api/Subscription/InvitationStatus'
export * from './Api/Subscription/InviteeIdentifierType'
export * from './Api/Subscription/InviterIdentifierType'
export * from './Api/Workspace/Workspace'
export * from './Api/Workspace/WorkspaceUser'
export * from './Device/Environment'
export * from './Device/Platform'
export * from './Local/KeyParams/RootKeyParamsInterface'
@@ -36,7 +38,7 @@ export * from './Local/RootKey/RootKeyContent'
export * from './Local/RootKey/RootKeyInterface'
export * from './Runtime/Collection/CollectionSort'
export * from './Runtime/Collection/Item/ItemCollection'
export * from './Runtime/Collection/Item/TagNotesIndex'
export * from './Runtime/Collection/Item/TagItemsIndex'
export * from './Runtime/Collection/Payload/ImmutablePayloadCollection'
export * from './Runtime/Collection/Payload/PayloadCollection'
export * from './Runtime/Deltas'
+76
View File
@@ -3,6 +3,82 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.140](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.139](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.138](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.135](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.134](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.133](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.132](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.131](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.130](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.129](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.128](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.127](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-09)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.126](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-08)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.125](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.124](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.123](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.122](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.121](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.121",
"version": "1.3.140",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.11.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [1.10.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/responses
## [1.10.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
## [1.10.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/responses
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/responses",
"version": "1.10.4",
"version": "1.11.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -31,7 +31,7 @@
"ts-jest": "^28.0.5"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/security": "^1.1.0",
"reflect-metadata": "^0.1.13"
+62
View File
@@ -3,6 +3,68 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.32.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/services
## [1.32.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/services
# [1.32.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
### Features
* **api:** add keyshare initiation for workspaces ([fabce1f](https://github.com/standardnotes/app/commit/fabce1f7aca5c9caaa5bb3908b2dc68063c690d0))
# [1.31.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* item linking ([#1779](https://github.com/standardnotes/app/issues/1779)) ([e3f2842](https://github.com/standardnotes/app/commit/e3f28421ff042c635ad2ae645c102c27e3e3f9c7))
# [1.30.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
# [1.29.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add access level to invitation requests ([49b3d27](https://github.com/standardnotes/app/commit/49b3d2714fbe4ac9f9242097b8df6b4e3d604513))
# [1.28.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add accepting invites to workspace ([15e2c82](https://github.com/standardnotes/app/commit/15e2c82e654ce3f983cd42b01f14d18435b3e939))
* **api:** add listing workspaces ([8376381](https://github.com/standardnotes/app/commit/837638198112df24c30e53803a7ddf5f841975b0))
## [1.27.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* dark mode not working in editors ([#1773](https://github.com/standardnotes/app/issues/1773)) ([27d2c95](https://github.com/standardnotes/app/commit/27d2c95b5b82645bf6c0372979f05236c83a10f6))
# [1.27.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
* linter issues ([e2e7605](https://github.com/standardnotes/app/commit/e2e76054142e8d67cac69280e2a3efcb15cf67f1))
### Features
* **api:** add inviting to workspace ([158ca6a](https://github.com/standardnotes/app/commit/158ca6ac6a428e082c8f984791f80fcaadcb3e34))
# [1.26.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
### Features
* **api:** add workspaces api ([#1765](https://github.com/standardnotes/app/issues/1765)) ([01ba715](https://github.com/standardnotes/app/commit/01ba715eba987a7da1ee062fec0b3593a7a453ed))
# [1.25.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features
+1 -1
View File
@@ -12,7 +12,7 @@ module.exports = {
global: {
branches: 9,
functions: 10,
lines: 17,
lines: 16,
statements: 16
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.25.0",
"version": "1.32.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -26,7 +26,7 @@
"dependencies": {
"@standardnotes/api": "workspace:^",
"@standardnotes/auth": "^3.19.4",
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.39.0",
"@standardnotes/encryption": "workspace:^",
"@standardnotes/files": "workspace:^",
"@standardnotes/models": "workspace:^",
@@ -1,13 +1,15 @@
import { ApplicationIdentifier, ContentType } from '@standardnotes/common'
import { BackupFile, DecryptedItemInterface, ItemStream, Platform, PrefKey, PrefValue } from '@standardnotes/models'
import { FilesClientInterface } from '@standardnotes/files'
import { AlertService } from '../Alert/AlertService'
import { AlertService } from '../Alert/AlertService'
import { ComponentManagerInterface } from '../Component/ComponentManagerInterface'
import { ApplicationEvent } from '../Event/ApplicationEvent'
import { ApplicationEventCallback } from '../Event/ApplicationEventCallback'
import { FeaturesClientInterface } from '../Feature/FeaturesClientInterface'
import { SubscriptionClientInterface } from '../Subscription/SubscriptionClientInterface'
import { DeviceInterface } from '../Device/DeviceInterface'
import { WorkspaceClientInterface } from '../Workspace/WorkspaceClientInterface'
import { ItemsClientInterface } from '../Item/ItemsClientInterface'
import { MutatorClientInterface } from '../Mutator/MutatorClientInterface'
import { StorageValueModes } from '../Storage/StorageTypes'
@@ -15,7 +17,6 @@ import { StorageValueModes } from '../Storage/StorageTypes'
import { DeinitMode } from './DeinitMode'
import { DeinitSource } from './DeinitSource'
import { UserClientInterface } from './UserClientInterface'
import { DeviceInterface } from '../Device/DeviceInterface'
export interface ApplicationInterface {
deinit(mode: DeinitMode, source: DeinitSource): void
@@ -49,6 +50,7 @@ export interface ApplicationInterface {
get user(): UserClientInterface
get files(): FilesClientInterface
get subscriptions(): SubscriptionClientInterface
get workspaces(): WorkspaceClientInterface
readonly identifier: ApplicationIdentifier
readonly platform: Platform
deviceInterface: DeviceInterface
@@ -77,7 +77,7 @@ describe('fileService', () => {
crypto.xchacha20StreamEncryptorPush = jest.fn().mockReturnValue(new Uint8Array())
})
it.only('should cache file after download', async () => {
it('should cache file after download', async () => {
const file = {
uuid: '1',
decryptedSize: 100_000,
@@ -4,7 +4,7 @@ import {
FileItem,
SNTag,
SmartView,
TagNoteCountChangeObserver,
TagItemCountChangeObserver,
DecryptedPayloadInterface,
EncryptedItemInterface,
DecryptedTransferPayload,
@@ -14,6 +14,7 @@ import {
SNTheme,
DisplayOptions,
ItemsKeyInterface,
ItemContent,
} from '@standardnotes/models'
export interface ItemsClientInterface {
@@ -23,12 +24,12 @@ export interface ItemsClientInterface {
disassociateFileWithNote(file: FileItem, note: SNNote): Promise<FileItem>
getFilesForNote(note: SNNote): FileItem[]
renameFile(file: FileItem, name: string): Promise<FileItem>
addTagToNote(note: SNNote, tag: SNTag, addHierarchy: boolean): Promise<SNTag[]>
addTagToFile(file: FileItem, tag: SNTag, addHierarchy: boolean): Promise<SNTag[]>
/** Creates an unmanaged, un-inserted item from a payload. */
createItemFromPayload(payload: DecryptedPayloadInterface): DecryptedItemInterface
@@ -54,7 +55,7 @@ export interface ItemsClientInterface {
notesMatchingSmartView(view: SmartView): SNNote[]
addNoteCountChangeObserver(observer: TagNoteCountChangeObserver): () => void
addNoteCountChangeObserver(observer: TagItemCountChangeObserver): () => void
allCountableNotesCount(): number
@@ -72,6 +73,14 @@ export interface ItemsClientInterface {
itemsReferencingItem(itemToLookupUuidFor: DecryptedItemInterface, contentType?: ContentType): DecryptedItemInterface[]
linkNoteToNote(note: SNNote, otherNote: SNNote): Promise<SNNote>
linkFileToFile(file: FileItem, otherFile: FileItem): Promise<FileItem>
unlinkItem(
item: DecryptedItemInterface<ItemContent>,
itemToUnlink: DecryptedItemInterface<ItemContent>,
): Promise<DecryptedItemInterface<ItemContent>>
/**
* Finds tags with title or component starting with a search query and (optionally) not associated with a note
* @param searchQuery - The query string to match
@@ -101,10 +110,16 @@ export interface ItemsClientInterface {
/**
* Get tags for a note sorted in natural order
* @param note - The note whose tags will be returned
* @returns Array containing tags associated with a note
* @param item - The item whose tags will be returned
* @returns Array containing tags associated with an item
*/
getSortedTagsForNote(note: SNNote): SNTag[]
getSortedTagsForItem(item: DecryptedItemInterface<ItemContent>): SNTag[]
getSortedLinkedFilesForItem(item: DecryptedItemInterface<ItemContent>): FileItem[]
getSortedFilesLinkingToItem(item: DecryptedItemInterface<ItemContent>): FileItem[]
getSortedLinkedNotesForItem(item: DecryptedItemInterface<ItemContent>): SNNote[]
getSortedNotesLinkingToItem(item: DecryptedItemInterface<ItemContent>): SNNote[]
isSmartViewTitle(title: string): boolean
@@ -137,4 +152,12 @@ export interface ItemsClientInterface {
* @returns Whether the item is a template (unmanaged)
*/
isTemplateItem(item: DecryptedItemInterface): boolean
/**
* @returns `'direct'` if `itemOne` has the reference to `itemTwo`, `'indirect'` if `itemTwo` has the reference to `itemOne`, `'unlinked'` if neither reference each other
*/
relationshipTypeForItems(
itemOne: DecryptedItemInterface,
itemTwo: DecryptedItemInterface,
): 'direct' | 'indirect' | 'unlinked'
}
@@ -0,0 +1,30 @@
import { Uuid, WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { Workspace, WorkspaceUser } from '@standardnotes/models'
export interface WorkspaceClientInterface {
createWorkspace(dto: {
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<{ uuid: string } | null>
inviteToWorkspace(dto: {
inviteeEmail: string
workspaceUuid: Uuid
accessLevel: WorkspaceAccessLevel
}): Promise<{ uuid: string } | null>
acceptInvite(dto: {
inviteUuid: Uuid
userUuid: Uuid
publicKey: string
encryptedPrivateKey: string
}): Promise<{ success: boolean }>
listWorkspaces(): Promise<{ ownedWorkspaces: Array<Workspace>; joinedWorkspaces: Array<Workspace> }>
listWorkspaceUsers(dto: { workspaceUuid: Uuid }): Promise<{ users: Array<WorkspaceUser> }>
initiateKeyshare(dto: {
workspaceUuid: Uuid
userUuid: Uuid
encryptedWorkspaceKey: string
}): Promise<{ success: boolean }>
}
@@ -0,0 +1,119 @@
import { WorkspaceApiServiceInterface } from '@standardnotes/api'
import { Uuid, WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common'
import { Workspace, WorkspaceUser } from '@standardnotes/models'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { AbstractService } from '../Service/AbstractService'
import { WorkspaceClientInterface } from './WorkspaceClientInterface'
export class WorkspaceManager extends AbstractService implements WorkspaceClientInterface {
constructor(
private workspaceApiService: WorkspaceApiServiceInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
}
async initiateKeyshare(dto: {
workspaceUuid: string
userUuid: string
encryptedWorkspaceKey: string
}): Promise<{ success: boolean }> {
try {
const result = await this.workspaceApiService.initiateKeyshare(dto)
if (result.data.error !== undefined) {
return { success: false }
}
return result.data
} catch (error) {
return { success: false }
}
}
async listWorkspaceUsers(dto: { workspaceUuid: string }): Promise<{ users: WorkspaceUser[] }> {
try {
const result = await this.workspaceApiService.listWorkspaceUsers(dto)
if (result.data.error !== undefined) {
return { users: [] }
}
return result.data
} catch (error) {
return { users: [] }
}
}
async listWorkspaces(): Promise<{ ownedWorkspaces: Workspace[]; joinedWorkspaces: Workspace[] }> {
try {
const result = await this.workspaceApiService.listWorkspaces()
if (result.data.error !== undefined) {
return { ownedWorkspaces: [], joinedWorkspaces: [] }
}
return result.data
} catch (error) {
return { ownedWorkspaces: [], joinedWorkspaces: [] }
}
}
async acceptInvite(dto: {
inviteUuid: string
userUuid: string
publicKey: string
encryptedPrivateKey: string
}): Promise<{ success: boolean }> {
try {
const result = await this.workspaceApiService.acceptInvite(dto)
if (result.data.error !== undefined) {
return { success: false }
}
return result.data
} catch (error) {
return { success: false }
}
}
async inviteToWorkspace(dto: {
inviteeEmail: string
workspaceUuid: Uuid
accessLevel: WorkspaceAccessLevel
}): Promise<{ uuid: string } | null> {
try {
const result = await this.workspaceApiService.inviteToWorkspace(dto)
if (result.data.error !== undefined) {
return null
}
return result.data
} catch (error) {
return null
}
}
async createWorkspace(dto: {
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<{ uuid: string } | null> {
try {
const result = await this.workspaceApiService.createWorkspace(dto)
if (result.data.error !== undefined) {
return null
}
return result.data
} catch (error) {
return null
}
}
}
+2
View File
@@ -73,3 +73,5 @@ export * from './Sync/SyncOptions'
export * from './Sync/SyncQueueStrategy'
export * from './Sync/SyncServiceInterface'
export * from './Sync/SyncSource'
export * from './Workspace/WorkspaceClientInterface'
export * from './Workspace/WorkspaceManager'
+52
View File
@@ -3,6 +3,58 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.139.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
### Features
* replace private workspaces with private usernames ([#1783](https://github.com/standardnotes/app/issues/1783)) ([18c821d](https://github.com/standardnotes/app/commit/18c821d8eb51beb6f54211eb1d6eb454303044f5))
## [2.138.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/snjs
## [2.138.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-12)
**Note:** Version bump only for package @standardnotes/snjs
# [2.138.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* item linking ([#1779](https://github.com/standardnotes/app/issues/1779)) ([e3f2842](https://github.com/standardnotes/app/commit/e3f28421ff042c635ad2ae645c102c27e3e3f9c7))
# [2.137.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
### Features
* **api:** add listing workspace users ([fb41f65](https://github.com/standardnotes/app/commit/fb41f651eca45dd62314609c2f389d5dc683c36e))
## [2.136.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/snjs
## [2.136.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/snjs
## [2.136.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* dark mode not working in editors ([#1773](https://github.com/standardnotes/app/issues/1773)) ([27d2c95](https://github.com/standardnotes/app/commit/27d2c95b5b82645bf6c0372979f05236c83a10f6))
## [2.136.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
### Bug Fixes
* **api:** workspace creation arguments ([a275a45](https://github.com/standardnotes/app/commit/a275a45753abc4a29a89de5fe784260165297bbe))
# [2.136.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
### Features
* **api:** add workspaces api ([#1765](https://github.com/standardnotes/app/issues/1765)) ([01ba715](https://github.com/standardnotes/app/commit/01ba715eba987a7da1ee062fec0b3593a7a453ed))
# [2.135.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-06)
### Features

Some files were not shown because too many files have changed in this diff Show More