chore: designated survivor test suite (#2540)
* chore: designated survivor test suite * add more tests * fix: tests exclusivness * fix removing account from shared vaults test
This commit is contained in:
Binary file not shown.
@@ -36,7 +36,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/models": "workspace:*",
|
"@standardnotes/models": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/utils": "workspace:*",
|
"@standardnotes/utils": "workspace:*",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.0.9",
|
"@electron/remote": "^2.0.9",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/electron-clear-data": "1.1.1",
|
"@standardnotes/electron-clear-data": "1.1.1",
|
||||||
"@standardnotes/web": "workspace:*",
|
"@standardnotes/web": "workspace:*",
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.1.3",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/models": "workspace:*",
|
"@standardnotes/models": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/sncrypto-common": "workspace:*",
|
"@standardnotes/sncrypto-common": "workspace:*",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"reflect-metadata": "^0.1.13"
|
"reflect-metadata": "^0.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/features": "workspace:*",
|
"@standardnotes/features": "workspace:*",
|
||||||
"@standardnotes/responses": "workspace:*",
|
"@standardnotes/responses": "workspace:*",
|
||||||
"@standardnotes/sncrypto-common": "workspace:^",
|
"@standardnotes/sncrypto-common": "workspace:^",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/api": "workspace:^",
|
"@standardnotes/api": "workspace:^",
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/encryption": "workspace:^",
|
"@standardnotes/encryption": "workspace:^",
|
||||||
"@standardnotes/features": "workspace:^",
|
"@standardnotes/features": "workspace:^",
|
||||||
"@standardnotes/files": "workspace:^",
|
"@standardnotes/files": "workspace:^",
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export class SharedVaultService
|
|||||||
await this.handleNotification(event.payload as NotificationServiceEventPayload)
|
await this.handleNotification(event.payload as NotificationServiceEventPayload)
|
||||||
break
|
break
|
||||||
case SyncEvent.ReceivedRemoteSharedVaults:
|
case SyncEvent.ReceivedRemoteSharedVaults:
|
||||||
void this.notifyEventSync(SharedVaultServiceEvent.SharedVaultStatusChanged)
|
void this.notifyEvent(SharedVaultServiceEvent.SharedVaultStatusChanged)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,20 @@ export class SharedVaultService
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case NotificationType.TYPES.UserRemovedFromSharedVault: {
|
case NotificationType.TYPES.UserRemovedFromSharedVault: {
|
||||||
this.vaultUsers.invalidateVaultUsersCache(event.eventPayload.props.primaryIdentifier.value).catch(console.error)
|
const vaultOrError = this._getVault.execute<SharedVaultListingInterface>({
|
||||||
|
sharedVaultUuid: event.eventPayload.props.primaryIdentifier.value,
|
||||||
|
})
|
||||||
|
if (!vaultOrError.isFailed()) {
|
||||||
|
const vault = vaultOrError.getValue()
|
||||||
|
|
||||||
|
this.vaultUsers
|
||||||
|
.invalidateVaultUsersCache(event.eventPayload.props.primaryIdentifier.value)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
await this._syncLocalVaultsWithRemoteSharedVaults.execute([vault])
|
||||||
|
|
||||||
|
void this.notifyEvent(SharedVaultServiceEvent.SharedVaultStatusChanged)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case NotificationType.TYPES.SharedVaultItemRemoved: {
|
case NotificationType.TYPES.SharedVaultItemRemoved: {
|
||||||
@@ -124,14 +137,15 @@ export class SharedVaultService
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case NotificationType.TYPES.SharedVaultFileRemoved:
|
case NotificationType.TYPES.SharedVaultFileRemoved:
|
||||||
case NotificationType.TYPES.SharedVaultFileUploaded: {
|
case NotificationType.TYPES.SharedVaultFileUploaded:
|
||||||
|
case NotificationType.TYPES.UserDesignatedAsSurvivor: {
|
||||||
const vaultOrError = this._getVault.execute<SharedVaultListingInterface>({
|
const vaultOrError = this._getVault.execute<SharedVaultListingInterface>({
|
||||||
sharedVaultUuid: event.eventPayload.props.primaryIdentifier.value,
|
sharedVaultUuid: event.eventPayload.props.primaryIdentifier.value,
|
||||||
})
|
})
|
||||||
if (!vaultOrError.isFailed()) {
|
if (!vaultOrError.isFailed()) {
|
||||||
await this._syncLocalVaultsWithRemoteSharedVaults.execute([vaultOrError.getValue()])
|
await this._syncLocalVaultsWithRemoteSharedVaults.execute([vaultOrError.getValue()])
|
||||||
|
|
||||||
void this.notifyEventSync(SharedVaultServiceEvent.SharedVaultStatusChanged)
|
void this.notifyEvent(SharedVaultServiceEvent.SharedVaultStatusChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,59 +1,63 @@
|
|||||||
export const BaseTests = [
|
export const BaseTests = {
|
||||||
'memory.test.js',
|
enabled: true,
|
||||||
'protocol.test.js',
|
exclusive: false,
|
||||||
'utils.test.js',
|
files: [
|
||||||
'000.test.js',
|
'memory.test.js',
|
||||||
'001.test.js',
|
'protocol.test.js',
|
||||||
'002.test.js',
|
'utils.test.js',
|
||||||
'003.test.js',
|
'000.test.js',
|
||||||
'004.test.js',
|
'001.test.js',
|
||||||
'username.test.js',
|
'002.test.js',
|
||||||
'app-group.test.js',
|
'003.test.js',
|
||||||
'application.test.js',
|
'004.test.js',
|
||||||
'payload.test.js',
|
'username.test.js',
|
||||||
'payload_encryption.test.js',
|
'app-group.test.js',
|
||||||
'item.test.js',
|
'application.test.js',
|
||||||
'item_manager.test.js',
|
'payload.test.js',
|
||||||
'features.test.js',
|
'payload_encryption.test.js',
|
||||||
'settings.test.js',
|
'item.test.js',
|
||||||
'mfa_service.test.js',
|
'item_manager.test.js',
|
||||||
'mutator.test.js',
|
'features.test.js',
|
||||||
'mutator_service.test.js',
|
'settings.test.js',
|
||||||
'payload_manager.test.js',
|
'mfa_service.test.js',
|
||||||
'collections.test.js',
|
'mutator.test.js',
|
||||||
'note_display_criteria.test.js',
|
'mutator_service.test.js',
|
||||||
'keys.test.js',
|
'payload_manager.test.js',
|
||||||
'key_params.test.js',
|
'collections.test.js',
|
||||||
'key_recovery_service.test.js',
|
'note_display_criteria.test.js',
|
||||||
'backups.test.js',
|
'keys.test.js',
|
||||||
'upgrading.test.js',
|
'key_params.test.js',
|
||||||
'model_tests/importing.test.js',
|
'key_recovery_service.test.js',
|
||||||
'model_tests/appmodels.test.js',
|
'backups.test.js',
|
||||||
'model_tests/items.test.js',
|
'upgrading.test.js',
|
||||||
'model_tests/mapping.test.js',
|
'model_tests/importing.test.js',
|
||||||
'model_tests/notes_smart_tags.test.js',
|
'model_tests/appmodels.test.js',
|
||||||
'model_tests/notes_tags.test.js',
|
'model_tests/items.test.js',
|
||||||
'model_tests/notes_tags_folders.test.js',
|
'model_tests/mapping.test.js',
|
||||||
'model_tests/performance.test.js',
|
'model_tests/notes_smart_tags.test.js',
|
||||||
'sync_tests/offline.test.js',
|
'model_tests/notes_tags.test.js',
|
||||||
'sync_tests/notes_tags.test.js',
|
'model_tests/notes_tags_folders.test.js',
|
||||||
'sync_tests/online.test.js',
|
'model_tests/performance.test.js',
|
||||||
'sync_tests/conflicting.test.js',
|
'sync_tests/offline.test.js',
|
||||||
'sync_tests/integrity.test.js',
|
'sync_tests/notes_tags.test.js',
|
||||||
'auth-fringe-cases.test.js',
|
'sync_tests/online.test.js',
|
||||||
'auth.test.js',
|
'sync_tests/conflicting.test.js',
|
||||||
'device_auth.test.js',
|
'sync_tests/integrity.test.js',
|
||||||
'storage.test.js',
|
'auth-fringe-cases.test.js',
|
||||||
'protection.test.js',
|
'auth.test.js',
|
||||||
'singletons.test.js',
|
'device_auth.test.js',
|
||||||
'migrations/migration.test.js',
|
'storage.test.js',
|
||||||
'migrations/tags-to-folders.test.js',
|
'protection.test.js',
|
||||||
'history.test.js',
|
'singletons.test.js',
|
||||||
'actions.test.js',
|
'migrations/migration.test.js',
|
||||||
'preferences.test.js',
|
'migrations/tags-to-folders.test.js',
|
||||||
'files.test.js',
|
'history.test.js',
|
||||||
'session.test.js',
|
'actions.test.js',
|
||||||
'session-invalidation.test.js',
|
'preferences.test.js',
|
||||||
'subscriptions.test.js',
|
'files.test.js',
|
||||||
'recovery.test.js',
|
'session.test.js',
|
||||||
]
|
'session-invalidation.test.js',
|
||||||
|
'subscriptions.test.js',
|
||||||
|
'recovery.test.js',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ export const VaultTests = {
|
|||||||
'vaults/files.test.js',
|
'vaults/files.test.js',
|
||||||
'vaults/limits.test.js',
|
'vaults/limits.test.js',
|
||||||
'vaults/quota.test.js',
|
'vaults/quota.test.js',
|
||||||
|
'vaults/surviving.test.js',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const acceptAllInvites = async (context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inviteContext = async (context, contactContext, sharedVault, contact, permission) => {
|
export const inviteContext = async (context, contactContext, sharedVault, contact, permission) => {
|
||||||
contactContext.lockSyncing()
|
contactContext.lockSyncing()
|
||||||
|
|
||||||
const inviteOrError = await context.vaultInvites.inviteContactToSharedVault(sharedVault, contact, permission)
|
const inviteOrError = await context.vaultInvites.inviteContactToSharedVault(sharedVault, contact, permission)
|
||||||
@@ -207,3 +207,12 @@ export const moveItemToVault = async (context, sharedVault, item) => {
|
|||||||
|
|
||||||
return result.getValue()
|
return result.getValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const designateSharedVaultSurvior = async (context, sharedVault, survivorUuid) => {
|
||||||
|
const result = await context.vaultUsers.designateSurvivor(sharedVault, survivorUuid)
|
||||||
|
if (result.isFailed()) {
|
||||||
|
throw new Error(result.getError())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.getValue()
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,14 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import MainRegistry from './TestRegistry/MainRegistry.js'
|
import MainRegistry from './TestRegistry/MainRegistry.js'
|
||||||
|
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
|
const testSuite = urlSearchParams.get('suite');
|
||||||
|
if (testSuite === 'vaults') {
|
||||||
|
MainRegistry.VaultTests.exclusive = true;
|
||||||
|
} else if (testSuite === 'base') {
|
||||||
|
MainRegistry.BaseTests.exclusive = true;
|
||||||
|
}
|
||||||
|
|
||||||
const loadTest = (fileName) => {
|
const loadTest = (fileName) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
@@ -56,18 +64,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainRegistry.VaultTests.enabled) {
|
InternalFeatureService.get().enableFeature(InternalFeature.Vaults);
|
||||||
InternalFeatureService.get().enableFeature(InternalFeature.Vaults);
|
|
||||||
if (MainRegistry.VaultTests.exclusive) {
|
if (MainRegistry.VaultTests.exclusive) {
|
||||||
await loadTests(MainRegistry.VaultTests.files);
|
await loadTests(MainRegistry.VaultTests.files);
|
||||||
} else {
|
} else if (MainRegistry.BaseTests.exclusive) {
|
||||||
await loadTests([
|
await loadTests(MainRegistry.BaseTests.files);
|
||||||
...MainRegistry.BaseTests,
|
|
||||||
...MainRegistry.VaultTests.files
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await loadTests(MainRegistry.BaseTests);
|
await loadTests([
|
||||||
|
...MainRegistry.BaseTests.files,
|
||||||
|
...MainRegistry.VaultTests.files
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mocha.run()
|
mocha.run()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as Factory from '../lib/factory.js'
|
import * as Factory from '../lib/factory.js'
|
||||||
|
import * as Utils from '../lib/Utils.js'
|
||||||
import * as Collaboration from '../lib/Collaboration.js'
|
import * as Collaboration from '../lib/Collaboration.js'
|
||||||
|
|
||||||
chai.use(chaiAsPromised)
|
chai.use(chaiAsPromised)
|
||||||
@@ -167,4 +168,47 @@ describe('shared vault deletion', function () {
|
|||||||
|
|
||||||
await deinitContactContext()
|
await deinitContactContext()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should remove a user from all shared vaults upon account removal', async () => {
|
||||||
|
const secondContext = await Factory.createVaultsContextWithRealCrypto()
|
||||||
|
await secondContext.launch()
|
||||||
|
await secondContext.register()
|
||||||
|
|
||||||
|
const thirdContext = await Factory.createVaultsContextWithRealCrypto()
|
||||||
|
await thirdContext.launch()
|
||||||
|
await thirdContext.register()
|
||||||
|
|
||||||
|
const firstVault = await Collaboration.createSharedVault(context)
|
||||||
|
const secondVault = await Collaboration.createSharedVault(thirdContext)
|
||||||
|
|
||||||
|
const firstToSecondContact = await Collaboration.createTrustedContactForUserOfContext(context, secondContext)
|
||||||
|
await Collaboration.createTrustedContactForUserOfContext(secondContext, context)
|
||||||
|
|
||||||
|
const thirdToSecondContact = await Collaboration.createTrustedContactForUserOfContext(thirdContext, secondContext)
|
||||||
|
await Collaboration.createTrustedContactForUserOfContext(thirdContext, context)
|
||||||
|
|
||||||
|
await Collaboration.inviteContext(context, secondContext, firstVault, firstToSecondContact, SharedVaultUserPermission.PERMISSIONS.Write)
|
||||||
|
await Collaboration.inviteContext(thirdContext, secondContext, secondVault, thirdToSecondContact, SharedVaultUserPermission.PERMISSIONS.Write)
|
||||||
|
|
||||||
|
const promise = secondContext.awaitNextSyncSharedVaultFromScratchEvent()
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(secondContext)
|
||||||
|
|
||||||
|
await Utils.awaitPromiseOrThrow(promise, 2.0, 'Waiting for vault to sync')
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(secondContext.application, secondContext.password)
|
||||||
|
await secondContext.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await context.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedVaultUsersInFirstVault = await context.vaultUsers.getSharedVaultUsersFromServer(firstVault)
|
||||||
|
expect(sharedVaultUsersInFirstVault.length).to.equal(1)
|
||||||
|
|
||||||
|
const sharedVaultUsersInSecondVault = await thirdContext.vaultUsers.getSharedVaultUsersFromServer(secondVault)
|
||||||
|
expect(sharedVaultUsersInSecondVault.length).to.equal(1)
|
||||||
|
|
||||||
|
await secondContext.deinit()
|
||||||
|
await thirdContext.deinit()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
363
packages/snjs/mocha/vaults/surviving.test.js
Normal file
363
packages/snjs/mocha/vaults/surviving.test.js
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
import * as Factory from '../lib/factory.js'
|
||||||
|
import * as Files from '../lib/Files.js'
|
||||||
|
import * as Collaboration from '../lib/Collaboration.js'
|
||||||
|
|
||||||
|
chai.use(chaiAsPromised)
|
||||||
|
const expect = chai.expect
|
||||||
|
|
||||||
|
describe('designated survival', function () {
|
||||||
|
this.timeout(Factory.TwentySecondTimeout)
|
||||||
|
|
||||||
|
let context
|
||||||
|
let secondContext
|
||||||
|
let thirdContext
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
localStorage.clear()
|
||||||
|
|
||||||
|
context = await Factory.createVaultsContextWithRealCrypto()
|
||||||
|
|
||||||
|
await context.launch()
|
||||||
|
await context.register()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async function () {
|
||||||
|
await context.deinit()
|
||||||
|
localStorage.clear()
|
||||||
|
sinon.restore()
|
||||||
|
context = undefined
|
||||||
|
if (secondContext) {
|
||||||
|
await secondContext.deinit()
|
||||||
|
secondContext = undefined
|
||||||
|
}
|
||||||
|
if (thirdContext) {
|
||||||
|
await thirdContext.deinit()
|
||||||
|
thirdContext = undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should indicate that a vault has a designated survivor', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
let vault = context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(vault.sharing.designatedSurvivor).to.be.null
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
await context.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
vault = context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(vault.sharing.designatedSurvivor).to.equal(contactContext.userUuid)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('owner of a shared vault with a designated survivor removing the vault', () => {
|
||||||
|
it('should not remove all users from the vault upon shared vault removal', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||||
|
|
||||||
|
await context.syncAndAwaitNotificationsProcessing()
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||||
|
expect(sharedVaultUsers.length).to.equal(2)
|
||||||
|
|
||||||
|
expect(context.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||||
|
expect(context.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||||
|
expect(context.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||||
|
|
||||||
|
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||||
|
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||||
|
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||||
|
|
||||||
|
expect(thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||||
|
expect(thirdContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||||
|
expect(thirdContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should transition items of the owner in the vault to the designated survivor', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
|
await Collaboration.moveItemToVault(context, sharedVault, note)
|
||||||
|
|
||||||
|
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||||
|
expect(sharedVaultUsers.length).to.equal(2)
|
||||||
|
|
||||||
|
const contactNote = secondContext.items.findItem(note.uuid)
|
||||||
|
expect(contactNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||||
|
expect(contactNote.user_uuid).to.equal(secondContext.userUuid)
|
||||||
|
|
||||||
|
const thirdPartyNote = thirdContext.items.findItem(note.uuid)
|
||||||
|
expect(thirdPartyNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||||
|
expect(thirdPartyNote.user_uuid).to.equal(secondContext.userUuid)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should still allow to download files of the owner in the vault', async () => {
|
||||||
|
await context.activatePaidSubscriptionForUser()
|
||||||
|
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
const response = await fetch('/mocha/assets/small_file.md')
|
||||||
|
const buffer = new Uint8Array(await response.arrayBuffer())
|
||||||
|
const uploadedFile = await Files.uploadFile(context.files, buffer, 'my-file', 'md', 1000, sharedVault)
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedFileBefore = secondContext.items.findItem(uploadedFile.uuid)
|
||||||
|
expect(sharedFileBefore).to.not.be.undefined
|
||||||
|
expect(sharedFileBefore.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||||
|
|
||||||
|
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedFileAfter = secondContext.items.findItem(uploadedFile.uuid)
|
||||||
|
expect(sharedFileAfter).to.not.be.undefined
|
||||||
|
expect(sharedFileAfter.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||||
|
|
||||||
|
const downloadedBytes = await Files.downloadFile(secondContext.files, sharedFileAfter)
|
||||||
|
expect(downloadedBytes).to.eql(buffer)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should transition vault ownership to the designated survivor', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
await context.sharedVaults.deleteSharedVault(sharedVault)
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const contactVault = secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(contactVault.sharing.ownerUserUuid).to.not.equal(context.userUuid)
|
||||||
|
expect(contactVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||||
|
|
||||||
|
const thirdPartyVault = thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(thirdPartyVault.sharing.ownerUserUuid).to.not.equal(context.userUuid)
|
||||||
|
expect(thirdPartyVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('owner of a shared vault with a designated survivor deleting their account', () => {
|
||||||
|
it('should not remove all users from the vault upon account removal', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(context.application, context.password)
|
||||||
|
await context.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||||
|
expect(sharedVaultUsers.length).to.equal(2)
|
||||||
|
|
||||||
|
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||||
|
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||||
|
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||||
|
|
||||||
|
expect(thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.not.be.undefined
|
||||||
|
expect(thirdContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.not.be.undefined
|
||||||
|
expect(thirdContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.not.be.empty
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should transition items of the owner in the vault to the designated survivor', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
const note = await context.createSyncedNote('foo', 'bar')
|
||||||
|
await Collaboration.moveItemToVault(context, sharedVault, note)
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(context.application, context.password)
|
||||||
|
await context.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedVaultUsers = await secondContext.vaultUsers.getSharedVaultUsersFromServer(sharedVault)
|
||||||
|
expect(sharedVaultUsers.length).to.equal(2)
|
||||||
|
|
||||||
|
const contactNote = secondContext.items.findItem(note.uuid)
|
||||||
|
expect(contactNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||||
|
expect(contactNote.user_uuid).to.equal(secondContext.userUuid)
|
||||||
|
|
||||||
|
const thirdPartyNote = thirdContext.items.findItem(note.uuid)
|
||||||
|
expect(thirdPartyNote.key_system_identifier).to.equal(sharedVault.systemIdentifier)
|
||||||
|
expect(thirdPartyNote.user_uuid).to.equal(secondContext.userUuid)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should still allow to download files of the owner in the vault', async () => {
|
||||||
|
await context.activatePaidSubscriptionForUser()
|
||||||
|
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
const response = await fetch('/mocha/assets/small_file.md')
|
||||||
|
const buffer = new Uint8Array(await response.arrayBuffer())
|
||||||
|
const uploadedFile = await Files.uploadFile(context.files, buffer, 'my-file', 'md', 1000, sharedVault)
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedFileBefore = secondContext.items.findItem(uploadedFile.uuid)
|
||||||
|
expect(sharedFileBefore).to.not.be.undefined
|
||||||
|
expect(sharedFileBefore.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(context.application, context.password)
|
||||||
|
await context.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const sharedFileAfter = secondContext.items.findItem(uploadedFile.uuid)
|
||||||
|
expect(sharedFileAfter).to.not.be.undefined
|
||||||
|
expect(sharedFileAfter.remoteIdentifier).to.equal(uploadedFile.remoteIdentifier)
|
||||||
|
|
||||||
|
const downloadedBytes = await Files.downloadFile(secondContext.files, sharedFileAfter)
|
||||||
|
expect(downloadedBytes).to.eql(buffer)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should transition vault ownership to the designated survivor', async () => {
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
await Collaboration.designateSharedVaultSurvior(context, sharedVault, contactContext.userUuid)
|
||||||
|
|
||||||
|
const { thirdPartyContext } = await Collaboration.inviteNewPartyToSharedVault(
|
||||||
|
context,
|
||||||
|
sharedVault,
|
||||||
|
)
|
||||||
|
thirdContext = thirdPartyContext
|
||||||
|
|
||||||
|
await Collaboration.acceptAllInvites(thirdContext)
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(context.application, context.password)
|
||||||
|
await context.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
const contactVault = secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(contactVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||||
|
|
||||||
|
const thirdPartyVault = thirdContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })
|
||||||
|
expect(thirdPartyVault.sharing.ownerUserUuid).to.equal(secondContext.userUuid)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('owner of a shared vault without a designated survivor deleting their account', () => {
|
||||||
|
it('should remove all users from all shared vaults upon account removal', async () => {
|
||||||
|
await context.activatePaidSubscriptionForUser()
|
||||||
|
|
||||||
|
const { sharedVault, contactContext } =
|
||||||
|
await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
secondContext = contactContext
|
||||||
|
|
||||||
|
const result = await Collaboration.createSharedVaultWithAcceptedInvite(context)
|
||||||
|
thirdContext = result.contactContext
|
||||||
|
const secondSharedVault = result.sharedVault
|
||||||
|
|
||||||
|
Factory.handlePasswordChallenges(context.application, context.password)
|
||||||
|
await context.application.user.deleteAccount()
|
||||||
|
|
||||||
|
await secondContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
await thirdContext.syncAndAwaitNotificationsProcessing()
|
||||||
|
|
||||||
|
expect(secondContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier })).to.be.undefined
|
||||||
|
expect(secondContext.keys.getPrimaryKeySystemRootKey(sharedVault.systemIdentifier)).to.be.undefined
|
||||||
|
expect(secondContext.keys.getKeySystemItemsKeys(sharedVault.systemIdentifier)).to.be.empty
|
||||||
|
|
||||||
|
expect(thirdContext.vaults.getVault({ keySystemIdentifier: secondSharedVault.systemIdentifier })).to.be.undefined
|
||||||
|
expect(thirdContext.keys.getPrimaryKeySystemRootKey(secondSharedVault.systemIdentifier)).to.be.undefined
|
||||||
|
expect(thirdContext.keys.getKeySystemItemsKeys(secondSharedVault.systemIdentifier)).to.be.empty
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"@babel/preset-env": "*",
|
"@babel/preset-env": "*",
|
||||||
"@standardnotes/api": "workspace:*",
|
"@standardnotes/api": "workspace:*",
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/domain-events": "^2.122.0",
|
"@standardnotes/domain-events": "^2.122.0",
|
||||||
"@standardnotes/encryption": "workspace:*",
|
"@standardnotes/encryption": "workspace:*",
|
||||||
"@standardnotes/features": "workspace:*",
|
"@standardnotes/features": "workspace:*",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standardnotes/common": "^1.50.0",
|
"@standardnotes/common": "^1.50.0",
|
||||||
"@standardnotes/domain-core": "^1.33.1",
|
"@standardnotes/domain-core": "^1.34.1",
|
||||||
"@standardnotes/features": "workspace:^",
|
"@standardnotes/features": "workspace:^",
|
||||||
"@standardnotes/filepicker": "workspace:^",
|
"@standardnotes/filepicker": "workspace:^",
|
||||||
"@standardnotes/models": "workspace:^",
|
"@standardnotes/models": "workspace:^",
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@@ -4138,7 +4138,7 @@ __metadata:
|
|||||||
resolution: "@standardnotes/api@workspace:packages/api"
|
resolution: "@standardnotes/api@workspace:packages/api"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/models": "workspace:*"
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
"@standardnotes/utils": "workspace:*"
|
"@standardnotes/utils": "workspace:*"
|
||||||
@@ -4288,7 +4288,7 @@ __metadata:
|
|||||||
"@babel/core": "*"
|
"@babel/core": "*"
|
||||||
"@babel/preset-env": "*"
|
"@babel/preset-env": "*"
|
||||||
"@electron/remote": ^2.0.9
|
"@electron/remote": ^2.0.9
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/electron-clear-data": 1.1.1
|
"@standardnotes/electron-clear-data": 1.1.1
|
||||||
"@standardnotes/web": "workspace:*"
|
"@standardnotes/web": "workspace:*"
|
||||||
"@types/fs-extra": ^11.0.1
|
"@types/fs-extra": ^11.0.1
|
||||||
@@ -4340,12 +4340,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@standardnotes/domain-core@npm:^1.33.1":
|
"@standardnotes/domain-core@npm:^1.34.1":
|
||||||
version: 1.33.1
|
version: 1.34.1
|
||||||
resolution: "@standardnotes/domain-core@npm:1.33.1"
|
resolution: "@standardnotes/domain-core@npm:1.34.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
uuid: ^9.0.0
|
uuid: ^9.0.0
|
||||||
checksum: 4caba6cd6fa667158aa326e43762bc466b726dfbd89e04cfc6fd6b89dce573b1be231350470fc7f1d027868bfd096096de7733256d35a7be699d693e84d29f2a
|
checksum: 29fa0ee7868b08a5255ce737535aa67b9fe8f0562f7d5a308f4be4a63d46821f34b4ea1d4241064e3025968ae45e09eba3dcbd1ff8d510618114541c42a8e6ae
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -4392,7 +4392,7 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/config": 2.4.3
|
"@standardnotes/config": 2.4.3
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/models": "workspace:*"
|
"@standardnotes/models": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
"@standardnotes/sncrypto-common": "workspace:*"
|
"@standardnotes/sncrypto-common": "workspace:*"
|
||||||
@@ -4427,7 +4427,7 @@ __metadata:
|
|||||||
resolution: "@standardnotes/features@workspace:packages/features"
|
resolution: "@standardnotes/features@workspace:packages/features"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@types/jest": ^29.2.3
|
"@types/jest": ^29.2.3
|
||||||
"@typescript-eslint/eslint-plugin": "*"
|
"@typescript-eslint/eslint-plugin": "*"
|
||||||
eslint: "*"
|
eslint: "*"
|
||||||
@@ -4633,7 +4633,7 @@ __metadata:
|
|||||||
resolution: "@standardnotes/models@workspace:packages/models"
|
resolution: "@standardnotes/models@workspace:packages/models"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/features": "workspace:*"
|
"@standardnotes/features": "workspace:*"
|
||||||
"@standardnotes/responses": "workspace:*"
|
"@standardnotes/responses": "workspace:*"
|
||||||
"@standardnotes/sncrypto-common": "workspace:^"
|
"@standardnotes/sncrypto-common": "workspace:^"
|
||||||
@@ -4729,7 +4729,7 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/api": "workspace:^"
|
"@standardnotes/api": "workspace:^"
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/encryption": "workspace:^"
|
"@standardnotes/encryption": "workspace:^"
|
||||||
"@standardnotes/features": "workspace:^"
|
"@standardnotes/features": "workspace:^"
|
||||||
"@standardnotes/files": "workspace:^"
|
"@standardnotes/files": "workspace:^"
|
||||||
@@ -4830,7 +4830,7 @@ __metadata:
|
|||||||
"@babel/preset-env": "*"
|
"@babel/preset-env": "*"
|
||||||
"@standardnotes/api": "workspace:*"
|
"@standardnotes/api": "workspace:*"
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/domain-events": ^2.122.0
|
"@standardnotes/domain-events": ^2.122.0
|
||||||
"@standardnotes/encryption": "workspace:*"
|
"@standardnotes/encryption": "workspace:*"
|
||||||
"@standardnotes/features": "workspace:*"
|
"@standardnotes/features": "workspace:*"
|
||||||
@@ -4955,7 +4955,7 @@ __metadata:
|
|||||||
resolution: "@standardnotes/ui-services@workspace:packages/ui-services"
|
resolution: "@standardnotes/ui-services@workspace:packages/ui-services"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@standardnotes/common": ^1.50.0
|
"@standardnotes/common": ^1.50.0
|
||||||
"@standardnotes/domain-core": ^1.33.1
|
"@standardnotes/domain-core": ^1.34.1
|
||||||
"@standardnotes/features": "workspace:^"
|
"@standardnotes/features": "workspace:^"
|
||||||
"@standardnotes/filepicker": "workspace:^"
|
"@standardnotes/filepicker": "workspace:^"
|
||||||
"@standardnotes/models": "workspace:^"
|
"@standardnotes/models": "workspace:^"
|
||||||
|
|||||||
Reference in New Issue
Block a user