Compare commits

...
Author SHA1 Message Date
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
88 changed files with 927 additions and 264 deletions
+23
View File
@@ -3,6 +3,29 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [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
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.11.0",
"version": "1.13.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -36,7 +36,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
@@ -1,3 +1,6 @@
export enum WorkspaceApiOperations {
Creating,
Inviting,
Accepting,
ListingWorkspaces,
}
@@ -1,4 +1,9 @@
import { 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 { WorkspaceServerInterface } from '../../Server/Workspace/WorkspaceServerInterface'
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
@@ -14,10 +19,21 @@ describe('WorkspaceApiService', () => {
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>)
})
it('should create a workspace', async () => {
const response = await createService().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
@@ -32,6 +48,7 @@ describe('WorkspaceApiService', () => {
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
workspaceType: 'private',
})
})
@@ -44,6 +61,7 @@ describe('WorkspaceApiService', () => {
let error = null
try {
await service.createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
@@ -63,6 +81,7 @@ describe('WorkspaceApiService', () => {
let error = null
try {
await createService().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
@@ -73,4 +92,164 @@ describe('WorkspaceApiService', () => {
expect(error).not.toBeNull()
})
it('should invite to a workspace', async () => {
const response = await createService().inviteToWorkspace({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
})
expect(response).toEqual({
data: {
uuid: 'i-1-2-3',
},
})
expect(workspaceServer.inviteToWorkspace).toHaveBeenCalledWith({
workspaceUuid: 'w-1-2-3',
inviteeEmail: '[email protected]',
})
})
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]',
})
} 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]',
})
} 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()
})
})
@@ -1,7 +1,12 @@
import { Uuid, 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 { WorkspaceApiServiceInterface } from './WorkspaceApiServiceInterface'
import { WorkspaceApiOperations } from './WorkspaceApiOperations'
@@ -13,31 +18,96 @@ export class WorkspaceApiService implements WorkspaceApiServiceInterface {
this.operationsInProgress = new Map()
}
async createWorkspace(dto: {
encryptedWorkspaceKey: string
encryptedPrivateKey: string
publicKey: string
workspaceName?: string
}): Promise<WorkspaceCreationResponse> {
if (this.operationsInProgress.get(WorkspaceApiOperations.Creating)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(WorkspaceApiOperations.Creating, true)
async listWorkspaces(): Promise<WorkspaceListResponse> {
this.lockOperation(WorkspaceApiOperations.ListingWorkspaces)
try {
const response = await this.workspaceServer.createWorkspace({
encryptedPrivateKey: dto.encryptedPrivateKey,
encryptedWorkspaceKey: dto.encryptedWorkspaceKey,
publicKey: dto.publicKey,
workspaceName: dto.workspaceName,
})
const response = await this.workspaceServer.listWorkspaces({})
this.operationsInProgress.set(WorkspaceApiOperations.Creating, false)
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 }): Promise<WorkspaceInvitationResponse> {
this.lockOperation(WorkspaceApiOperations.Inviting)
try {
const response = await this.workspaceServer.inviteToWorkspace({
inviteeEmail: dto.inviteeEmail,
workspaceUuid: dto.workspaceUuid,
})
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)
}
}
@@ -1,10 +1,24 @@
import { WorkspaceCreationResponse } from '../../Response'
import { Uuid, WorkspaceType } from '@standardnotes/common'
import { WorkspaceCreationResponse } from '../../Response/Workspace/WorkspaceCreationResponse'
import { WorkspaceInvitationAcceptingResponse } from '../../Response/Workspace/WorkspaceInvitationAcceptingResponse'
import { WorkspaceInvitationResponse } from '../../Response/Workspace/WorkspaceInvitationResponse'
import { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
export interface WorkspaceApiServiceInterface {
createWorkspace(dto: {
encryptedWorkspaceKey: string
encryptedPrivateKey: string
publicKey: string
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<WorkspaceCreationResponse>
inviteToWorkspace(dto: { inviteeEmail: string; workspaceUuid: Uuid }): Promise<WorkspaceInvitationResponse>
acceptInvite(dto: {
inviteUuid: Uuid
userUuid: Uuid
publicKey: string
encryptedPrivateKey: string
}): Promise<WorkspaceInvitationAcceptingResponse>
listWorkspaces(): Promise<WorkspaceListResponse>
}
@@ -1,7 +1,10 @@
import { WorkspaceType } from '@standardnotes/common'
export type WorkspaceCreationRequestParams = {
encryptedWorkspaceKey: string
encryptedPrivateKey: string
publicKey: string
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,7 @@
import { Uuid } from '@standardnotes/common'
export type WorkspaceInvitationRequestParams = {
workspaceUuid: Uuid
inviteeEmail: string
[additionalParam: string]: unknown
}
@@ -0,0 +1,3 @@
export type WorkspaceListRequestParams = {
[additionalParam: string]: unknown
}
+3
View File
@@ -7,3 +7,6 @@ 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/WorkspaceListRequestParams'
@@ -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 { 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>
}
@@ -14,3 +14,9 @@ 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/WorkspaceInvitationResponse'
export * from './Workspace/WorkspaceInvitationResponseBody'
export * from './Workspace/WorkspaceListResponse'
export * from './Workspace/WorkspaceListResponseBody'
@@ -1,5 +1,10 @@
import { Uuid } from '@standardnotes/common'
const WorkspacePaths = {
createWorkspace: '/v1/workspaces',
listWorkspaces: '/v1/workspaces',
inviteToWorkspace: (uuid: Uuid) => `/v1/workspaces/${uuid}/invites`,
acceptInvite: (uuid: Uuid) => `/v1/invites/${uuid}/accept`,
}
export const Paths = {
@@ -1,5 +1,9 @@
import { HttpServiceInterface } from '../../Http'
import { 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 { WorkspaceListResponse } from '../../Response/Workspace/WorkspaceListResponse'
import { WorkspaceServer } from './WorkspaceServer'
@@ -17,6 +21,7 @@ describe('WorkspaceServer', () => {
it('should create a workspace', async () => {
const response = await createServer().createWorkspace({
workspaceType: WorkspaceType.Private,
encryptedPrivateKey: 'foo',
encryptedWorkspaceKey: 'bar',
publicKey: 'buzz',
@@ -28,4 +33,54 @@ describe('WorkspaceServer', () => {
},
})
})
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',
})
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: [] },
})
})
})
@@ -1,6 +1,12 @@
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 { Paths } from './Paths'
import { WorkspaceServerInterface } from './WorkspaceServerInterface'
@@ -8,6 +14,24 @@ import { WorkspaceServerInterface } from './WorkspaceServerInterface'
export class WorkspaceServer implements WorkspaceServerInterface {
constructor(private httpService: HttpServiceInterface) {}
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)
@@ -1,6 +1,15 @@
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'
export interface WorkspaceServerInterface {
createWorkspace(params: WorkspaceCreationRequestParams): Promise<WorkspaceCreationResponse>
listWorkspaces(params: WorkspaceListRequestParams): Promise<WorkspaceListResponse>
inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise<WorkspaceInvitationResponse>
acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise<WorkspaceInvitationAcceptingResponse>
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.18",
"private": true,
"author": "Standard Notes.",
"main": "dist",
+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.
## [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
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.200",
"version": "3.23.203",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.16.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -35,7 +35,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/sncrypto-common": "workspace:*",
+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.
## [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.52.4",
"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.36.1",
"@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]
}
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.23.15",
"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.36.1",
"@standardnotes/files": "workspace:*",
"@standardnotes/utils": "workspace:*",
"@types/wicg-file-system-access": "^2020.9.5",
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.10.15",
"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.36.1",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
+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.
## [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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.41.3",
"version": "3.41.6",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+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.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.25.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -31,7 +31,7 @@
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"@standardnotes/features": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/utils": "workspace:*",
@@ -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
}
+1
View File
@@ -28,6 +28,7 @@ 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 './Device/Environment'
export * from './Device/Platform'
export * from './Local/KeyParams/RootKeyParamsInterface'
+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.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.127",
"version": "1.3.130",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.10.6",
"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.36.1",
"@standardnotes/features": "workspace:*",
"@standardnotes/security": "^1.1.0",
"reflect-metadata": "^0.1.13"
+24
View File
@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [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
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.26.0",
"version": "1.28.0",
"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.36.1",
"@standardnotes/encryption": "workspace:^",
"@standardnotes/files": "workspace:^",
"@standardnotes/models": "workspace:^",
@@ -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,
@@ -1,8 +1,20 @@
import { Uuid, WorkspaceType } from '@standardnotes/common'
import { Workspace } from '@standardnotes/models'
export interface WorkspaceClientInterface {
createWorkspace(dto: {
encryptedWorkspaceKey: string
encryptedPrivateKey: string
publicKey: string
workspaceType: WorkspaceType
encryptedWorkspaceKey?: string
encryptedPrivateKey?: string
publicKey?: string
workspaceName?: string
}): Promise<{ uuid: string } | null>
inviteToWorkspace(dto: { inviteeEmail: string; workspaceUuid: Uuid }): 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> }>
}
@@ -1,4 +1,7 @@
import { WorkspaceApiServiceInterface } from '@standardnotes/api'
import { Uuid, WorkspaceType } from '@standardnotes/common'
import { Workspace } from '@standardnotes/models'
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
import { AbstractService } from '../Service/AbstractService'
import { WorkspaceClientInterface } from './WorkspaceClientInterface'
@@ -11,10 +14,58 @@ export class WorkspaceManager extends AbstractService implements WorkspaceClient
super(internalEventBus)
}
async createWorkspace(dto: {
encryptedWorkspaceKey: string
encryptedPrivateKey: string
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 }): 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 {
+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.
## [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
+3 -1
View File
@@ -1497,7 +1497,10 @@ export class SNApplication
const syncEventCallback = async (eventName: ExternalServices.SyncEvent) => {
const appEvent = applicationEventForSyncEvent(eventName)
if (appEvent) {
await this.protocolService.onSyncEvent(eventName)
await this.notifyEvent(appEvent)
if (appEvent === ApplicationEvent.CompletedFullSync) {
if (!this.handledFullSyncStage) {
this.handledFullSyncStage = true
@@ -1505,7 +1508,6 @@ export class SNApplication
}
}
}
await this.protocolService.onSyncEvent(eventName)
}
const uninstall = this.syncService.addEventObserver(syncEventCallback)
this.serviceObservers.push(uninstall)
@@ -44,6 +44,7 @@ import {
SetOfflineFeaturesFunctionResponse,
StorageKey,
} from '@standardnotes/services'
import { FeatureIdentifier } from '@standardnotes/features'
type GetOfflineSubscriptionDetailsResponse = OfflineSubscriptionEntitlements | ClientDisplayableError
@@ -145,7 +146,10 @@ export class SNFeaturesService
override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
await super.handleApplicationStage(stage)
if (stage === ApplicationStage.FullSyncCompleted_13) {
void this.addDarkTheme()
if (!this.hasOnlineSubscription()) {
const offlineRepo = this.getOfflineRepo()
if (offlineRepo) {
@@ -155,6 +159,14 @@ export class SNFeaturesService
}
}
private async addDarkTheme() {
const darkThemeFeature = FeaturesImports.FindNativeFeature(FeatureIdentifier.DarkTheme)
if (darkThemeFeature) {
await this.mapRemoteNativeFeaturesToItems([darkThemeFeature])
}
}
public enableExperimentalFeature(identifier: FeaturesImports.FeatureIdentifier): void {
const feature = this.getUserFeature(identifier)
if (!feature) {
@@ -366,7 +378,7 @@ export class SNFeaturesService
if (!arraysEqual(this.roles, roles)) {
void this.notifyEvent(FeaturesEvent.UserRolesChanged)
}
await this.storageService.setValue(StorageKey.UserRoles, this.roles)
this.storageService.setValue(StorageKey.UserRoles, this.roles)
}
public async didDownloadFeatures(features: FeaturesImports.FeatureDescription[]): Promise<void> {
@@ -448,7 +460,15 @@ export class SNFeaturesService
return FeaturesImports.FindNativeFeature(featureId)?.deprecated === true
}
public isFreeFeature(featureId: FeaturesImports.FeatureIdentifier) {
return [FeatureIdentifier.DarkTheme].includes(featureId)
}
public getFeatureStatus(featureId: FeaturesImports.FeatureIdentifier): FeatureStatus {
if (this.isFreeFeature(featureId)) {
return FeatureStatus.Entitled
}
const isDeprecated = this.isFeatureDeprecated(featureId)
if (isDeprecated) {
if (this.hasPaidOnlineOrOfflineSubscription()) {
@@ -548,7 +568,9 @@ export class SNFeaturesService
let hasChanges = false
const now = new Date()
const expired = new Date(feature.expires_at || 0).getTime() < now.getTime()
const expired = this.isFreeFeature(feature.identifier)
? false
: new Date(feature.expires_at || 0).getTime() < now.getTime()
const existingItem = currentItems.find((item) => {
if (item.content.package_info) {
+7 -8
View File
@@ -1,12 +1,11 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('application instances', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
@@ -27,8 +26,8 @@ describe('application instances', () => {
expect(app1.payloadManager).to.not.equal(app2.payloadManager)
await Factory.createMappedNote(app1)
expect(app1.itemManager.items.length).length.to.equal(BASE_ITEM_COUNT + 1)
expect(app2.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
expect(app1.itemManager.items.length).length.to.equal(BaseItemCounts.DefaultItems + 1)
expect(app2.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
await Factory.safeDeinit(app1)
await Factory.safeDeinit(app2)
})
@@ -40,14 +39,14 @@ describe('application instances', () => {
await Factory.createMappedNote(app1)
await app1.syncService.sync(syncOptions)
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT)
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems)
await Factory.createMappedNote(app2)
await app2.syncService.sync(syncOptions)
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
await Factory.safeDeinit(app1)
await Factory.safeDeinit(app2)
})
@@ -1,16 +1,15 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('auth fringe cases', () => {
const BASE_ITEM_COUNT = ['default items key', 'user prefs'].length
const createContext = async () => {
const application = await Factory.createInitAppWithFakeCrypto()
return {
expectedItemCount: BASE_ITEM_COUNT,
expectedItemCount: BaseItemCounts.DefaultItems,
application: application,
email: UuidGenerator.GenerateUuid(),
password: UuidGenerator.GenerateUuid(),
@@ -100,9 +99,13 @@ describe('auth fringe cases', () => {
expect(newApplication.itemManager.getDisplayableNotes().length).to.equal(2)
expect(newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text).to.equal(staleText)
expect(
newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text,
).to.equal(staleText)
const conflictedCopy = newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid !== firstVersionOfNote.uuid)
const conflictedCopy = newApplication.itemManager
.getDisplayableNotes()
.find((n) => n.uuid !== firstVersionOfNote.uuid)
expect(conflictedCopy.text).to.equal(serverText)
expect(conflictedCopy.duplicate_of).to.equal(firstVersionOfNote.uuid)
await Factory.safeDeinit(newApplication)
+4 -5
View File
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
@@ -7,8 +8,6 @@ const expect = chai.expect
describe('basic auth', function () {
this.timeout(Factory.TenSecondTimeout)
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
@@ -16,7 +15,7 @@ describe('basic auth', function () {
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
@@ -62,7 +61,7 @@ describe('basic auth', function () {
expect(this.application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyNone)
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
expect(rawPayloads.length).to.equal(BASE_ITEM_COUNT)
expect(rawPayloads.length).to.equal(BaseItemCounts.DefaultItems)
})
it('successfully signs in to registered account', async function () {
@@ -408,7 +407,7 @@ describe('basic auth', function () {
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
expect(this.application.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
/** Should login with new password */
+3 -2
View File
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
@@ -24,8 +25,8 @@ describe('backups', function () {
this.application = null
})
const BASE_ITEM_COUNT_ENCRYPTED = ['ItemsKey', 'UserPreferences'].length
const BASE_ITEM_COUNT_DECRYPTED = ['UserPreferences'].length
const BASE_ITEM_COUNT_ENCRYPTED = BaseItemCounts.DefaultItems
const BASE_ITEM_COUNT_DECRYPTED = ['UserPreferences', 'DarkTheme'].length
it('backup file should have a version number', async function () {
let data = await this.application.createDecryptedBackupFile()
+13 -6
View File
@@ -83,11 +83,11 @@ describe('features', () => {
it('should fetch user features and create items for features with content type', async () => {
expect(application.apiService.getUserFeatures.callCount).to.equal(1)
expect(application.itemManager.createItem.callCount).to.equal(2)
const themeItems = application.items.getItems(ContentType.Theme)
const editorItems = application.items.getItems(ContentType.Component)
expect(themeItems).to.have.lengthOf(1)
expect(editorItems).to.have.lengthOf(1)
expect(themeItems[0].content).to.containSubset(
const systemThemeCount = 1
expect(themeItems).to.have.lengthOf(1 + systemThemeCount)
expect(themeItems[1].content).to.containSubset(
JSON.parse(
JSON.stringify({
name: midnightThemeFeature.name,
@@ -96,6 +96,9 @@ describe('features', () => {
}),
),
)
const editorItems = application.items.getItems(ContentType.Component)
expect(editorItems).to.have.lengthOf(1)
expect(editorItems[0].content).to.containSubset(
JSON.parse(
JSON.stringify({
@@ -157,7 +160,9 @@ describe('features', () => {
})
})
const themeItem = application.items.getItems(ContentType.Theme)[0]
const themeItem = application.items
.getItems(ContentType.Theme)
.find((theme) => theme.identifier === midnightThemeFeature.identifier)
// Wipe roles from initial sync
await application.featuresService.setRoles([])
@@ -171,7 +176,9 @@ describe('features', () => {
true,
)
const noTheme = application.items.getItems(ContentType.Theme)[0]
const noTheme = application.items
.getItems(ContentType.Theme)
.find((theme) => theme.identifier === midnightThemeFeature.identifier)
expect(noTheme).to.not.be.ok
})
})
+4
View File
@@ -2,6 +2,10 @@ import WebDeviceInterface from './web_device_interface.js'
import FakeWebCrypto from './fake_web_crypto.js'
import * as Defaults from './Defaults.js'
export const BaseItemCounts = {
DefaultItems: ['ItemsKey', 'UserPreferences', 'DarkTheme'].length,
}
export function createApplicationWithOptions({ identifier, environment, platform, host, crypto, device }) {
if (!device) {
device = new WebDeviceInterface()
@@ -161,14 +161,15 @@ describe('migrations', () => {
await application.mutator.insertItem(noDistractionItem)
await application.sync.sync()
expect(application.items.getItems(ContentType.Theme).length).to.equal(1)
const systemThemeCount = 1
expect(application.items.getItems(ContentType.Theme).length).to.equal(1 + systemThemeCount)
/** Run migration */
const migration = new Migration2_42_0(application.migrationService.services)
await migration.handleStage(ApplicationStage.FullSyncCompleted_13)
await application.sync.sync()
expect(application.items.getItems(ContentType.Theme).length).to.equal(0)
expect(application.items.getItems(ContentType.Theme).length).to.equal(systemThemeCount)
await Factory.safeDeinit(application)
})
@@ -1,12 +1,12 @@
/* eslint-disable camelcase */
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('app models', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const sharedApplication = Factory.createApplicationWithFakeCrypto()
before(async function () {
@@ -20,7 +20,7 @@ describe('app models', () => {
})
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
})
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
import { createRelatedNoteTagPairPayload } from '../lib/Items.js'
chai.use(chaiAsPromised)
@@ -7,7 +8,6 @@ const expect = chai.expect
describe('importing', function () {
this.timeout(Factory.TenSecondTimeout)
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
let expectedItemCount
let application
@@ -19,7 +19,7 @@ describe('importing', function () {
})
const setup = async ({ fakeCrypto }) => {
expectedItemCount = BASE_ITEM_COUNT
expectedItemCount = BaseItemCounts.DefaultItems
if (fakeCrypto) {
application = await Factory.createInitAppWithFakeCrypto()
} else {
@@ -599,12 +599,11 @@ describe('importing', function () {
application = await Factory.createInitAppWithFakeCrypto()
application.setLaunchCallback({
receiveChallenge: (challenge) => {
const values = challenge.prompts.map(
(prompt) =>
CreateChallengeValue(
prompt,
prompt.validation === ChallengeValidation.None ? 'incorrect password' : password,
),
const values = challenge.prompts.map((prompt) =>
CreateChallengeValue(
prompt,
prompt.validation === ChallengeValidation.None ? 'incorrect password' : password,
),
)
application.submitValuesForChallenge(challenge, values)
},
@@ -782,14 +781,13 @@ describe('importing', function () {
if (challenge.prompts.length === 2) {
application.submitValuesForChallenge(
challenge,
challenge.prompts.map(
(prompt) =>
CreateChallengeValue(
prompt,
prompt.validation !== ChallengeValidation.ProtectionSessionDuration
? password
: UnprotectedAccessSecondsDuration.OneMinute,
),
challenge.prompts.map((prompt) =>
CreateChallengeValue(
prompt,
prompt.validation !== ChallengeValidation.ProtectionSessionDuration
? password
: UnprotectedAccessSecondsDuration.OneMinute,
),
),
)
} else {
@@ -1,19 +1,18 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('items', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
}
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
})
@@ -1,15 +1,14 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
import { createNoteParams } from '../lib/Items.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('model manager mapping', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
})
@@ -2,19 +2,18 @@
import * as Factory from '../lib/factory.js'
import * as Utils from '../lib/Utils.js'
import { createRelatedNoteTagPairPayload } from '../lib/Items.js'
import { BaseItemCounts } from '../lib/Applications.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('notes and tags', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
}
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
})
+2 -3
View File
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
import WebDeviceInterface from './lib/web_device_interface.js'
chai.use(chaiAsPromised)
@@ -8,8 +9,6 @@ const expect = chai.expect
describe('server session', function () {
this.timeout(Factory.TenSecondTimeout)
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
@@ -17,7 +16,7 @@ describe('server session', function () {
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
+3 -3
View File
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
import WebDeviceInterface from './lib/web_device_interface.js'
chai.use(chaiAsPromised)
@@ -11,7 +12,6 @@ describe('singletons', function () {
const syncOptions = {
checkIntegrity: true,
}
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
function createPrefsPayload() {
const params = {
@@ -30,7 +30,7 @@ describe('singletons', function () {
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
@@ -83,7 +83,7 @@ describe('singletons', function () {
localStorage.clear()
})
it(`only resolves to ${BASE_ITEM_COUNT} items`, async function () {
it(`only resolves to ${BaseItemCounts.DefaultItems} items`, async function () {
/** Preferences are an item we know to always return true for isSingleton */
const prefs1 = createPrefsPayload()
const prefs2 = createPrefsPayload()
+5 -5
View File
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from './lib/Applications.js'
import * as Factory from './lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
@@ -11,7 +12,6 @@ describe('storage manager', function () {
* Base keys are `storage`, `snjs_version`, and `keychain`
*/
const BASE_KEY_COUNT = 3
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
beforeEach(async function () {
localStorage.clear()
@@ -37,7 +37,7 @@ describe('storage manager', function () {
const payload = Factory.createNotePayload()
await this.application.diskStorageService.savePayload(payload)
const payloads = await this.application.diskStorageService.getAllRawPayloads()
expect(payloads.length).to.equal(BASE_ITEM_COUNT + 1)
expect(payloads.length).to.equal(BaseItemCounts.DefaultItems + 1)
})
it('should clear values', async function () {
@@ -71,7 +71,7 @@ describe('storage manager', function () {
const value = 'bar'
await this.application.diskStorageService.setValue(key, value)
/** Items are stored in local storage */
expect(Object.keys(localStorage).length).to.equal(this.expectedKeyCount + BASE_ITEM_COUNT)
expect(Object.keys(localStorage).length).to.equal(this.expectedKeyCount + BaseItemCounts.DefaultItems)
const retrievedValue = await this.application.diskStorageService.getValue(key)
expect(retrievedValue).to.equal(value)
})
@@ -297,8 +297,8 @@ describe('storage manager', function () {
})
await Factory.createSyncedNote(this.application)
expect(await Factory.storagePayloadCount(this.application)).to.equal(BASE_ITEM_COUNT + 1)
expect(await Factory.storagePayloadCount(this.application)).to.equal(BaseItemCounts.DefaultItems + 1)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
expect(await Factory.storagePayloadCount(this.application)).to.equal(BASE_ITEM_COUNT)
expect(await Factory.storagePayloadCount(this.application)).to.equal(BaseItemCounts.DefaultItems)
})
})
@@ -1,13 +1,13 @@
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
import { createItemParams, createSyncedNoteWithTag } from '../lib/Items.js'
import { createSyncedNoteWithTag } from '../lib/Items.js'
import * as Utils from '../lib/Utils.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('online conflict handling', function () {
this.timeout(Factory.TenSecondTimeout)
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
@@ -16,7 +16,7 @@ describe('online conflict handling', function () {
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.context = await Factory.createAppContextWithFakeCrypto('AppA')
await this.context.launch()
@@ -1,12 +1,11 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('sync integrity', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
before(function () {
localStorage.clear()
})
@@ -16,7 +15,7 @@ describe('sync integrity', () => {
})
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
@@ -1,19 +1,18 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('offline syncing', () => {
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
awaitAll: true,
}
beforeEach(async function () {
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.application = await Factory.createInitAppWithFakeCrypto()
})
@@ -1,4 +1,5 @@
/* eslint-disable no-undef */
import { BaseItemCounts } from '../lib/Applications.js'
import * as Factory from '../lib/factory.js'
import * as Utils from '../lib/Utils.js'
chai.use(chaiAsPromised)
@@ -6,7 +7,6 @@ const expect = chai.expect
describe('online syncing', function () {
this.timeout(Factory.TenSecondTimeout)
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
const syncOptions = {
checkIntegrity: true,
@@ -15,7 +15,7 @@ describe('online syncing', function () {
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BASE_ITEM_COUNT
this.expectedItemCount = BaseItemCounts.DefaultItems
this.context = await Factory.createAppContext()
await this.context.launch()
@@ -97,7 +97,7 @@ describe('online syncing', function () {
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
expect(this.application.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
const promise = Factory.loginToApplication({
application: this.application,
@@ -244,7 +244,7 @@ describe('online syncing', function () {
// set item to be merged for when sign in occurs
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
expect(this.application.syncService.isOutOfSync()).to.equal(false)
expect(this.application.itemManager.getDirtyItems().length).to.equal(BASE_ITEM_COUNT + 1)
expect(this.application.itemManager.getDirtyItems().length).to.equal(BaseItemCounts.DefaultItems + 1)
// Sign back in for next tests
await Factory.loginToApplication({
@@ -686,7 +686,7 @@ describe('online syncing', function () {
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
expect(rawPayloads.length).to.equal(BASE_ITEM_COUNT)
expect(rawPayloads.length).to.equal(BaseItemCounts.DefaultItems)
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.136.0",
"version": "2.136.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -68,7 +68,7 @@
},
"dependencies": {
"@standardnotes/api": "workspace:*",
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"@standardnotes/domain-events": "^2.39.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/features": "workspace:*",
+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.6.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.6.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.6.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.6.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-07)
**Note:** Version bump only for package @standardnotes/ui-services
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.6.2",
"version": "1.6.5",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -23,7 +23,7 @@
"test": "jest spec --coverage --passWithNoTests"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"@standardnotes/filepicker": "workspace:^",
"@standardnotes/services": "workspace:^",
"@standardnotes/styles": "workspace:^",
+3 -10
View File
@@ -16,11 +16,11 @@ import {
StorageValueModes,
FeatureStatus,
} from '@standardnotes/services'
import { FeatureIdentifier } from '@standardnotes/snjs'
const CachedThemesKey = 'cachedThemes'
const TimeBeforeApplyingColorScheme = 5
const DefaultThemeIdentifier = 'Default'
const DarkThemeIdentifier = 'Dark'
export class ThemeManager extends AbstractService {
private activeThemes: Uuid[] = []
@@ -200,18 +200,14 @@ export class ThemeManager extends AbstractService {
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
const preference = prefersDarkColorScheme ? PrefKey.AutoDarkThemeIdentifier : PrefKey.AutoLightThemeIdentifier
const preferenceDefault =
preference === PrefKey.AutoDarkThemeIdentifier ? DarkThemeIdentifier : DefaultThemeIdentifier
preference === PrefKey.AutoDarkThemeIdentifier ? FeatureIdentifier.DarkTheme : DefaultThemeIdentifier
const themes = this.application.items
.getDisplayableComponents()
.filter((component) => component.isTheme()) as SNTheme[]
const activeTheme = themes.find((theme) => theme.active && !theme.isLayerable())
const activeThemeIdentifier = activeTheme
? activeTheme.identifier
: this.application.getPreference(PrefKey.DarkMode, false)
? DarkThemeIdentifier
: DefaultThemeIdentifier
const activeThemeIdentifier = activeTheme ? activeTheme.identifier : DefaultThemeIdentifier
const themeIdentifier = this.application.getPreference(preference, preferenceDefault) as string
@@ -225,9 +221,6 @@ export class ThemeManager extends AbstractService {
if (themeIdentifier === DefaultThemeIdentifier) {
toggleActiveTheme()
void this.application.setPreference(PrefKey.DarkMode, false)
} else if (themeIdentifier === DarkThemeIdentifier) {
toggleActiveTheme()
void this.application.setPreference(PrefKey.DarkMode, true)
} else {
const theme = themes.find((theme) => theme.package_info.identifier === themeIdentifier)
if (theme && !theme.active) {
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.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.9.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
### Features
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/utils",
"version": "1.9.0",
"version": "1.9.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -25,7 +25,7 @@
"test": "jest spec"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
"@standardnotes/common": "^1.36.1",
"dompurify": "^2.3.8",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13"
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.71.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-11)
**Note:** Version bump only for package @standardnotes/web
## [3.71.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))
## [3.71.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-10)
**Note:** Version bump only for package @standardnotes/web
## [3.71.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-09)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.71.2",
"version": "3.71.5",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -58,11 +58,6 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
}
})
themesAsItems.unshift({
label: 'Dark',
value: 'Dark',
})
themesAsItems.unshift({
label: 'Default',
value: 'Default',
@@ -166,13 +166,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
application.setPreference(PrefKey.DarkMode, false)
}, [application, deactivateAnyNonLayerableTheme])
const toggleDarkMode = useCallback(() => {
if (!isDarkModeOn) {
deactivateAnyNonLayerableTheme()
application.setPreference(PrefKey.DarkMode, true)
}
}, [application, isDarkModeOn, deactivateAnyNonLayerableTheme])
return (
<div>
{toggleableComponents.length > 0 && (
@@ -205,13 +198,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
<RadioIndicator checked={defaultThemeOn} className="mr-2" />
Default
</button>
<button
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
onClick={toggleDarkMode}
>
<RadioIndicator checked={isDarkModeOn} className="mr-2" />
Dark
</button>
{themes.map((theme) => (
<ThemesMenuButton item={theme} application={application} key={theme.component?.uuid ?? theme.identifier} />
))}
@@ -1,4 +1,7 @@
import { ThemeItem } from '@/Components/QuickSettingsMenu/ThemeItem'
import { FeatureIdentifier } from '@standardnotes/snjs'
const isDarkModeTheme = (theme: ThemeItem) => theme.identifier === FeatureIdentifier.DarkTheme
export const sortThemes = (a: ThemeItem, b: ThemeItem) => {
const aIsLayerable = a.component?.isLayerable()
@@ -8,6 +11,8 @@ export const sortThemes = (a: ThemeItem, b: ThemeItem) => {
return 1
} else if (!aIsLayerable && bIsLayerable) {
return -1
} else if (!isDarkModeTheme(a) && isDarkModeTheme(b)) {
return 1
} else {
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1
}
@@ -1,71 +0,0 @@
.dark-mode {
--foreground-color: #eeeeee;
--background-color: #0f1011;
--highlight-color: #a464c2;
--border-color: #0f1011;
--sn-component-foreground-color: var(--foreground-color);
--sn-component-background-color: transparent;
--sn-component-foreground-highlight-color: var(--highlight-color);
--sn-component-outer-border-color: transparent;
--sn-component-inner-border-color: var(--foreground-color);
// StyleKit Vars
--sn-stylekit-passive-color-0: #999999;
--sn-stylekit-passive-color-3: #28292b;
--sn-stylekit-passive-color-4: #1c1d1e;
--sn-stylekit-passive-color-5: #1d1f20;
--sn-stylekit-shadow-color: #000000;
--sn-stylekit-info-color: var(--highlight-color);
--sn-stylekit-info-contrast-color: var(--foreground-color);
--sn-stylekit-neutral-color: #7c7c7c;
--sn-stylekit-neutral-contrast-color: #ffffff;
--sn-stylekit-success-color: #2b9612;
--sn-stylekit-success-contrast-color: #ffffff;
--sn-stylekit-warning-color: #f6a200;
--sn-stylekit-warning-contrast-color: #ffffff;
--sn-stylekit-danger-color: #f80324;
--sn-stylekit-danger-contrast-color: #ffffff;
--sn-stylekit-editor-background-color: var(--sn-stylekit-background-color);
--sn-stylekit-editor-foreground-color: var(--sn-stylekit-foreground-color);
--sn-stylekit-background-color: var(--background-color);
--sn-stylekit-foreground-color: var(--foreground-color);
--sn-stylekit-border-color: #000000;
--sn-stylekit-contrast-background-color: #000000;
--sn-stylekit-contrast-foreground-color: #ffffff;
--sn-stylekit-contrast-border-color: #000000;
--sn-stylekit-secondary-background-color: var(--sn-stylekit-passive-color-4);
--sn-stylekit-secondary-foreground-color: #ffffff;
--sn-stylekit-secondary-border-color: #000000;
--sn-stylekit-secondary-contrast-background-color: #000000;
--sn-stylekit-secondary-contrast-foreground-color: #ffffff;
--sn-stylekit-secondary-contrast-border-color: #ffffff;
--sn-stylekit-paragraph-text-color: #ffffff;
--sn-desktop-titlebar-bg-color: var(--background-color);
--sn-desktop-titlebar-border-color: var(--border-color);
--sn-desktop-titlebar-ui-color: var(--foreground-color);
--sn-desktop-titlebar-ui-hover-color: var(--highlight-color);
--sn-stylekit-scrollbar-track-border-color: var(--border-color);
--sn-stylekit-scrollbar-thumb-color: var(--sn-stylekit-info-color);
--sn-stylekit-menu-border: 1px solid #424242;
// Theme
--navigation-item-selected-background-color: var(--background-color);
}
@@ -3,7 +3,6 @@
@import '../../../styles/src/Styles/_scrollbar.scss';
@import '../../../styles/src/Styles/utils/_animation.scss';
@import 'theme';
@import 'dark-mode';
@import 'main';
@import 'ui';
@import 'footer';
+15 -15
View File
@@ -6068,7 +6068,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/api@workspace:packages/api"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/encryption": "workspace:*"
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
@@ -6251,12 +6251,12 @@ __metadata:
languageName: node
linkType: hard
"@standardnotes/common@npm:^1.32.0":
version: 1.32.0
resolution: "@standardnotes/common@npm:1.32.0"
"@standardnotes/common@npm:^1.36.1":
version: 1.36.1
resolution: "@standardnotes/common@npm:1.36.1"
dependencies:
reflect-metadata: ^0.1.13
checksum: 52d33f385e4cc26ac8d2f723c3a5e12bb8a2c4a17f08700ca5843810583ca722475a83b71f86bb1402fda7c7c66e8149beb3f70848efc90da4aafef663d7ffbe
checksum: 4f2367d461aa1cd4e3ec132520310773183c3c9f8e423565aec315f5e5dffdce79f9704307a32fbfec17157f99d37d49982ad4272eee5aac0dbe37da34be054c
languageName: node
linkType: hard
@@ -6443,7 +6443,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/encryption@workspace:packages/encryption"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/config": 2.4.3
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
@@ -6485,7 +6485,7 @@ __metadata:
resolution: "@standardnotes/features@workspace:packages/features"
dependencies:
"@standardnotes/auth": ^3.19.4
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/security": ^1.2.0
"@types/jest": ^28.1.5
"@typescript-eslint/eslint-plugin": ^5.30.0
@@ -6501,7 +6501,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/filepicker@workspace:packages/filepicker"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/files": "workspace:*"
"@standardnotes/utils": "workspace:*"
"@types/jest": ^28.1.5
@@ -6519,7 +6519,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/files@workspace:packages/files"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/encryption": "workspace:*"
"@standardnotes/models": "workspace:*"
"@standardnotes/responses": "workspace:*"
@@ -6905,7 +6905,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/models@workspace:packages/models"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/features": "workspace:*"
"@standardnotes/responses": "workspace:*"
"@standardnotes/utils": "workspace:*"
@@ -6972,7 +6972,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/responses@workspace:packages/responses"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/features": "workspace:*"
"@standardnotes/security": ^1.1.0
"@types/jest": ^28.1.5
@@ -7041,7 +7041,7 @@ __metadata:
dependencies:
"@standardnotes/api": "workspace:^"
"@standardnotes/auth": ^3.19.4
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/encryption": "workspace:^"
"@standardnotes/files": "workspace:^"
"@standardnotes/models": "workspace:^"
@@ -7156,7 +7156,7 @@ __metadata:
"@babel/core": "*"
"@babel/preset-env": "*"
"@standardnotes/api": "workspace:*"
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/domain-events": ^2.39.0
"@standardnotes/encryption": "workspace:*"
"@standardnotes/features": "workspace:*"
@@ -7309,7 +7309,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/ui-services@workspace:packages/ui-services"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@standardnotes/filepicker": "workspace:^"
"@standardnotes/services": "workspace:^"
"@standardnotes/styles": "workspace:^"
@@ -7329,7 +7329,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@standardnotes/utils@workspace:packages/utils"
dependencies:
"@standardnotes/common": ^1.32.0
"@standardnotes/common": ^1.36.1
"@types/dompurify": ^2.3.3
"@types/jest": ^28.1.5
"@types/jsdom": ^16.2.14