@twin.org/synchronised-storage-service 0.0.3-next.9 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/es/helpers/blobStorageHelper.js +1 -1
- package/dist/es/helpers/blobStorageHelper.js.map +1 -1
- package/dist/es/helpers/changeSetHelper.js +3 -3
- package/dist/es/helpers/changeSetHelper.js.map +1 -1
- package/dist/es/helpers/localSyncStateHelper.js +7 -7
- package/dist/es/helpers/localSyncStateHelper.js.map +1 -1
- package/dist/es/helpers/remoteSyncStateHelper.js +14 -9
- package/dist/es/helpers/remoteSyncStateHelper.js.map +1 -1
- package/dist/es/helpers/versions.js +9 -0
- package/dist/es/helpers/versions.js.map +1 -1
- package/dist/es/restEntryPoints.js +3 -0
- package/dist/es/restEntryPoints.js.map +1 -1
- package/dist/es/synchronisedStorageRoutes.js +4 -2
- package/dist/es/synchronisedStorageRoutes.js.map +1 -1
- package/dist/es/synchronisedStorageService.js +14 -11
- package/dist/es/synchronisedStorageService.js.map +1 -1
- package/dist/types/helpers/blobStorageHelper.d.ts +1 -1
- package/dist/types/helpers/changeSetHelper.d.ts +3 -3
- package/dist/types/helpers/localSyncStateHelper.d.ts +5 -5
- package/dist/types/helpers/remoteSyncStateHelper.d.ts +10 -19
- package/dist/types/helpers/versions.d.ts +9 -0
- package/dist/types/restEntryPoints.d.ts +3 -0
- package/dist/types/synchronisedStorageService.d.ts +3 -3
- package/docs/changelog.md +229 -76
- package/docs/examples.md +80 -1
- package/docs/open-api/spec.json +17 -21
- package/docs/reference/classes/SyncSnapshotEntry.md +12 -12
- package/docs/reference/classes/SynchronisedStorageService.md +9 -9
- package/docs/reference/interfaces/ISyncPointerStore.md +2 -2
- package/docs/reference/interfaces/ISyncSnapshot.md +7 -7
- package/docs/reference/interfaces/ISyncState.md +3 -3
- package/docs/reference/interfaces/ISynchronisedStorageServiceConfig.md +13 -13
- package/docs/reference/interfaces/ISynchronisedStorageServiceConstructorOptions.md +19 -19
- package/docs/reference/variables/restEntryPoints.md +2 -0
- package/package.json +20 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remoteSyncStateHelper.js","sourceRoot":"","sources":["../../../src/helpers/remoteSyncStateHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tBaseError,\n\tConverter,\n\tIs,\n\tNotFoundError,\n\tObjectHelper,\n\tRandomHelper\n} from \"@twin.org/core\";\nimport type { IEventBusComponent } from \"@twin.org/event-bus-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\ttype ISyncBatchRequest,\n\ttype ISyncBatchResponse,\n\ttype ISyncChange,\n\ttype ISyncChangeSet,\n\ttype ISyncItemResponse,\n\tSyncNodeIdMode,\n\tSyncChangeOperation,\n\tSynchronisedStorageTopics,\n\tSynchronisedStorageContexts,\n\tSynchronisedStorageTypes,\n\ttype ISynchronisedEntity\n} from \"@twin.org/synchronised-storage-models\";\nimport type { IVerifiableStorageConnector } from \"@twin.org/verifiable-storage-models\";\nimport type { BlobStorageHelper } from \"./blobStorageHelper.js\";\nimport type { ChangeSetHelper } from \"./changeSetHelper.js\";\nimport {\n\tSYNC_POINTER_STORE_VERSION,\n\tSYNC_SNAPSHOT_VERSION,\n\tSYNC_STATE_VERSION\n} from \"./versions.js\";\nimport type { ISyncPointerStore } from \"../models/ISyncPointerStore.js\";\nimport type { ISyncSnapshot } from \"../models/ISyncSnapshot.js\";\nimport type { ISyncState } from \"../models/ISyncState.js\";\n\n/**\n * Class for performing entity storage operations in decentralised storage.\n */\nexport class RemoteSyncStateHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<RemoteSyncStateHelper>();\n\n\t/**\n\t * The logging component to use for logging.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The event bus component.\n\t * @internal\n\t */\n\tprivate readonly _eventBusComponent: IEventBusComponent;\n\n\t/**\n\t * The blob storage helper.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\n\n\t/**\n\t * The verifiable storage connector to use for storing sync pointers.\n\t * @internal\n\t */\n\tprivate readonly _verifiableSyncPointerStorageConnector: IVerifiableStorageConnector;\n\n\t/**\n\t * The change set helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _changeSetHelper: ChangeSetHelper;\n\n\t/**\n\t * The storage ids of the batch responses for each storage key.\n\t * @internal\n\t */\n\tprivate readonly _batchResponseStorageIds: { [storageKey: string]: string[] };\n\n\t/**\n\t * The full changes for each storage key.\n\t * @internal\n\t */\n\tprivate readonly _populateFullChanges: {\n\t\t[storageKey: string]: {\n\t\t\tchanges: ISyncChange[];\n\t\t\tentities: { [id: string]: ISynchronisedEntity | undefined };\n\t\t\trequestIds: string[];\n\t\t\tcompleteCallback: (id?: string) => Promise<void>;\n\t\t};\n\t};\n\n\t/**\n\t * The synchronised storage key to use for verified storage operations.\n\t * @internal\n\t */\n\tprivate _synchronisedStorageKey?: string;\n\n\t/**\n\t * The identity of the node that is performing the update.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Whether the node is trusted or not.\n\t * @internal\n\t */\n\tprivate readonly _isTrustedNode: boolean;\n\n\t/**\n\t * Maximum number of consolidations to keep in storage.\n\t * @internal\n\t */\n\tprivate readonly _maxConsolidations: number;\n\n\t/**\n\t * Create a new instance of RemoteSyncStateHelper.\n\t * @param loggingComponent The logging component to use for logging.\n\t * @param eventBusComponent The event bus component to use for events.\n\t * @param verifiableSyncPointerStorageConnector The verifiable storage connector to use for storing sync pointers.\n\t * @param blobStorageHelper The blob storage helper to use for remote sync states.\n\t * @param changeSetHelper The change set helper to use for managing changesets.\n\t * @param isTrustedNode Whether the node is trusted or not.\n\t * @param maxConsolidations The maximum number of consolidations to keep in storage.\n\t */\n\tconstructor(\n\t\tloggingComponent: ILoggingComponent | undefined,\n\t\teventBusComponent: IEventBusComponent,\n\t\tverifiableSyncPointerStorageConnector: IVerifiableStorageConnector,\n\t\tblobStorageHelper: BlobStorageHelper,\n\t\tchangeSetHelper: ChangeSetHelper,\n\t\tisTrustedNode: boolean,\n\t\tmaxConsolidations: number\n\t) {\n\t\tthis._logging = loggingComponent;\n\t\tthis._eventBusComponent = eventBusComponent;\n\t\tthis._verifiableSyncPointerStorageConnector = verifiableSyncPointerStorageConnector;\n\t\tthis._changeSetHelper = changeSetHelper;\n\t\tthis._blobStorageHelper = blobStorageHelper;\n\t\tthis._isTrustedNode = isTrustedNode;\n\t\tthis._maxConsolidations = maxConsolidations;\n\n\t\tthis._batchResponseStorageIds = {};\n\t\tthis._populateFullChanges = {};\n\t}\n\n\t/**\n\t * Set the node identity to use for signing changesets.\n\t * @param nodeId The identity of the node that is performing the update.\n\t */\n\tpublic setNodeId(nodeId: string): void {\n\t\tthis._nodeId = nodeId;\n\t}\n\n\t/**\n\t * Start the remote sync state helper.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tawait this._eventBusComponent.subscribe<ISyncBatchResponse>(\n\t\t\tSynchronisedStorageTopics.BatchResponse,\n\t\t\tasync response => {\n\t\t\t\tawait this.handleBatchResponse(response.data);\n\t\t\t}\n\t\t);\n\n\t\tawait this._eventBusComponent.subscribe<ISyncItemResponse>(\n\t\t\tSynchronisedStorageTopics.LocalItemResponse,\n\t\t\tasync response => {\n\t\t\t\tawait this.handleLocalItemResponse(response.data);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Set the synchronised storage key.\n\t * @param synchronisedStorageKey The synchronised storage key to use.\n\t */\n\tpublic setSynchronisedStorageKey(synchronisedStorageKey: string): void {\n\t\tthis._synchronisedStorageKey = synchronisedStorageKey;\n\t}\n\n\t/**\n\t * Build a changeset.\n\t * @param storageKey The storage key of the change set.\n\t * @param changes The changes to apply.\n\t * @param completeCallback The callback to call when the changeset is created and stored.\n\t * @returns The storage id of the change set if created.\n\t */\n\tpublic async buildChangeSet(\n\t\tstorageKey: string,\n\t\tchanges: ISyncChange[],\n\t\tcompleteCallback: (syncChangeSet?: ISyncChangeSet, id?: string) => Promise<void>\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"buildingChangeSet\",\n\t\t\tdata: {\n\t\t\t\tstorageKey,\n\t\t\t\tchangeCount: changes.length\n\t\t\t}\n\t\t});\n\n\t\tthis._populateFullChanges[storageKey] = {\n\t\t\tchanges,\n\t\t\tentities: {},\n\t\t\trequestIds: [],\n\t\t\tcompleteCallback: async () => this.finaliseFullChanges(storageKey, completeCallback)\n\t\t};\n\n\t\tconst setChanges = changes.filter(c => c.operation === SyncChangeOperation.Set);\n\t\tif (setChanges.length === 0) {\n\t\t\t// If we don't need to request any full details, we can just call the complete callback\n\t\t\tawait this.finaliseFullChanges(storageKey, completeCallback);\n\t\t} else {\n\t\t\t// Otherwise we need to request the full details for each change\n\t\t\tthis._populateFullChanges[storageKey].requestIds = setChanges.map(change => change.id);\n\n\t\t\t// Once all the requests are handled the callback will be called\n\t\t\tfor (const change of setChanges) {\n\t\t\t\t// Create a request for each change to populate the full details\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"createChangeSetRequestingItem\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait this._eventBusComponent.publish<ISyncItemResponse>(\n\t\t\t\t\tSynchronisedStorageTopics.LocalItemRequest,\n\t\t\t\t\t{\n\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Finalise the full details for the sync change set.\n\t * @param storageKey The storage key of the change set.\n\t * @param completeCallback The callback to call when the changeset is populated.\n\t * @returns Nothing.\n\t */\n\tpublic async finaliseFullChanges(\n\t\tstorageKey: string,\n\t\tcompleteCallback: (syncChangeSet?: ISyncChangeSet, id?: string) => Promise<void>\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"finalisingSyncChanges\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tconst changes = this._populateFullChanges[storageKey].changes;\n\t\t\tfor (const change of changes) {\n\t\t\t\tchange.entity = this._populateFullChanges[storageKey].entities[change.id] ?? change.entity;\n\n\t\t\t\tif (change.operation === SyncChangeOperation.Set && Is.objectValue(change.entity)) {\n\t\t\t\t\t// Remove the id from the entity as this is stored in the operation\n\t\t\t\t\t// and will be reinstated when the changeset is reconstituted\n\t\t\t\t\tObjectHelper.propertyDelete(change.entity, \"id\");\n\t\t\t\t\t// Remove the node identity as the changeset has this stored at the top level\n\t\t\t\t\t// and we do not want to store it in the change itself to reduce redundancy\n\t\t\t\t\tObjectHelper.propertyDelete(change.entity, \"nodeIdentity\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst now = new Date(Date.now()).toISOString();\n\t\t\tconst syncChangeSet: ISyncChangeSet = {\n\t\t\t\t\"@context\": SynchronisedStorageContexts.Context,\n\t\t\t\ttype: SynchronisedStorageTypes.ChangeSet,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tstorageKey,\n\t\t\t\tchanges,\n\t\t\t\tnodeIdentity: this._nodeId\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// If this is a trusted node, we also store the changeset\n\t\t\t\tlet changeSetStorageId;\n\t\t\t\tif (this._isTrustedNode) {\n\t\t\t\t\tchangeSetStorageId = await this._changeSetHelper.storeChangeSet(syncChangeSet);\n\t\t\t\t}\n\n\t\t\t\tawait completeCallback(syncChangeSet, changeSetStorageId);\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"finalisingSyncChangesFailed\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey\n\t\t\t\t\t},\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t\tawait completeCallback();\n\t\t\t}\n\t\t} else {\n\t\t\tawait completeCallback();\n\t\t}\n\t}\n\n\t/**\n\t * Add a new changeset into the sync state.\n\t * @param storageKey The storage key of the change set to add.\n\t * @param changeSetStorageId The id of the change set to add the current state\n\t * @returns Nothing.\n\t */\n\tpublic async addChangeSetToSyncState(\n\t\tstorageKey: string,\n\t\tchangeSetStorageId: string\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"addChangeSetToSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey,\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\n\t\t// First load the sync pointer store to get the current sync pointer for the storage key\n\t\tconst syncPointerStore = await this.getVerifiableSyncPointerStore();\n\n\t\tlet syncState: ISyncState | undefined;\n\t\tif (!Is.empty(syncPointerStore.syncPointers[storageKey])) {\n\t\t\tsyncState = await this.getSyncState(syncPointerStore.syncPointers[storageKey]);\n\t\t}\n\n\t\t// No current sync state, so we create a new one\n\t\tif (Is.empty(syncState)) {\n\t\t\tsyncState = { version: SYNC_STATE_VERSION, storageKey, snapshots: [] };\n\t\t}\n\n\t\t// Sort the snapshots so the newest snapshot is last in the array\n\t\tconst sortedSnapshots = syncState.snapshots.sort((a, b) =>\n\t\t\ta.dateCreated.localeCompare(b.dateCreated)\n\t\t);\n\n\t\t// Get the current snapshot, if it does not exist we create a new one\n\t\tlet currentSnapshot: ISyncSnapshot | undefined = sortedSnapshots[sortedSnapshots.length - 1];\n\t\tconst currentEpoch = currentSnapshot?.epoch ?? 0;\n\t\tconst now = new Date(Date.now()).toISOString();\n\n\t\t// If there is no snapshot or the current one is a consolidation\n\t\t// we start a new snapshot\n\t\tif (Is.empty(currentSnapshot) || currentSnapshot.isConsolidated) {\n\t\t\tcurrentSnapshot = {\n\t\t\t\tversion: SYNC_SNAPSHOT_VERSION,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tisConsolidated: false,\n\t\t\t\tepoch: currentEpoch + 1,\n\t\t\t\tchangeSetStorageIds: []\n\t\t\t};\n\t\t\tsyncState.snapshots.push(currentSnapshot);\n\t\t} else {\n\t\t\t// Snapshot exists, we update the dateModified\n\t\t\tcurrentSnapshot.dateModified = now;\n\t\t}\n\n\t\t// Add the changeset storage id to the current snapshot\n\t\tcurrentSnapshot.changeSetStorageIds.push(changeSetStorageId);\n\n\t\t// Store the sync state in the blob storage\n\t\tsyncPointerStore.syncPointers[storageKey] = await this.storeRemoteSyncState(syncState);\n\n\t\t// Store the verifiable sync pointer store in the verifiable storage\n\t\tawait this.storeVerifiableSyncPointerStore(syncPointerStore);\n\t}\n\n\t/**\n\t * Create a consolidated snapshot for the entire storage.\n\t * @param storageKey The storage key of the snapshot to create.\n\t * @param batchSize The batch size to use for consolidation.\n\t * @returns Nothing.\n\t */\n\tpublic async consolidationStart(storageKey: string, batchSize: number): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"consolidationStarting\"\n\t\t});\n\n\t\t// Perform a batch request to start the consolidation\n\t\tawait this._eventBusComponent.publish<ISyncBatchRequest>(\n\t\t\tSynchronisedStorageTopics.BatchRequest,\n\t\t\t{ storageKey, batchSize, requestMode: SyncNodeIdMode.All }\n\t\t);\n\t}\n\n\t/**\n\t * Get the sync pointer store.\n\t * @returns The sync pointer store.\n\t */\n\tpublic async getVerifiableSyncPointerStore(): Promise<ISyncPointerStore> {\n\t\tif (Is.stringValue(this._synchronisedStorageKey)) {\n\t\t\ttry {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"verifiableSyncPointerStoreRetrieving\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconst syncPointerStore = await this._verifiableSyncPointerStorageConnector.get(\n\t\t\t\t\tthis._synchronisedStorageKey,\n\t\t\t\t\t{ includeData: true }\n\t\t\t\t);\n\t\t\t\tif (Is.uint8Array(syncPointerStore.data)) {\n\t\t\t\t\tconst syncPointer = ObjectHelper.fromBytes<ISyncPointerStore>(syncPointerStore.data);\n\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\t\tmessage: \"verifiableSyncPointerStoreRetrieved\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\treturn syncPointer;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tif (!BaseError.someErrorName(err, NotFoundError.CLASS_NAME)) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"verifiableSyncPointerStoreNotFound\",\n\t\t\t\tdata: {\n\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// If no sync pointer store exists, we return an empty one\n\t\treturn {\n\t\t\tversion: SYNC_POINTER_STORE_VERSION,\n\t\t\tsyncPointers: {}\n\t\t};\n\t}\n\n\t/**\n\t * Store the verifiable sync pointer in the verifiable storage.\n\t * @param syncPointerStore The sync pointer store to store.\n\t * @returns Nothing.\n\t */\n\tpublic async storeVerifiableSyncPointerStore(syncPointerStore: ISyncPointerStore): Promise<void> {\n\t\tif (Is.stringValue(this._nodeId) && Is.stringValue(this._synchronisedStorageKey)) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"verifiableSyncPointerStoreStoring\",\n\t\t\t\tdata: {\n\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Store the verifiable sync pointer in the verifiable storage\n\t\t\tawait this._verifiableSyncPointerStorageConnector.update(\n\t\t\t\tthis._nodeId,\n\t\t\t\tthis._synchronisedStorageKey,\n\t\t\t\tObjectHelper.toBytes<ISyncPointerStore>(syncPointerStore)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Store the remote sync state.\n\t * @param syncState The sync state to store.\n\t * @returns The id of the sync state.\n\t */\n\tpublic async storeRemoteSyncState(syncState: ISyncState): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"syncStateStoring\",\n\t\t\tdata: {\n\t\t\t\tsnapshotCount: syncState.snapshots.length\n\t\t\t}\n\t\t});\n\n\t\t// Limits the number of consolidations in the list so that we can shrink decentralised\n\t\t// storage requirements, sort from newest to oldest so that we can easily find the\n\t\t// oldest snapshots to remove.\n\t\tconst snapshots = syncState.snapshots.sort(\n\t\t\t(a, b) => new Date(a.dateCreated).getTime() - new Date(b.dateCreated).getTime()\n\t\t);\n\n\t\t// Find all the consolidation indexes\n\t\tconst consolidationIndexes = [];\n\t\tfor (let i = 0; i < snapshots.length; i++) {\n\t\t\tconst snapshot = snapshots[i];\n\t\t\tif (snapshot.isConsolidated) {\n\t\t\t\tconsolidationIndexes.push(i);\n\t\t\t}\n\t\t}\n\n\t\tif (consolidationIndexes.length > this._maxConsolidations) {\n\t\t\t// Once we have reached the max for consolidations we need to remove\n\t\t\t// all the snapshots, including non consolidated ones, beyond this point\n\t\t\tconst toRemove = snapshots.slice(consolidationIndexes[this._maxConsolidations - 1] + 1);\n\n\t\t\tsyncState.snapshots = snapshots.slice(\n\t\t\t\t0,\n\t\t\t\tconsolidationIndexes[this._maxConsolidations - 1] + 1\n\t\t\t);\n\n\t\t\tfor (const snapshot of toRemove) {\n\t\t\t\t// We need to remove all the storage ids associated with the snapshot\n\t\t\t\tif (Is.arrayValue(snapshot.changeSetStorageIds)) {\n\t\t\t\t\tfor (const storageId of snapshot.changeSetStorageIds) {\n\t\t\t\t\t\tawait this._blobStorageHelper.removeBlob(storageId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._blobStorageHelper.saveBlob(syncState);\n\t}\n\n\t/**\n\t * Get the remote sync state.\n\t * @param syncPointerId The id of the sync pointer to retrieve the state for.\n\t * @returns The remote sync state.\n\t */\n\tpublic async getSyncState(syncPointerId: string): Promise<ISyncState | undefined> {\n\t\ttry {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"syncStateRetrieving\",\n\t\t\t\tdata: {\n\t\t\t\t\tsyncPointerId\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst syncState = await this._blobStorageHelper.loadBlob<ISyncState>(syncPointerId);\n\n\t\t\tif (Is.object(syncState)) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"syncStateRetrieved\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tsyncPointerId,\n\t\t\t\t\t\tsnapshotCount: syncState.snapshots.length\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn syncState;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"getSyncStateError\",\n\t\t\t\tdata: {\n\t\t\t\t\tsyncPointerId\n\t\t\t\t},\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"syncStateNotFound\",\n\t\t\tdata: {\n\t\t\t\tsyncPointerId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Handle the batch response which is triggered from a consolidation request.\n\t * @param response The batch response to handle.\n\t */\n\tprivate async handleBatchResponse(response: ISyncBatchResponse): Promise<void> {\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tconst now = new Date(Date.now()).toISOString();\n\n\t\t\t// Create a new snapshot entry for the current batch\n\t\t\tconst syncChangeSet: ISyncChangeSet = {\n\t\t\t\t\"@context\": SynchronisedStorageContexts.Context,\n\t\t\t\ttype: SynchronisedStorageTypes.ChangeSet,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tchanges: response.entities.map(change => ({\n\t\t\t\t\toperation: SyncChangeOperation.Set,\n\t\t\t\t\tid: change.id\n\t\t\t\t})),\n\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\tnodeIdentity: this._nodeId\n\t\t\t};\n\n\t\t\t// Store the changeset in the blob storage\n\t\t\tconst changeSetStorageId = await this._changeSetHelper.storeChangeSet(syncChangeSet);\n\n\t\t\t// Add the changeset storage id to the snapshot ids\n\t\t\tthis._batchResponseStorageIds[response.storageKey] ??= [];\n\t\t\tthis._batchResponseStorageIds[response.storageKey].push(changeSetStorageId);\n\n\t\t\t// If this is the last entry in the batch response, we can create the consolidated snapshot\n\t\t\tif (response.lastEntry) {\n\t\t\t\t// Get the current sync pointer store\n\t\t\t\tconst syncPointerStore = await this.getVerifiableSyncPointerStore();\n\n\t\t\t\tlet syncState: ISyncState | undefined;\n\n\t\t\t\tif (Is.stringValue(syncPointerStore.syncPointers[response.storageKey])) {\n\t\t\t\t\t// If the sync pointer exists, we load the current sync state\n\t\t\t\t\tsyncState = await this.getSyncState(syncPointerStore.syncPointers[response.storageKey]);\n\t\t\t\t}\n\n\t\t\t\t// If the sync state does not exist, we create a new one\n\t\t\t\tsyncState ??= {\n\t\t\t\t\tversion: SYNC_STATE_VERSION,\n\t\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\t\tsnapshots: []\n\t\t\t\t};\n\n\t\t\t\t// Sort the snapshots so the newest snapshot is last in the array\n\t\t\t\tconst sortedSnapshots = syncState.snapshots.sort((a, b) =>\n\t\t\t\t\ta.dateCreated.localeCompare(b.dateCreated)\n\t\t\t\t);\n\t\t\t\tconst currentSnapshot: ISyncSnapshot | undefined =\n\t\t\t\t\tsortedSnapshots[sortedSnapshots.length - 1];\n\t\t\t\tconst currentEpoch = currentSnapshot?.epoch ?? 0;\n\n\t\t\t\tconst batchSnapshot: ISyncSnapshot = {\n\t\t\t\t\tversion: SYNC_SNAPSHOT_VERSION,\n\t\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\t\tdateCreated: now,\n\t\t\t\t\tdateModified: now,\n\t\t\t\t\tisConsolidated: true,\n\t\t\t\t\tepoch: currentEpoch + 1,\n\t\t\t\t\tchangeSetStorageIds: this._batchResponseStorageIds[response.storageKey]\n\t\t\t\t};\n\t\t\t\tsyncState.snapshots.push(batchSnapshot);\n\n\t\t\t\t// Store the updated sync state\n\t\t\t\tconst syncStateId = await this.storeRemoteSyncState(syncState);\n\n\t\t\t\tsyncPointerStore.syncPointers[response.storageKey] = syncStateId;\n\n\t\t\t\t// Store the verifiable sync pointer in the verifiable storage\n\t\t\t\tawait this.storeVerifiableSyncPointerStore(syncPointerStore);\n\n\t\t\t\t// Remove the batch response storage ids for the storage key\n\t\t\t\t// as we have consolidated the changes\n\t\t\t\tdelete this._batchResponseStorageIds[response.storageKey];\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"consolidationCompleted\"\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handle the item response.\n\t * @param response The item response to handle.\n\t */\n\tprivate async handleLocalItemResponse(response: ISyncItemResponse): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"createChangeSetRespondingItem\",\n\t\t\tdata: {\n\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\tid: response.id\n\t\t\t}\n\t\t});\n\t\t// We have received a response to an item request, find the right storage\n\t\t// for the request id\n\t\tif (!Is.empty(this._populateFullChanges[response.storageKey])) {\n\t\t\tconst idx = this._populateFullChanges[response.storageKey].requestIds.indexOf(response.id);\n\n\t\t\tif (idx !== -1) {\n\t\t\t\tthis._populateFullChanges[response.storageKey].requestIds.splice(idx, 1);\n\t\t\t\tthis._populateFullChanges[response.storageKey].entities[response.id] = response.entity;\n\n\t\t\t\t// If there are no request ids remaining we can complete the population\n\t\t\t\tif (this._populateFullChanges[response.storageKey].requestIds.length === 0) {\n\t\t\t\t\tawait this._populateFullChanges[response.storageKey].completeCallback();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"remoteSyncStateHelper.js","sourceRoot":"","sources":["../../../src/helpers/remoteSyncStateHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tBaseError,\n\tConverter,\n\tIs,\n\tNotFoundError,\n\tObjectHelper,\n\tRandomHelper\n} from \"@twin.org/core\";\nimport type { IEventBusComponent } from \"@twin.org/event-bus-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\ttype ISyncBatchRequest,\n\ttype ISyncBatchResponse,\n\ttype ISyncChange,\n\ttype ISyncChangeSet,\n\ttype ISyncItemResponse,\n\tSyncNodeIdMode,\n\tSyncChangeOperation,\n\tSynchronisedStorageTopics,\n\tSynchronisedStorageContexts,\n\tSynchronisedStorageTypes,\n\ttype ISynchronisedEntity\n} from \"@twin.org/synchronised-storage-models\";\nimport type { IVerifiableStorageConnector } from \"@twin.org/verifiable-storage-models\";\nimport type { BlobStorageHelper } from \"./blobStorageHelper.js\";\nimport type { ChangeSetHelper } from \"./changeSetHelper.js\";\nimport {\n\tSYNC_POINTER_STORE_VERSION,\n\tSYNC_SNAPSHOT_VERSION,\n\tSYNC_STATE_VERSION\n} from \"./versions.js\";\nimport type { ISyncPointerStore } from \"../models/ISyncPointerStore.js\";\nimport type { ISyncSnapshot } from \"../models/ISyncSnapshot.js\";\nimport type { ISyncState } from \"../models/ISyncState.js\";\n\n/**\n * Class for performing entity storage operations in decentralised storage.\n */\nexport class RemoteSyncStateHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<RemoteSyncStateHelper>();\n\n\t/**\n\t * The logging component to use for logging.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The event bus component.\n\t * @internal\n\t */\n\tprivate readonly _eventBusComponent: IEventBusComponent;\n\n\t/**\n\t * The blob storage helper.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\n\n\t/**\n\t * The verifiable storage connector to use for storing sync pointers.\n\t * @internal\n\t */\n\tprivate readonly _verifiableSyncPointerStorageConnector: IVerifiableStorageConnector;\n\n\t/**\n\t * The change set helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _changeSetHelper: ChangeSetHelper;\n\n\t/**\n\t * The storage ids of the batch responses for each storage key.\n\t * @internal\n\t */\n\tprivate readonly _batchResponseStorageIds: { [storageKey: string]: string[] };\n\n\t/**\n\t * The full changes for each storage key.\n\t * @internal\n\t */\n\tprivate readonly _populateFullChanges: {\n\t\t[storageKey: string]: {\n\t\t\tchanges: ISyncChange[];\n\t\t\tentities: { [id: string]: ISynchronisedEntity | undefined };\n\t\t\trequestIds: string[];\n\t\t\tcompleteCallback: (id?: string) => Promise<void>;\n\t\t};\n\t};\n\n\t/**\n\t * The synchronised storage key to use for verified storage operations.\n\t * @internal\n\t */\n\tprivate _synchronisedStorageKey?: string;\n\n\t/**\n\t * The identity of the node that is performing the update.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Whether the node is trusted or not.\n\t * @internal\n\t */\n\tprivate readonly _isTrustedNode: boolean;\n\n\t/**\n\t * Maximum number of consolidations to keep in storage.\n\t * @internal\n\t */\n\tprivate readonly _maxConsolidations: number;\n\n\t/**\n\t * Create a new instance of RemoteSyncStateHelper.\n\t * @param loggingComponent The logging component to use for logging.\n\t * @param eventBusComponent The event bus component to use for events.\n\t * @param verifiableSyncPointerStorageConnector The verifiable storage connector to use for storing sync pointers.\n\t * @param blobStorageHelper The blob storage helper to use for remote sync states.\n\t * @param changeSetHelper The change set helper to use for managing changesets.\n\t * @param isTrustedNode Whether the node is trusted or not.\n\t * @param maxConsolidations The maximum number of consolidations to keep in storage.\n\t */\n\tconstructor(\n\t\tloggingComponent: ILoggingComponent | undefined,\n\t\teventBusComponent: IEventBusComponent,\n\t\tverifiableSyncPointerStorageConnector: IVerifiableStorageConnector,\n\t\tblobStorageHelper: BlobStorageHelper,\n\t\tchangeSetHelper: ChangeSetHelper,\n\t\tisTrustedNode: boolean,\n\t\tmaxConsolidations: number\n\t) {\n\t\tthis._logging = loggingComponent;\n\t\tthis._eventBusComponent = eventBusComponent;\n\t\tthis._verifiableSyncPointerStorageConnector = verifiableSyncPointerStorageConnector;\n\t\tthis._changeSetHelper = changeSetHelper;\n\t\tthis._blobStorageHelper = blobStorageHelper;\n\t\tthis._isTrustedNode = isTrustedNode;\n\t\tthis._maxConsolidations = maxConsolidations;\n\n\t\tthis._batchResponseStorageIds = {};\n\t\tthis._populateFullChanges = {};\n\t}\n\n\t/**\n\t * Set the node identity to use for signing changesets.\n\t * @param nodeId The identity of the node that is performing the update.\n\t */\n\tpublic setNodeId(nodeId: string): void {\n\t\tthis._nodeId = nodeId;\n\t}\n\n\t/**\n\t * Start the remote sync state helper.\n\t * @returns A promise that resolves when all event bus subscriptions are registered.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tawait this._eventBusComponent.subscribe<ISyncBatchResponse>(\n\t\t\tSynchronisedStorageTopics.BatchResponse,\n\t\t\tasync response => {\n\t\t\t\tawait this.handleBatchResponse(response.data);\n\t\t\t}\n\t\t);\n\n\t\tawait this._eventBusComponent.subscribe<ISyncItemResponse>(\n\t\t\tSynchronisedStorageTopics.LocalItemResponse,\n\t\t\tasync response => {\n\t\t\t\tawait this.handleLocalItemResponse(response.data);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Set the synchronised storage key.\n\t * @param synchronisedStorageKey The synchronised storage key to use.\n\t */\n\tpublic setSynchronisedStorageKey(synchronisedStorageKey: string): void {\n\t\tthis._synchronisedStorageKey = synchronisedStorageKey;\n\t}\n\n\t/**\n\t * Build a changeset and invoke the callback when complete.\n\t * @param storageKey The storage key of the change set.\n\t * @param changes The changes to apply.\n\t * @param completeCallback The callback invoked when the changeset is created and stored.\n\t * @returns A promise that resolves when item requests are dispatched or the changeset is finalised immediately.\n\t */\n\tpublic async buildChangeSet(\n\t\tstorageKey: string,\n\t\tchanges: ISyncChange[],\n\t\tcompleteCallback: (syncChangeSet?: ISyncChangeSet, id?: string) => Promise<void>\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"buildingChangeSet\",\n\t\t\tdata: {\n\t\t\t\tstorageKey,\n\t\t\t\tchangeCount: changes.length\n\t\t\t}\n\t\t});\n\n\t\tthis._populateFullChanges[storageKey] = {\n\t\t\tchanges,\n\t\t\tentities: {},\n\t\t\trequestIds: [],\n\t\t\tcompleteCallback: async () => this.finaliseFullChanges(storageKey, completeCallback)\n\t\t};\n\n\t\tconst setChanges = changes.filter(c => c.operation === SyncChangeOperation.Set);\n\t\tif (setChanges.length === 0) {\n\t\t\t// If we don't need to request any full details, we can just call the complete callback\n\t\t\tawait this.finaliseFullChanges(storageKey, completeCallback);\n\t\t} else {\n\t\t\t// Otherwise we need to request the full details for each change\n\t\t\tthis._populateFullChanges[storageKey].requestIds = setChanges.map(change => change.id);\n\n\t\t\t// Once all the requests are handled the callback will be called\n\t\t\tfor (const change of setChanges) {\n\t\t\t\t// Create a request for each change to populate the full details\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"createChangeSetRequestingItem\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait this._eventBusComponent.publish<ISyncItemResponse>(\n\t\t\t\t\tSynchronisedStorageTopics.LocalItemRequest,\n\t\t\t\t\t{\n\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Finalise the full details for the sync change set.\n\t * @param storageKey The storage key of the change set.\n\t * @param completeCallback The callback invoked when the changeset is populated and optionally stored.\n\t * @returns A promise that resolves when the changeset is built and the callback is invoked.\n\t */\n\tpublic async finaliseFullChanges(\n\t\tstorageKey: string,\n\t\tcompleteCallback: (syncChangeSet?: ISyncChangeSet, id?: string) => Promise<void>\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"finalisingSyncChanges\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tconst changes = this._populateFullChanges[storageKey].changes;\n\t\t\tfor (const change of changes) {\n\t\t\t\tchange.entity = this._populateFullChanges[storageKey].entities[change.id] ?? change.entity;\n\n\t\t\t\tif (change.operation === SyncChangeOperation.Set && Is.objectValue(change.entity)) {\n\t\t\t\t\t// Remove the id from the entity as this is stored in the operation\n\t\t\t\t\t// and will be reinstated when the changeset is reconstituted\n\t\t\t\t\tObjectHelper.propertyDelete(change.entity, \"id\");\n\t\t\t\t\t// Remove the node identity as the changeset has this stored at the top level\n\t\t\t\t\t// and we do not want to store it in the change itself to reduce redundancy\n\t\t\t\t\tObjectHelper.propertyDelete(change.entity, \"nodeIdentity\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst now = new Date(Date.now()).toISOString();\n\t\t\tconst syncChangeSet: ISyncChangeSet = {\n\t\t\t\t\"@context\": SynchronisedStorageContexts.Context,\n\t\t\t\ttype: SynchronisedStorageTypes.ChangeSet,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tstorageKey,\n\t\t\t\tchanges,\n\t\t\t\tnodeIdentity: this._nodeId\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// If this is a trusted node, we also store the changeset\n\t\t\t\tlet changeSetStorageId;\n\t\t\t\tif (this._isTrustedNode) {\n\t\t\t\t\tchangeSetStorageId = await this._changeSetHelper.storeChangeSet(syncChangeSet);\n\t\t\t\t}\n\n\t\t\t\tawait completeCallback(syncChangeSet, changeSetStorageId);\n\t\t\t} catch (err) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"finalisingSyncChangesFailed\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey\n\t\t\t\t\t},\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t\tawait completeCallback();\n\t\t\t}\n\t\t} else {\n\t\t\tawait completeCallback();\n\t\t}\n\t}\n\n\t/**\n\t * Add a new changeset into the sync state.\n\t * @param storageKey The storage key of the change set to add.\n\t * @param changeSetStorageId The id of the change set to add.\n\t * @returns A promise that resolves when the sync state and verifiable sync pointer are updated.\n\t */\n\tpublic async addChangeSetToSyncState(\n\t\tstorageKey: string,\n\t\tchangeSetStorageId: string\n\t): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"addChangeSetToSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey,\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\n\t\t// First load the sync pointer store to get the current sync pointer for the storage key\n\t\tconst syncPointerStore = await this.getVerifiableSyncPointerStore();\n\n\t\tlet syncState: ISyncState | undefined;\n\t\tif (!Is.empty(syncPointerStore.syncPointers[storageKey])) {\n\t\t\tsyncState = await this.getSyncState(syncPointerStore.syncPointers[storageKey]);\n\t\t}\n\n\t\t// No current sync state, so we create a new one\n\t\tif (Is.empty(syncState)) {\n\t\t\tsyncState = { version: SYNC_STATE_VERSION, storageKey, snapshots: [] };\n\t\t}\n\n\t\t// Sort the snapshots so the newest snapshot is last in the array\n\t\tconst sortedSnapshots = syncState.snapshots.sort((a, b) =>\n\t\t\ta.dateCreated.localeCompare(b.dateCreated)\n\t\t);\n\n\t\t// Get the current snapshot, if it does not exist we create a new one\n\t\tlet currentSnapshot: ISyncSnapshot | undefined = sortedSnapshots[sortedSnapshots.length - 1];\n\t\tconst currentEpoch = currentSnapshot?.epoch ?? 0;\n\t\tconst now = new Date(Date.now()).toISOString();\n\n\t\t// If there is no snapshot or the current one is a consolidation\n\t\t// we start a new snapshot\n\t\tif (Is.empty(currentSnapshot) || currentSnapshot.isConsolidated) {\n\t\t\tcurrentSnapshot = {\n\t\t\t\tversion: SYNC_SNAPSHOT_VERSION,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tisConsolidated: false,\n\t\t\t\tepoch: currentEpoch + 1,\n\t\t\t\tchangeSetStorageIds: []\n\t\t\t};\n\t\t\tsyncState.snapshots.push(currentSnapshot);\n\t\t} else {\n\t\t\t// Snapshot exists, we update the dateModified\n\t\t\tcurrentSnapshot.dateModified = now;\n\t\t}\n\n\t\t// Add the changeset storage id to the current snapshot\n\t\tcurrentSnapshot.changeSetStorageIds.push(changeSetStorageId);\n\n\t\t// Store the sync state in the blob storage\n\t\tsyncPointerStore.syncPointers[storageKey] = await this.storeRemoteSyncState(syncState);\n\n\t\t// Store the verifiable sync pointer store in the verifiable storage\n\t\tawait this.storeVerifiableSyncPointerStore(syncPointerStore);\n\t}\n\n\t/**\n\t * Create a consolidated snapshot for the entire storage.\n\t * @param storageKey The storage key of the snapshot to create.\n\t * @param batchSize The batch size to use for consolidation.\n\t * @returns A promise that resolves when the batch request is published to the event bus.\n\t */\n\tpublic async consolidationStart(storageKey: string, batchSize: number): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"consolidationStarting\"\n\t\t});\n\n\t\t// Perform a batch request to start the consolidation\n\t\tawait this._eventBusComponent.publish<ISyncBatchRequest>(\n\t\t\tSynchronisedStorageTopics.BatchRequest,\n\t\t\t{ storageKey, batchSize, requestMode: SyncNodeIdMode.All }\n\t\t);\n\t}\n\n\t/**\n\t * Get the sync pointer store.\n\t * @returns The sync pointer store.\n\t */\n\tpublic async getVerifiableSyncPointerStore(): Promise<ISyncPointerStore> {\n\t\tif (Is.stringValue(this._synchronisedStorageKey)) {\n\t\t\ttry {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"verifiableSyncPointerStoreRetrieving\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconst syncPointerStore = await this._verifiableSyncPointerStorageConnector.get(\n\t\t\t\t\tthis._synchronisedStorageKey,\n\t\t\t\t\t{ includeData: true }\n\t\t\t\t);\n\t\t\t\tif (Is.uint8Array(syncPointerStore.data)) {\n\t\t\t\t\tconst syncPointer = ObjectHelper.fromBytes<ISyncPointerStore>(syncPointerStore.data);\n\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\t\tmessage: \"verifiableSyncPointerStoreRetrieved\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\treturn syncPointer;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tif (!BaseError.someErrorName(err, NotFoundError.CLASS_NAME)) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"verifiableSyncPointerStoreNotFound\",\n\t\t\t\tdata: {\n\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// If no sync pointer store exists, we return an empty one\n\t\treturn {\n\t\t\tversion: SYNC_POINTER_STORE_VERSION,\n\t\t\tsyncPointers: {}\n\t\t};\n\t}\n\n\t/**\n\t * Store the verifiable sync pointer in the verifiable storage.\n\t * @param syncPointerStore The sync pointer store to store.\n\t * @returns A promise that resolves when the pointer store is persisted to verifiable storage.\n\t */\n\tpublic async storeVerifiableSyncPointerStore(syncPointerStore: ISyncPointerStore): Promise<void> {\n\t\tif (Is.stringValue(this._nodeId) && Is.stringValue(this._synchronisedStorageKey)) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"verifiableSyncPointerStoreStoring\",\n\t\t\t\tdata: {\n\t\t\t\t\tkey: this._synchronisedStorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Store the verifiable sync pointer in the verifiable storage\n\t\t\tawait this._verifiableSyncPointerStorageConnector.update(\n\t\t\t\tthis._nodeId,\n\t\t\t\tthis._synchronisedStorageKey,\n\t\t\t\tObjectHelper.toBytes<ISyncPointerStore>(syncPointerStore)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Store the remote sync state.\n\t * @param syncState The sync state to store.\n\t * @returns The id of the sync state.\n\t */\n\tpublic async storeRemoteSyncState(syncState: ISyncState): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"syncStateStoring\",\n\t\t\tdata: {\n\t\t\t\tsnapshotCount: syncState.snapshots.length\n\t\t\t}\n\t\t});\n\n\t\t// Limits the number of consolidations in the list so that we can shrink decentralised\n\t\t// storage requirements, sort from newest to oldest so that we can easily find the\n\t\t// oldest snapshots to remove.\n\t\tconst snapshots = syncState.snapshots.sort(\n\t\t\t(a, b) => new Date(a.dateCreated).getTime() - new Date(b.dateCreated).getTime()\n\t\t);\n\n\t\t// Find all the consolidation indexes\n\t\tconst consolidationIndexes = [];\n\t\tfor (let i = 0; i < snapshots.length; i++) {\n\t\t\tconst snapshot = snapshots[i];\n\t\t\tif (snapshot.isConsolidated) {\n\t\t\t\tconsolidationIndexes.push(i);\n\t\t\t}\n\t\t}\n\n\t\tif (consolidationIndexes.length > this._maxConsolidations) {\n\t\t\t// Once we have reached the max for consolidations we need to remove\n\t\t\t// all the snapshots, including non consolidated ones, beyond this point\n\t\t\tconst toRemove = snapshots.slice(consolidationIndexes[this._maxConsolidations - 1] + 1);\n\n\t\t\tsyncState.snapshots = snapshots.slice(\n\t\t\t\t0,\n\t\t\t\tconsolidationIndexes[this._maxConsolidations - 1] + 1\n\t\t\t);\n\n\t\t\tfor (const snapshot of toRemove) {\n\t\t\t\t// We need to remove all the storage ids associated with the snapshot\n\t\t\t\tif (Is.arrayValue(snapshot.changeSetStorageIds)) {\n\t\t\t\t\tfor (const storageId of snapshot.changeSetStorageIds) {\n\t\t\t\t\t\tawait this._blobStorageHelper.removeBlob(storageId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._blobStorageHelper.saveBlob(syncState);\n\t}\n\n\t/**\n\t * Get the remote sync state.\n\t * @param syncPointerId The id of the sync pointer to retrieve the state for.\n\t * @returns The remote sync state.\n\t */\n\tpublic async getSyncState(syncPointerId: string): Promise<ISyncState | undefined> {\n\t\ttry {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"syncStateRetrieving\",\n\t\t\t\tdata: {\n\t\t\t\t\tsyncPointerId\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst syncState = await this._blobStorageHelper.loadBlob<ISyncState>(syncPointerId);\n\n\t\t\tif (Is.object(syncState)) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"syncStateRetrieved\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tsyncPointerId,\n\t\t\t\t\t\tsnapshotCount: syncState.snapshots.length\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn syncState;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\tmessage: \"getSyncStateError\",\n\t\t\t\tdata: {\n\t\t\t\t\tsyncPointerId\n\t\t\t\t},\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"syncStateNotFound\",\n\t\t\tdata: {\n\t\t\t\tsyncPointerId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Handle the batch response which is triggered from a consolidation request.\n\t * @param response The batch response to handle.\n\t * @returns A promise that resolves when the batch is processed and, if it is the last entry, the consolidated snapshot is stored.\n\t * @internal\n\t */\n\tprivate async handleBatchResponse(response: ISyncBatchResponse): Promise<void> {\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tconst now = new Date(Date.now()).toISOString();\n\n\t\t\t// Create a new snapshot entry for the current batch\n\t\t\tconst syncChangeSet: ISyncChangeSet = {\n\t\t\t\t\"@context\": SynchronisedStorageContexts.Context,\n\t\t\t\ttype: SynchronisedStorageTypes.ChangeSet,\n\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\tdateCreated: now,\n\t\t\t\tdateModified: now,\n\t\t\t\tchanges: response.entities.map(change => ({\n\t\t\t\t\toperation: SyncChangeOperation.Set,\n\t\t\t\t\tid: change.id\n\t\t\t\t})),\n\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\tnodeIdentity: this._nodeId\n\t\t\t};\n\n\t\t\t// Store the changeset in the blob storage\n\t\t\tconst changeSetStorageId = await this._changeSetHelper.storeChangeSet(syncChangeSet);\n\n\t\t\t// Add the changeset storage id to the snapshot ids\n\t\t\tthis._batchResponseStorageIds[response.storageKey] ??= [];\n\t\t\tthis._batchResponseStorageIds[response.storageKey].push(changeSetStorageId);\n\n\t\t\t// If this is the last entry in the batch response, we can create the consolidated snapshot\n\t\t\tif (response.lastEntry) {\n\t\t\t\t// Get the current sync pointer store\n\t\t\t\tconst syncPointerStore = await this.getVerifiableSyncPointerStore();\n\n\t\t\t\tlet syncState: ISyncState | undefined;\n\n\t\t\t\tif (Is.stringValue(syncPointerStore.syncPointers[response.storageKey])) {\n\t\t\t\t\t// If the sync pointer exists, we load the current sync state\n\t\t\t\t\tsyncState = await this.getSyncState(syncPointerStore.syncPointers[response.storageKey]);\n\t\t\t\t}\n\n\t\t\t\t// If the sync state does not exist, we create a new one\n\t\t\t\tsyncState ??= {\n\t\t\t\t\tversion: SYNC_STATE_VERSION,\n\t\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\t\tsnapshots: []\n\t\t\t\t};\n\n\t\t\t\t// Sort the snapshots so the newest snapshot is last in the array\n\t\t\t\tconst sortedSnapshots = syncState.snapshots.sort((a, b) =>\n\t\t\t\t\ta.dateCreated.localeCompare(b.dateCreated)\n\t\t\t\t);\n\t\t\t\tconst currentSnapshot: ISyncSnapshot | undefined =\n\t\t\t\t\tsortedSnapshots[sortedSnapshots.length - 1];\n\t\t\t\tconst currentEpoch = currentSnapshot?.epoch ?? 0;\n\n\t\t\t\tconst batchSnapshot: ISyncSnapshot = {\n\t\t\t\t\tversion: SYNC_SNAPSHOT_VERSION,\n\t\t\t\t\tid: Converter.bytesToHex(RandomHelper.generate(32)),\n\t\t\t\t\tdateCreated: now,\n\t\t\t\t\tdateModified: now,\n\t\t\t\t\tisConsolidated: true,\n\t\t\t\t\tepoch: currentEpoch + 1,\n\t\t\t\t\tchangeSetStorageIds: this._batchResponseStorageIds[response.storageKey]\n\t\t\t\t};\n\t\t\t\tsyncState.snapshots.push(batchSnapshot);\n\n\t\t\t\t// Store the updated sync state\n\t\t\t\tconst syncStateId = await this.storeRemoteSyncState(syncState);\n\n\t\t\t\tsyncPointerStore.syncPointers[response.storageKey] = syncStateId;\n\n\t\t\t\t// Store the verifiable sync pointer in the verifiable storage\n\t\t\t\tawait this.storeVerifiableSyncPointerStore(syncPointerStore);\n\n\t\t\t\t// Remove the batch response storage ids for the storage key\n\t\t\t\t// as we have consolidated the changes\n\t\t\t\tdelete this._batchResponseStorageIds[response.storageKey];\n\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"consolidationCompleted\"\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handle the item response.\n\t * @param response The item response to handle.\n\t * @returns A promise that resolves when the entity is recorded and the complete callback is invoked if all requests are fulfilled.\n\t * @internal\n\t */\n\tprivate async handleLocalItemResponse(response: ISyncItemResponse): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: RemoteSyncStateHelper.CLASS_NAME,\n\t\t\tmessage: \"createChangeSetRespondingItem\",\n\t\t\tdata: {\n\t\t\t\tstorageKey: response.storageKey,\n\t\t\t\tid: response.id\n\t\t\t}\n\t\t});\n\t\t// We have received a response to an item request, find the right storage\n\t\t// for the request id\n\t\tif (!Is.empty(this._populateFullChanges[response.storageKey])) {\n\t\t\tconst idx = this._populateFullChanges[response.storageKey].requestIds.indexOf(response.id);\n\n\t\t\tif (idx !== -1) {\n\t\t\t\tthis._populateFullChanges[response.storageKey].requestIds.splice(idx, 1);\n\t\t\t\tthis._populateFullChanges[response.storageKey].entities[response.id] = response.entity;\n\n\t\t\t\t// If there are no request ids remaining we can complete the population\n\t\t\t\tif (this._populateFullChanges[response.storageKey].requestIds.length === 0) {\n\t\t\t\t\tawait this._populateFullChanges[response.storageKey].completeCallback();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// Copyright 2024 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
/**
|
|
4
|
+
* Current schema version for sync state objects.
|
|
5
|
+
*/
|
|
3
6
|
export const SYNC_STATE_VERSION = "1";
|
|
7
|
+
/**
|
|
8
|
+
* Current schema version for sync pointer store objects.
|
|
9
|
+
*/
|
|
4
10
|
export const SYNC_POINTER_STORE_VERSION = "1";
|
|
11
|
+
/**
|
|
12
|
+
* Current schema version for sync snapshot entry objects.
|
|
13
|
+
*/
|
|
5
14
|
export const SYNC_SNAPSHOT_VERSION = "1";
|
|
6
15
|
//# sourceMappingURL=versions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/helpers/versions.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/helpers/versions.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAW,GAAG,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAW,GAAG,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAW,GAAG,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Current schema version for sync state objects.\n */\nexport const SYNC_STATE_VERSION: string = \"1\";\n\n/**\n * Current schema version for sync pointer store objects.\n */\nexport const SYNC_POINTER_STORE_VERSION: string = \"1\";\n\n/**\n * Current schema version for sync snapshot entry objects.\n */\nexport const SYNC_SNAPSHOT_VERSION: string = \"1\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,qCAAqC,EACrC,uBAAuB,EACvB,MAAM,gCAAgC,CAAC;AAExC,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,sBAAsB;QAC5B,gBAAgB,EAAE,sBAAsB;QACxC,IAAI,EAAE,uBAAuB;QAC7B,cAAc,EAAE,qCAAqC;KACrD;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport {\n\tgenerateRestRoutesSynchronisedStorage,\n\ttagsSynchronisedStorage\n} from \"./synchronisedStorageRoutes.js\";\n\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"synchronised-storage\",\n\t\tdefaultBaseRoute: \"synchronised-storage\",\n\t\ttags: tagsSynchronisedStorage,\n\t\tgenerateRoutes: generateRestRoutesSynchronisedStorage\n\t}\n];\n"]}
|
|
1
|
+
{"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,qCAAqC,EACrC,uBAAuB,EACvB,MAAM,gCAAgC,CAAC;AAExC;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,sBAAsB;QAC5B,gBAAgB,EAAE,sBAAsB;QACxC,IAAI,EAAE,uBAAuB;QAC7B,cAAc,EAAE,qCAAqC;KACrD;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport {\n\tgenerateRestRoutesSynchronisedStorage,\n\ttagsSynchronisedStorage\n} from \"./synchronisedStorageRoutes.js\";\n\n/**\n * REST entry points for the synchronised storage service.\n */\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"synchronised-storage\",\n\t\tdefaultBaseRoute: \"synchronised-storage\",\n\t\ttags: tagsSynchronisedStorage,\n\t\tgenerateRoutes: generateRestRoutesSynchronisedStorage\n\t}\n];\n"]}
|
|
@@ -64,7 +64,8 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
|
|
|
64
64
|
type: "INoContentResponse"
|
|
65
65
|
}
|
|
66
66
|
],
|
|
67
|
-
skipAuth: true
|
|
67
|
+
skipAuth: true,
|
|
68
|
+
skipTenant: true
|
|
68
69
|
};
|
|
69
70
|
const getDecryptionKeyRoute = {
|
|
70
71
|
operationId: "synchronisedStorageGetDecryptionKeyRequest",
|
|
@@ -100,7 +101,8 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
|
|
|
100
101
|
type: "IUnauthorizedResponse"
|
|
101
102
|
}
|
|
102
103
|
],
|
|
103
|
-
skipAuth: true
|
|
104
|
+
skipAuth: true,
|
|
105
|
+
skipTenant: true
|
|
104
106
|
};
|
|
105
107
|
return [syncChangeSetRoute, getDecryptionKeyRoute];
|
|
106
108
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synchronisedStorageRoutes.js","sourceRoot":"","sources":["../../src/synchronisedStorageRoutes.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EACN,2BAA2B,EAC3B,wBAAwB,EAKxB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE1E;;GAEG;AACH,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAElD;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAW;IAC9C;QACC,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,yEAAyE;KACtF;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,qCAAqC,CACpD,aAAqB,EACrB,aAAqB;IAErB,MAAM,kBAAkB,GAA0D;QACjF,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,+DAA+D;QACxE,GAAG,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI;QACpC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,GAAG,aAAa,iBAAiB;QACvC,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAC9C,uCAAuC,CAAC,kBAAkB,EAAE,aAAa,EAAE,OAAO,CAAC;QACpF,WAAW,EAAE;YACZ,IAAI,yBAAiC;YACrC,QAAQ,EAAE;gBACT;oBACC,EAAE,EAAE,gDAAgD;oBACpD,OAAO,EAAE;wBACR,OAAO,EAAE;4BACR,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,2BAA2B;yBACxD;wBACD,IAAI,EAAE;4BACL,UAAU,EAAE,2BAA2B,CAAC,OAAO;4BAC/C,IAAI,EAAE,wBAAwB,CAAC,SAAS;4BACxC,EAAE,EAAE,kEAAkE;4BACtE,WAAW,EAAE,0BAA0B;4BACvC,YAAY,EAAE,0BAA0B;4BACxC,YAAY,EACX,uFAAuF;4BACxF,OAAO,EAAE;gCACR;oCACC,MAAM,EAAE;wCACP,YAAY,EAAE,0BAA0B;qCACxC;oCACD,EAAE,EAAE,WAAW;oCACf,SAAS,EAAE,KAAK;iCAChB;6BACD;4BACD,UAAU,EAAE,WAAW;yBACvB;qBACD;iBACD;aACD;SACD;QACD,YAAY,EAAE;YACb;gBACC,IAAI,sBAA8B;aAClC;SACD;QACD,QAAQ,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"synchronisedStorageRoutes.js","sourceRoot":"","sources":["../../src/synchronisedStorageRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIHttpRequestContext,\n\tINoContentResponse,\n\tIRestRoute,\n\tITag,\n\tIUnauthorizedResponse\n} from \"@twin.org/api-models\";\nimport { ComponentFactory, Guards } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tSynchronisedStorageContexts,\n\tSynchronisedStorageTypes,\n\ttype ISyncChangeSetRequest,\n\ttype ISyncDecryptionKeyRequest,\n\ttype ISyncDecryptionKeyResponse,\n\ttype ISynchronisedStorageComponent\n} from \"@twin.org/synchronised-storage-models\";\nimport { HeaderHelper, HeaderTypes, HttpStatusCode } from \"@twin.org/web\";\n\n/**\n * The source used when communicating about these routes.\n */\nconst ROUTES_SOURCE = \"synchronisedStorageRoutes\";\n\n/**\n * The tag to associate with the routes.\n */\nexport const tagsSynchronisedStorage: ITag[] = [\n\t{\n\t\tname: \"Synchronised Storage\",\n\t\tdescription: \"Endpoints which are modelled to access a synchronised storage contract.\"\n\t}\n];\n\n/**\n * The REST routes for synchronised storage.\n * @param baseRouteName Prefix to prepend to the paths.\n * @param componentName The name of the component to use in the routes stored in the ComponentFactory.\n * @returns The generated routes.\n */\nexport function generateRestRoutesSynchronisedStorage(\n\tbaseRouteName: string,\n\tcomponentName: string\n): IRestRoute[] {\n\tconst syncChangeSetRoute: IRestRoute<ISyncChangeSetRequest, INoContentResponse> = {\n\t\toperationId: \"synchronisedStorageSyncChangeSetRequest\",\n\t\tsummary: \"Request that the node perform a sync request for a changeset.\",\n\t\ttag: tagsSynchronisedStorage[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/sync-changeset`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tsynchronisedStorageSyncChangeSetRequest(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<ISyncChangeSetRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"synchronisedStorageSyncChangeSetRequestExample\",\n\t\t\t\t\trequest: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t[HeaderTypes.Authorization]: \"z3V32BP9ShC...z3V32BP9ShC\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\"@context\": SynchronisedStorageContexts.Context,\n\t\t\t\t\t\t\ttype: SynchronisedStorageTypes.ChangeSet,\n\t\t\t\t\t\t\tid: \"0909090909090909090909090909090909090909090909090909090909090909\",\n\t\t\t\t\t\t\tdateCreated: \"2025-05-29T01:00:00.000Z\",\n\t\t\t\t\t\t\tdateModified: \"2025-05-29T01:00:00.000Z\",\n\t\t\t\t\t\t\tnodeIdentity:\n\t\t\t\t\t\t\t\t\"did:entity-storage:0xd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2\",\n\t\t\t\t\t\t\tchanges: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tentity: {\n\t\t\t\t\t\t\t\t\t\tdateModified: \"2025-01-01T00:00:00.000Z\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tid: \"test-id-1\",\n\t\t\t\t\t\t\t\t\toperation: \"set\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tstorageKey: \"test-type\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<INoContentResponse>()\n\t\t\t}\n\t\t],\n\t\tskipAuth: true,\n\t\tskipTenant: true\n\t};\n\n\tconst getDecryptionKeyRoute: IRestRoute<ISyncDecryptionKeyRequest, ISyncDecryptionKeyResponse> = {\n\t\toperationId: \"synchronisedStorageGetDecryptionKeyRequest\",\n\t\tsummary: \"Request the decryption key.\",\n\t\ttag: tagsSynchronisedStorage[0].name,\n\t\tmethod: \"POST\",\n\t\tpath: `${baseRouteName}/decryption-key`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tsynchronisedStorageGetDecryptionKeyRequest(httpRequestContext, componentName, request),\n\t\trequestType: {\n\t\t\ttype: nameof<ISyncChangeSetRequest>(),\n\t\t\texamples: [\n\t\t\t\t{\n\t\t\t\t\tid: \"synchronisedStorageSyncGetDecryptionKeyRequestExample\",\n\t\t\t\t\trequest: {}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<ISyncDecryptionKeyResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"synchronisedStorageSyncGetDecryptionKeyResponseExample\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tdecryptionKey:\n\t\t\t\t\t\t\t\t\t\"z5efBErQs3YBLZoH7jgKMQaRc9YjAxA5XSYKmW3FmTBDw9WionT2NS2x1SMvcRyBvw53cSSoaCT1xQH9tkWngGCX3\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: nameof<IUnauthorizedResponse>()\n\t\t\t}\n\t\t],\n\t\tskipAuth: true,\n\t\tskipTenant: true\n\t};\n\n\treturn [syncChangeSetRoute, getDecryptionKeyRoute];\n}\n\n/**\n * Perform the sync change set operation.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function synchronisedStorageSyncChangeSetRequest(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ISyncChangeSetRequest\n): Promise<INoContentResponse> {\n\tGuards.object<ISyncChangeSetRequest[\"headers\"]>(\n\t\tROUTES_SOURCE,\n\t\tnameof(request.headers),\n\t\trequest.headers\n\t);\n\tGuards.object<ISyncChangeSetRequest>(ROUTES_SOURCE, nameof(request), request);\n\tGuards.object<ISyncChangeSetRequest[\"body\"]>(ROUTES_SOURCE, nameof(request.body), request.body);\n\n\tconst component = ComponentFactory.get<ISynchronisedStorageComponent>(componentName);\n\tawait component.syncChangeSet(\n\t\trequest.body,\n\t\tHeaderHelper.extractBearer(request.headers?.[HeaderTypes.Authorization])\n\t);\n\treturn {\n\t\tstatusCode: HttpStatusCode.noContent\n\t};\n}\n\n/**\n * Request the decryption key.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function synchronisedStorageGetDecryptionKeyRequest(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: ISyncDecryptionKeyRequest\n): Promise<ISyncDecryptionKeyResponse> {\n\tGuards.object<ISyncChangeSetRequest[\"headers\"]>(\n\t\tROUTES_SOURCE,\n\t\tnameof(request.headers),\n\t\trequest.headers\n\t);\n\tGuards.object<ISyncDecryptionKeyRequest>(ROUTES_SOURCE, nameof(request), request);\n\n\tconst component = ComponentFactory.get<ISynchronisedStorageComponent>(componentName);\n\tconst key = await component.getDecryptionKey(\n\t\tHeaderHelper.extractBearer(request.headers?.[HeaderTypes.Authorization])\n\t);\n\treturn {\n\t\tbody: {\n\t\t\tdecryptionKey: key\n\t\t}\n\t};\n}\n"]}
|
|
@@ -138,7 +138,7 @@ export class SynchronisedStorageService {
|
|
|
138
138
|
Guards.object(SynchronisedStorageService.CLASS_NAME, "options.config", options.config);
|
|
139
139
|
Guards.stringValue(SynchronisedStorageService.CLASS_NAME, "options.config.verifiableStorageKeyId", options.config.verifiableStorageKeyId);
|
|
140
140
|
this._eventBusComponent = ComponentFactory.get(options.eventBusComponentType ?? "event-bus");
|
|
141
|
-
this._logging = ComponentFactory.getIfExists(options.loggingComponentType
|
|
141
|
+
this._logging = ComponentFactory.getIfExists(options.loggingComponentType);
|
|
142
142
|
this._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType ?? "vault");
|
|
143
143
|
this._localSyncSnapshotEntryEntityStorage = EntityStorageConnectorFactory.get(options.syncSnapshotStorageConnectorType ?? "sync-snapshot-entry");
|
|
144
144
|
this._verifiableSyncPointerStorageConnector = VerifiableStorageConnectorFactory.get(options.verifiableStorageConnectorType ?? "verifiable-storage");
|
|
@@ -185,7 +185,7 @@ export class SynchronisedStorageService {
|
|
|
185
185
|
/**
|
|
186
186
|
* The component needs to be started when the node is initialized.
|
|
187
187
|
* @param nodeLoggingComponentType The node logging component type.
|
|
188
|
-
* @returns
|
|
188
|
+
* @returns A promise that resolves when the service is started and all event bus subscriptions are active.
|
|
189
189
|
*/
|
|
190
190
|
async start(nodeLoggingComponentType) {
|
|
191
191
|
const contextIds = await ContextIdStore.getContextIds();
|
|
@@ -226,7 +226,7 @@ export class SynchronisedStorageService {
|
|
|
226
226
|
/**
|
|
227
227
|
* The component needs to be stopped when the node is closed.
|
|
228
228
|
* @param nodeLoggingComponentType The node logging component type.
|
|
229
|
-
* @returns
|
|
229
|
+
* @returns A promise that resolves when all scheduled tasks are removed and storage keys are deactivated.
|
|
230
230
|
*/
|
|
231
231
|
async stop(nodeLoggingComponentType) {
|
|
232
232
|
for (const storageKey in this._activeStorageKeys) {
|
|
@@ -265,7 +265,7 @@ export class SynchronisedStorageService {
|
|
|
265
265
|
* Synchronise a set of changes from an untrusted node, assumes this is a trusted node.
|
|
266
266
|
* @param syncChangeSet The change set to synchronise.
|
|
267
267
|
* @param trustPayload Trust payload to verify the requesters identity.
|
|
268
|
-
* @returns
|
|
268
|
+
* @returns A promise that resolves when the change set has been applied and the sync state updated.
|
|
269
269
|
*/
|
|
270
270
|
async syncChangeSet(syncChangeSet, trustPayload) {
|
|
271
271
|
if (!Is.empty(this._trustedSynchronisedStorageComponent)) {
|
|
@@ -293,7 +293,7 @@ export class SynchronisedStorageService {
|
|
|
293
293
|
/**
|
|
294
294
|
* Start the sync with further updates after an interval.
|
|
295
295
|
* @param storageKey The storage key to sync.
|
|
296
|
-
* @returns
|
|
296
|
+
* @returns A promise that resolves when the remote and local sync passes are complete.
|
|
297
297
|
* @internal
|
|
298
298
|
*/
|
|
299
299
|
async startEntitySync(storageKey) {
|
|
@@ -323,7 +323,7 @@ export class SynchronisedStorageService {
|
|
|
323
323
|
/**
|
|
324
324
|
* Check for updates in the remote storage.
|
|
325
325
|
* @param storageKey The storage key to check for updates.
|
|
326
|
-
* @returns
|
|
326
|
+
* @returns A promise that resolves when the local state has been updated from the remote sync state.
|
|
327
327
|
* @internal
|
|
328
328
|
*/
|
|
329
329
|
async updateFromRemoteSyncState(storageKey) {
|
|
@@ -349,7 +349,8 @@ export class SynchronisedStorageService {
|
|
|
349
349
|
}
|
|
350
350
|
/**
|
|
351
351
|
* Find any local updates and send them to the remote storage.
|
|
352
|
-
* @
|
|
352
|
+
* @param storageKey The key of the storage to synchronise.
|
|
353
|
+
* @returns A promise that resolves when local changes have been built into a changeset and dispatched.
|
|
353
354
|
* @internal
|
|
354
355
|
*/
|
|
355
356
|
async updateFromLocalSyncState(storageKey) {
|
|
@@ -432,7 +433,7 @@ export class SynchronisedStorageService {
|
|
|
432
433
|
/**
|
|
433
434
|
* Start the consolidation sync.
|
|
434
435
|
* @param storageKey The storage key to consolidate.
|
|
435
|
-
* @returns
|
|
436
|
+
* @returns A promise that resolves when the consolidation batch request is dispatched.
|
|
436
437
|
* @internal
|
|
437
438
|
*/
|
|
438
439
|
async startConsolidationSync(storageKey) {
|
|
@@ -456,8 +457,9 @@ export class SynchronisedStorageService {
|
|
|
456
457
|
}
|
|
457
458
|
}
|
|
458
459
|
/**
|
|
459
|
-
* Register a new
|
|
460
|
-
* @param syncRegisterStorageKey The
|
|
460
|
+
* Register a new storage key for synchronisation.
|
|
461
|
+
* @param syncRegisterStorageKey The registration payload containing the storage key.
|
|
462
|
+
* @returns A promise that resolves when the storage key is registered and activated if the service has started.
|
|
461
463
|
* @internal
|
|
462
464
|
*/
|
|
463
465
|
async registerStorageKey(syncRegisterStorageKey) {
|
|
@@ -477,8 +479,9 @@ export class SynchronisedStorageService {
|
|
|
477
479
|
}
|
|
478
480
|
}
|
|
479
481
|
/**
|
|
480
|
-
* Activate a storage key.
|
|
482
|
+
* Activate a storage key by scheduling update and consolidation tasks.
|
|
481
483
|
* @param storageKey The storage key to activate.
|
|
484
|
+
* @returns A promise that resolves when the scheduled tasks are registered.
|
|
482
485
|
* @internal
|
|
483
486
|
*/
|
|
484
487
|
async activateStorageKey(storageKey) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synchronisedStorageService.js","sourceRoot":"","sources":["../../src/synchronisedStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITaskSchedulerComponent } from \"@twin.org/background-task-models\";\nimport {\n\tBlobStorageConnectorFactory,\n\ttype IBlobStorageConnector\n} from \"@twin.org/blob-storage-models\";\nimport { ContextIdHelper, ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tUnauthorizedError\n} from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport type { IEventBusComponent } from \"@twin.org/event-bus-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\ttype ISyncChangeSet,\n\ttype ISynchronisedStorageComponent,\n\ttype ISyncItemChange,\n\ttype ISyncRegisterStorageKey,\n\tSynchronisedStorageTopics\n} from \"@twin.org/synchronised-storage-models\";\nimport { type ITrustComponent, TrustHelper } from \"@twin.org/trust-models\";\nimport { type IVaultConnector, VaultConnectorFactory, VaultKeyType } from \"@twin.org/vault-models\";\nimport {\n\ttype IVerifiableStorageConnector,\n\tVerifiableStorageConnectorFactory\n} from \"@twin.org/verifiable-storage-models\";\nimport verifiableStorageKeys from \"./data/verifiableStorageKeys.json\" with { type: \"json\" };\nimport type { SyncSnapshotEntry } from \"./entities/syncSnapshotEntry.js\";\nimport { BlobStorageHelper } from \"./helpers/blobStorageHelper.js\";\nimport { ChangeSetHelper } from \"./helpers/changeSetHelper.js\";\nimport { LocalSyncStateHelper } from \"./helpers/localSyncStateHelper.js\";\nimport { RemoteSyncStateHelper } from \"./helpers/remoteSyncStateHelper.js\";\nimport type { ISynchronisedStorageServiceConfig } from \"./models/ISynchronisedStorageServiceConfig.js\";\nimport type { ISynchronisedStorageServiceConstructorOptions } from \"./models/ISynchronisedStorageServiceConstructorOptions.js\";\n\n/**\n * Class for performing synchronised storage operations.\n */\nexport class SynchronisedStorageService implements ISynchronisedStorageComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<SynchronisedStorageService>();\n\n\t/**\n\t * The default interval to check for entity updates.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_ENTITY_UPDATE_INTERVAL_MINUTES: number = 5;\n\n\t/**\n\t * The default interval to perform consolidation.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CONSOLIDATION_INTERVAL_MINUTES: number = 60;\n\n\t/**\n\t * The default size of a consolidation batch.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CONSOLIDATION_BATCH_SIZE: number = 100;\n\n\t/**\n\t * The default max number of consolidations to keep in storage.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_MAX_CONSOLIDATIONS: number = 5;\n\n\t/**\n\t * The logging component to use for logging.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The event bus component.\n\t * @internal\n\t */\n\tprivate readonly _eventBusComponent: IEventBusComponent;\n\n\t/**\n\t * The vault connector.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector: IVaultConnector;\n\n\t/**\n\t * The storage connector for the sync snapshot entries.\n\t * @internal\n\t */\n\tprivate readonly _localSyncSnapshotEntryEntityStorage: IEntityStorageConnector<SyncSnapshotEntry>;\n\n\t/**\n\t * The blob storage connector to use for remote sync states.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageConnector: IBlobStorageConnector;\n\n\t/**\n\t * The verifiable storage connector to use for storing sync pointers.\n\t * @internal\n\t */\n\tprivate readonly _verifiableSyncPointerStorageConnector: IVerifiableStorageConnector;\n\n\t/**\n\t * The task scheduler component.\n\t * @internal\n\t */\n\tprivate readonly _taskSchedulerComponent: ITaskSchedulerComponent;\n\n\t/**\n\t * The synchronised storage service to use when this is not a trusted node.\n\t * @internal\n\t */\n\tprivate readonly _trustedSynchronisedStorageComponent?: ISynchronisedStorageComponent;\n\n\t/**\n\t * The blob storage helper.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\n\n\t/**\n\t * The trust component.\n\t * @internal\n\t */\n\tprivate readonly _trustComponent: ITrustComponent;\n\n\t/**\n\t * The change set helper.\n\t * @internal\n\t */\n\tprivate readonly _changeSetHelper: ChangeSetHelper;\n\n\t/**\n\t * The local sync state helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _localSyncStateHelper: LocalSyncStateHelper;\n\n\t/**\n\t * The remote sync state helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _remoteSyncStateHelper: RemoteSyncStateHelper;\n\n\t/**\n\t * The options for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: Required<ISynchronisedStorageServiceConfig>;\n\n\t/**\n\t * The synchronised storage key to use for the remote synchronised storage.\n\t * @internal\n\t */\n\tprivate readonly _synchronisedStorageKey: string;\n\n\t/**\n\t * The flag to determine if the service has been started.\n\t * @internal\n\t */\n\tprivate _serviceStarted: boolean;\n\n\t/**\n\t * The active storage keys for the synchronised storage service.\n\t * @internal\n\t */\n\tprivate readonly _activeStorageKeys: { [storageKey: string]: boolean };\n\n\t/**\n\t * The identity of the node this connector is running on.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Create a new instance of SynchronisedStorageService.\n\t * @param options The options for the service.\n\t */\n\tconstructor(options: ISynchronisedStorageServiceConstructorOptions) {\n\t\tGuards.object<ISynchronisedStorageServiceConstructorOptions>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options),\n\t\t\toptions\n\t\t);\n\t\tGuards.object<ISynchronisedStorageServiceConfig>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options.config.verifiableStorageKeyId),\n\t\t\toptions.config.verifiableStorageKeyId\n\t\t);\n\n\t\tthis._eventBusComponent = ComponentFactory.get(options.eventBusComponentType ?? \"event-bus\");\n\t\tthis._logging = ComponentFactory.getIfExists(options.loggingComponentType ?? \"logging\");\n\t\tthis._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType ?? \"vault\");\n\n\t\tthis._localSyncSnapshotEntryEntityStorage = EntityStorageConnectorFactory.get<\n\t\t\tIEntityStorageConnector<SyncSnapshotEntry>\n\t\t>(options.syncSnapshotStorageConnectorType ?? \"sync-snapshot-entry\");\n\n\t\tthis._verifiableSyncPointerStorageConnector = VerifiableStorageConnectorFactory.get(\n\t\t\toptions.verifiableStorageConnectorType ?? \"verifiable-storage\"\n\t\t);\n\n\t\tthis._blobStorageConnector = BlobStorageConnectorFactory.get(\n\t\t\toptions.blobStorageConnectorType ?? \"blob-storage\"\n\t\t);\n\n\t\tthis._taskSchedulerComponent = ComponentFactory.get(\n\t\t\toptions.taskSchedulerComponentType ?? \"task-scheduler\"\n\t\t);\n\n\t\tthis._trustComponent = ComponentFactory.get<ITrustComponent>(\n\t\t\toptions?.trustComponentType ?? \"trust\"\n\t\t);\n\n\t\t// If this is empty we assume the local node has the rights to write to the verifiable storage.\n\t\tlet isTrustedNode = true;\n\t\tif (!Is.empty(options.trustedSynchronisedStorageComponentType)) {\n\t\t\tisTrustedNode = false;\n\n\t\t\t// If it is set then we used the trusted component to send changesets to\n\t\t\tthis._trustedSynchronisedStorageComponent =\n\t\t\t\tComponentFactory.get<ISynchronisedStorageComponent>(\n\t\t\t\t\toptions.trustedSynchronisedStorageComponentType\n\t\t\t\t);\n\t\t}\n\n\t\tthis._config = {\n\t\t\tentityUpdateIntervalMinutes:\n\t\t\t\toptions.config.entityUpdateIntervalMinutes ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_ENTITY_UPDATE_INTERVAL_MINUTES,\n\t\t\tconsolidationIntervalMinutes:\n\t\t\t\toptions.config.consolidationIntervalMinutes ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_INTERVAL_MINUTES,\n\t\t\tconsolidationBatchSize:\n\t\t\t\toptions.config.consolidationBatchSize ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_BATCH_SIZE,\n\t\t\tmaxConsolidations:\n\t\t\t\toptions.config.maxConsolidations ?? SynchronisedStorageService._DEFAULT_MAX_CONSOLIDATIONS,\n\t\t\tblobStorageEncryptionKeyId:\n\t\t\t\toptions.config.blobStorageEncryptionKeyId ?? \"synchronised-storage-blob-encryption-key\",\n\t\t\tverifiableStorageKeyId: options.config.verifiableStorageKeyId,\n\t\t\toverrideTrustGeneratorType: options.config.overrideTrustGeneratorType ?? \"\"\n\t\t};\n\n\t\tthis._synchronisedStorageKey =\n\t\t\tverifiableStorageKeys[\n\t\t\t\toptions.config.verifiableStorageKeyId as keyof typeof verifiableStorageKeys\n\t\t\t] ?? options.config.verifiableStorageKeyId;\n\n\t\tGuards.stringValue(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\t\"synchronisedStorageKey\",\n\t\t\tthis._synchronisedStorageKey\n\t\t);\n\n\t\tthis._blobStorageHelper = new BlobStorageHelper(\n\t\t\tthis._logging,\n\t\t\tthis._vaultConnector,\n\t\t\tthis._blobStorageConnector,\n\t\t\tthis._config.blobStorageEncryptionKeyId,\n\t\t\tisTrustedNode\n\t\t);\n\n\t\tthis._changeSetHelper = new ChangeSetHelper(\n\t\t\tthis._logging,\n\t\t\tthis._eventBusComponent,\n\t\t\tthis._blobStorageHelper\n\t\t);\n\n\t\tthis._localSyncStateHelper = new LocalSyncStateHelper(\n\t\t\tthis._logging,\n\t\t\tthis._localSyncSnapshotEntryEntityStorage,\n\t\t\tthis._changeSetHelper\n\t\t);\n\n\t\tthis._remoteSyncStateHelper = new RemoteSyncStateHelper(\n\t\t\tthis._logging,\n\t\t\tthis._eventBusComponent,\n\t\t\tthis._verifiableSyncPointerStorageConnector,\n\t\t\tthis._blobStorageHelper,\n\t\t\tthis._changeSetHelper,\n\t\t\tisTrustedNode,\n\t\t\tthis._config.maxConsolidations\n\t\t);\n\n\t\tthis._serviceStarted = false;\n\t\tthis._activeStorageKeys = {};\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn SynchronisedStorageService.CLASS_NAME;\n\t}\n\n\t/**\n\t * The component needs to be started when the node is initialized.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async start(nodeLoggingComponentType?: string): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Node);\n\t\tthis._nodeId = contextIds[ContextIdKeys.Node];\n\n\t\tthis._remoteSyncStateHelper.setNodeId(this._nodeId);\n\t\tthis._changeSetHelper.setNodeId(this._nodeId);\n\t\tthis._blobStorageHelper.setNodeId(this._nodeId);\n\n\t\tthis._remoteSyncStateHelper.setSynchronisedStorageKey(this._synchronisedStorageKey);\n\t\tthis._serviceStarted = true;\n\n\t\t// If this is not a trusted node we need to request the decryption key from a trusted node\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tconst trustPayload = await this._trustComponent.generate(\n\t\t\t\tthis._nodeId,\n\t\t\t\tthis._config.overrideTrustGeneratorType.length > 0\n\t\t\t\t\t? this._config.overrideTrustGeneratorType\n\t\t\t\t\t: undefined\n\t\t\t);\n\n\t\t\tconst decryptionKey =\n\t\t\t\tawait this._trustedSynchronisedStorageComponent.getDecryptionKey(trustPayload);\n\n\t\t\tconst blobStorageEncryptionKeyId = `${this._nodeId}/${this._config.blobStorageEncryptionKeyId}`;\n\n\t\t\t// If the key exists remove it and get a new one, in case the key has been rotated\n\t\t\tconst existingKey = await this._vaultConnector.getKey(blobStorageEncryptionKeyId);\n\n\t\t\tif (!Is.empty(existingKey)) {\n\t\t\t\tawait this._vaultConnector.removeKey(blobStorageEncryptionKeyId);\n\t\t\t}\n\n\t\t\tawait this._vaultConnector.addKey(\n\t\t\t\tblobStorageEncryptionKeyId,\n\t\t\t\tVaultKeyType.ChaCha20Poly1305,\n\t\t\t\tConverter.base64ToBytes(decryptionKey)\n\t\t\t);\n\t\t}\n\n\t\tawait this._eventBusComponent.subscribe<ISyncRegisterStorageKey>(\n\t\t\tSynchronisedStorageTopics.RegisterStorageKey,\n\t\t\tasync event => this.registerStorageKey(event.data)\n\t\t);\n\n\t\tawait this._eventBusComponent.subscribe<ISyncItemChange>(\n\t\t\tSynchronisedStorageTopics.LocalItemChange,\n\t\t\tasync event => {\n\t\t\t\t// Make sure the change event is from this node\n\t\t\t\tif (Is.stringValue(this._nodeId) && this._nodeId === event.data.nodeId) {\n\t\t\t\t\tawait this._localSyncStateHelper.addLocalChange(\n\t\t\t\t\t\tevent.data.storageKey,\n\t\t\t\t\t\tevent.data.operation,\n\t\t\t\t\t\tevent.data.id\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tawait this._remoteSyncStateHelper.start();\n\n\t\t// If there are already storage keys registered, we need to activate them\n\t\tfor (const storageKey in this._activeStorageKeys) {\n\t\t\tawait this.activateStorageKey(storageKey);\n\t\t}\n\t}\n\n\t/**\n\t * The component needs to be stopped when the node is closed.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(nodeLoggingComponentType?: string): Promise<void> {\n\t\tfor (const storageKey in this._activeStorageKeys) {\n\t\t\tthis._activeStorageKeys[storageKey] = false;\n\t\t\tawait this._taskSchedulerComponent.removeTask(`synchronised-storage-update-${storageKey}`);\n\t\t\tawait this._taskSchedulerComponent.removeTask(\n\t\t\t\t`synchronised-storage-consolidation-${storageKey}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the decryption key for the synchronised storage.\n\t * This is used to decrypt the data stored in the synchronised storage.\n\t * @param trustPayload Trust payload to verify the requesters identity.\n\t * @returns The decryption key.\n\t */\n\tpublic async getDecryptionKey(trustPayload: unknown): Promise<string> {\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tthrow new GeneralError(SynchronisedStorageService.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tconst trustInfo = await TrustHelper.verifyTrust(\n\t\t\tthis._trustComponent,\n\t\t\ttrustPayload,\n\t\t\t\"getDecryptionKey\"\n\t\t);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"decryptionKeyRequest\",\n\t\t\tdata: {\n\t\t\t\tnodeId: trustInfo.identity\n\t\t\t}\n\t\t});\n\n\t\tconst blobStorageEncryptionKeyId = `${this._nodeId}/${this._config.blobStorageEncryptionKeyId}`;\n\t\tconst key = await this._vaultConnector.getKey(blobStorageEncryptionKeyId);\n\t\tif (Is.undefined(key.privateKey)) {\n\t\t\tthrow new UnauthorizedError(SynchronisedStorageService.CLASS_NAME, \"decryptionKeyNotFound\");\n\t\t}\n\n\t\treturn Converter.bytesToBase64(key.privateKey);\n\t}\n\n\t/**\n\t * Synchronise a set of changes from an untrusted node, assumes this is a trusted node.\n\t * @param syncChangeSet The change set to synchronise.\n\t * @param trustPayload Trust payload to verify the requesters identity.\n\t * @returns Nothing.\n\t */\n\tpublic async syncChangeSet(syncChangeSet: ISyncChangeSet, trustPayload: unknown): Promise<void> {\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tthrow new GeneralError(SynchronisedStorageService.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tGuards.object<ISyncChangeSet>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(syncChangeSet),\n\t\t\tsyncChangeSet\n\t\t);\n\t\tconst trustInfo = await TrustHelper.verifyTrust(\n\t\t\tthis._trustComponent,\n\t\t\ttrustPayload,\n\t\t\t\"syncChangeSet\"\n\t\t);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"syncChangeSetForRemoteNode\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId: syncChangeSet.id,\n\t\t\t\tnodeId: trustInfo.identity\n\t\t\t}\n\t\t});\n\n\t\tconst copy = await this._changeSetHelper.copyChangeset(syncChangeSet);\n\n\t\tif (!Is.empty(copy)) {\n\t\t\t// Apply the changes to this node\n\t\t\tawait this._changeSetHelper.applyChangeset(copy.syncChangeSet);\n\n\t\t\t// And update the sync state with the latest changes\n\t\t\tawait this._remoteSyncStateHelper.addChangeSetToSyncState(\n\t\t\t\tcopy.syncChangeSet.storageKey,\n\t\t\t\tcopy.changeSetStorageId\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Start the sync with further updates after an interval.\n\t * @param storageKey The storage key to sync.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async startEntitySync(storageKey: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"startEntitySync\",\n\t\t\t\tdata: {\n\t\t\t\t\tstorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// First we check for remote changes\n\t\t\tawait this.updateFromRemoteSyncState(storageKey);\n\n\t\t\t// Now send any updates we have to the remote storage\n\t\t\tawait this.updateFromLocalSyncState(storageKey);\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"entitySyncFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Check for updates in the remote storage.\n\t * @param storageKey The storage key to check for updates.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async updateFromRemoteSyncState(storageKey: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"updateFromRemoteSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\n\t\t// Get the verifiable sync pointer store from the verifiable storage\n\t\tconst verifiableSyncPointerStore =\n\t\t\tawait this._remoteSyncStateHelper.getVerifiableSyncPointerStore();\n\n\t\tif (!Is.empty(verifiableSyncPointerStore.syncPointers[storageKey])) {\n\t\t\t// Load the sync state from the remote blob storage using the sync pointer\n\t\t\t// to load the sync state\n\t\t\tconst remoteSyncState = await this._remoteSyncStateHelper.getSyncState(\n\t\t\t\tverifiableSyncPointerStore.syncPointers[storageKey]\n\t\t\t);\n\n\t\t\t// If we got the sync state we can try and sync from it\n\t\t\tif (!Is.undefined(remoteSyncState)) {\n\t\t\t\tawait this._localSyncStateHelper.applySyncState(storageKey, remoteSyncState);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Find any local updates and send them to the remote storage.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async updateFromLocalSyncState(storageKey: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"updateFromLocalSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\n\t\tconst localChangeSnapshots = await this._localSyncStateHelper.getSnapshots(storageKey, true);\n\n\t\tif (localChangeSnapshots.length > 0) {\n\t\t\tconst localChangeSnapshot = localChangeSnapshots[0];\n\n\t\t\tif (Is.arrayValue(localChangeSnapshot.changes)) {\n\t\t\t\tawait this._remoteSyncStateHelper.buildChangeSet(\n\t\t\t\t\tstorageKey,\n\t\t\t\t\tlocalChangeSnapshot.changes,\n\t\t\t\t\tasync (syncChangeSet, changeSetStorageId) => {\n\t\t\t\t\t\tif (Is.empty(syncChangeSet) && Is.empty(changeSetStorageId)) {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\tmessage: \"builtStorageChangeSetNone\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tstorageKey\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\tmessage: \"builtStorageChangeSet\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t// Send the local changes to the remote storage if we are a trusted node\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tIs.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\t\t\t\t\tIs.stringValue(changeSetStorageId)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// If we are a trusted node, we can add the change set to the sync state\n\t\t\t\t\t\t\t\t// and remove the local change snapshot\n\t\t\t\t\t\t\t\tawait this._remoteSyncStateHelper.addChangeSetToSyncState(\n\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tawait this._localSyncStateHelper.removeLocalChangeSnapshot(localChangeSnapshot);\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\t!Is.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\t\t\t\t\tIs.object(syncChangeSet) &&\n\t\t\t\t\t\t\t\tIs.stringValue(this._nodeId)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// If we are not a trusted node, we need to send the changes to the trusted node\n\t\t\t\t\t\t\t\t// and then remove the local change snapshot\n\t\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\t\tmessage: \"sendingChangeSetToTrustedNode\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst trustPayload = await this._trustComponent.generate(\n\t\t\t\t\t\t\t\t\tthis._nodeId,\n\t\t\t\t\t\t\t\t\tthis._config.overrideTrustGeneratorType.length > 0\n\t\t\t\t\t\t\t\t\t\t? this._config.overrideTrustGeneratorType\n\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tawait this._trustedSynchronisedStorageComponent.syncChangeSet(\n\t\t\t\t\t\t\t\t\tsyncChangeSet,\n\t\t\t\t\t\t\t\t\ttrustPayload\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tawait this._localSyncStateHelper.removeLocalChangeSnapshot(localChangeSnapshot);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\tmessage: \"updateFromLocalSyncStateNoChanges\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Start the consolidation sync.\n\t * @param storageKey The storage key to consolidate.\n\t * @returns Nothing.\n\t * @internal\n\t */\n\tprivate async startConsolidationSync(storageKey: string): Promise<void> {\n\t\ttry {\n\t\t\t// If we are going to perform a consolidation first take any local updates\n\t\t\t// we have and create a changeset from them, so that anybody applying\n\t\t\t// just changes since a consolidation can use the changeset\n\t\t\t// and skip the consolidation\n\t\t\tawait this.updateFromLocalSyncState(storageKey);\n\n\t\t\t// Now start the consolidation\n\t\t\tawait this._remoteSyncStateHelper.consolidationStart(\n\t\t\t\tstorageKey,\n\t\t\t\tthis._config.consolidationBatchSize ??\n\t\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_BATCH_SIZE\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"consolidationSyncFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Register a new sync type.\n\t * @param syncRegisterStorageKey The sync register type to register.\n\t * @internal\n\t */\n\tprivate async registerStorageKey(syncRegisterStorageKey: ISyncRegisterStorageKey): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"registerStorageKey\",\n\t\t\tdata: {\n\t\t\t\tstorageKey: syncRegisterStorageKey.storageKey\n\t\t\t}\n\t\t});\n\n\t\tif (Is.empty(this._activeStorageKeys[syncRegisterStorageKey.storageKey])) {\n\t\t\tthis._activeStorageKeys[syncRegisterStorageKey.storageKey] = false;\n\n\t\t\tif (this._serviceStarted) {\n\t\t\t\tawait this.activateStorageKey(syncRegisterStorageKey.storageKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Activate a storage key.\n\t * @param storageKey The storage key to activate.\n\t * @internal\n\t */\n\tprivate async activateStorageKey(storageKey: string): Promise<void> {\n\t\tif (!Is.empty(this._activeStorageKeys[storageKey]) && !this._activeStorageKeys[storageKey]) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"activateStorageKey\",\n\t\t\t\tdata: {\n\t\t\t\t\tstorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis._activeStorageKeys[storageKey] = true;\n\n\t\t\tif (this._config.entityUpdateIntervalMinutes > 0) {\n\t\t\t\tawait this._taskSchedulerComponent.addTask(\n\t\t\t\t\t`synchronised-storage-update-${storageKey}`,\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnextTriggerTime: Date.now(),\n\t\t\t\t\t\t\tintervalMinutes: this._config.entityUpdateIntervalMinutes\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tasync () => this.startEntitySync(storageKey)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!Is.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\tthis._config.consolidationIntervalMinutes > 0\n\t\t\t) {\n\t\t\t\tawait this._taskSchedulerComponent.addTask(\n\t\t\t\t\t`synchronised-storage-consolidation-${storageKey}`,\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnextTriggerTime: Date.now(),\n\t\t\t\t\t\t\tintervalMinutes: this._config.consolidationIntervalMinutes\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tasync () => this.startConsolidationSync(storageKey)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"synchronisedStorageService.js","sourceRoot":"","sources":["../../src/synchronisedStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITaskSchedulerComponent } from \"@twin.org/background-task-models\";\nimport {\n\tBlobStorageConnectorFactory,\n\ttype IBlobStorageConnector\n} from \"@twin.org/blob-storage-models\";\nimport { ContextIdHelper, ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tUnauthorizedError\n} from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport type { IEventBusComponent } from \"@twin.org/event-bus-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\ttype ISyncChangeSet,\n\ttype ISynchronisedStorageComponent,\n\ttype ISyncItemChange,\n\ttype ISyncRegisterStorageKey,\n\tSynchronisedStorageTopics\n} from \"@twin.org/synchronised-storage-models\";\nimport { type ITrustComponent, TrustHelper } from \"@twin.org/trust-models\";\nimport { type IVaultConnector, VaultConnectorFactory, VaultKeyType } from \"@twin.org/vault-models\";\nimport {\n\ttype IVerifiableStorageConnector,\n\tVerifiableStorageConnectorFactory\n} from \"@twin.org/verifiable-storage-models\";\nimport verifiableStorageKeys from \"./data/verifiableStorageKeys.json\" with { type: \"json\" };\nimport type { SyncSnapshotEntry } from \"./entities/syncSnapshotEntry.js\";\nimport { BlobStorageHelper } from \"./helpers/blobStorageHelper.js\";\nimport { ChangeSetHelper } from \"./helpers/changeSetHelper.js\";\nimport { LocalSyncStateHelper } from \"./helpers/localSyncStateHelper.js\";\nimport { RemoteSyncStateHelper } from \"./helpers/remoteSyncStateHelper.js\";\nimport type { ISynchronisedStorageServiceConfig } from \"./models/ISynchronisedStorageServiceConfig.js\";\nimport type { ISynchronisedStorageServiceConstructorOptions } from \"./models/ISynchronisedStorageServiceConstructorOptions.js\";\n\n/**\n * Class for performing synchronised storage operations.\n */\nexport class SynchronisedStorageService implements ISynchronisedStorageComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<SynchronisedStorageService>();\n\n\t/**\n\t * The default interval to check for entity updates.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_ENTITY_UPDATE_INTERVAL_MINUTES: number = 5;\n\n\t/**\n\t * The default interval to perform consolidation.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CONSOLIDATION_INTERVAL_MINUTES: number = 60;\n\n\t/**\n\t * The default size of a consolidation batch.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_CONSOLIDATION_BATCH_SIZE: number = 100;\n\n\t/**\n\t * The default max number of consolidations to keep in storage.\n\t * @internal\n\t */\n\tprivate static readonly _DEFAULT_MAX_CONSOLIDATIONS: number = 5;\n\n\t/**\n\t * The logging component to use for logging.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The event bus component.\n\t * @internal\n\t */\n\tprivate readonly _eventBusComponent: IEventBusComponent;\n\n\t/**\n\t * The vault connector.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector: IVaultConnector;\n\n\t/**\n\t * The storage connector for the sync snapshot entries.\n\t * @internal\n\t */\n\tprivate readonly _localSyncSnapshotEntryEntityStorage: IEntityStorageConnector<SyncSnapshotEntry>;\n\n\t/**\n\t * The blob storage connector to use for remote sync states.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageConnector: IBlobStorageConnector;\n\n\t/**\n\t * The verifiable storage connector to use for storing sync pointers.\n\t * @internal\n\t */\n\tprivate readonly _verifiableSyncPointerStorageConnector: IVerifiableStorageConnector;\n\n\t/**\n\t * The task scheduler component.\n\t * @internal\n\t */\n\tprivate readonly _taskSchedulerComponent: ITaskSchedulerComponent;\n\n\t/**\n\t * The synchronised storage service to use when this is not a trusted node.\n\t * @internal\n\t */\n\tprivate readonly _trustedSynchronisedStorageComponent?: ISynchronisedStorageComponent;\n\n\t/**\n\t * The blob storage helper.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\n\n\t/**\n\t * The trust component.\n\t * @internal\n\t */\n\tprivate readonly _trustComponent: ITrustComponent;\n\n\t/**\n\t * The change set helper.\n\t * @internal\n\t */\n\tprivate readonly _changeSetHelper: ChangeSetHelper;\n\n\t/**\n\t * The local sync state helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _localSyncStateHelper: LocalSyncStateHelper;\n\n\t/**\n\t * The remote sync state helper to use for applying changesets.\n\t * @internal\n\t */\n\tprivate readonly _remoteSyncStateHelper: RemoteSyncStateHelper;\n\n\t/**\n\t * The options for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: Required<ISynchronisedStorageServiceConfig>;\n\n\t/**\n\t * The synchronised storage key to use for the remote synchronised storage.\n\t * @internal\n\t */\n\tprivate readonly _synchronisedStorageKey: string;\n\n\t/**\n\t * The flag to determine if the service has been started.\n\t * @internal\n\t */\n\tprivate _serviceStarted: boolean;\n\n\t/**\n\t * The active storage keys for the synchronised storage service.\n\t * @internal\n\t */\n\tprivate readonly _activeStorageKeys: { [storageKey: string]: boolean };\n\n\t/**\n\t * The identity of the node this connector is running on.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Create a new instance of SynchronisedStorageService.\n\t * @param options The options for the service.\n\t */\n\tconstructor(options: ISynchronisedStorageServiceConstructorOptions) {\n\t\tGuards.object<ISynchronisedStorageServiceConstructorOptions>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options),\n\t\t\toptions\n\t\t);\n\t\tGuards.object<ISynchronisedStorageServiceConfig>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(options.config.verifiableStorageKeyId),\n\t\t\toptions.config.verifiableStorageKeyId\n\t\t);\n\n\t\tthis._eventBusComponent = ComponentFactory.get(options.eventBusComponentType ?? \"event-bus\");\n\t\tthis._logging = ComponentFactory.getIfExists(options.loggingComponentType);\n\t\tthis._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType ?? \"vault\");\n\n\t\tthis._localSyncSnapshotEntryEntityStorage = EntityStorageConnectorFactory.get<\n\t\t\tIEntityStorageConnector<SyncSnapshotEntry>\n\t\t>(options.syncSnapshotStorageConnectorType ?? \"sync-snapshot-entry\");\n\n\t\tthis._verifiableSyncPointerStorageConnector = VerifiableStorageConnectorFactory.get(\n\t\t\toptions.verifiableStorageConnectorType ?? \"verifiable-storage\"\n\t\t);\n\n\t\tthis._blobStorageConnector = BlobStorageConnectorFactory.get(\n\t\t\toptions.blobStorageConnectorType ?? \"blob-storage\"\n\t\t);\n\n\t\tthis._taskSchedulerComponent = ComponentFactory.get(\n\t\t\toptions.taskSchedulerComponentType ?? \"task-scheduler\"\n\t\t);\n\n\t\tthis._trustComponent = ComponentFactory.get<ITrustComponent>(\n\t\t\toptions?.trustComponentType ?? \"trust\"\n\t\t);\n\n\t\t// If this is empty we assume the local node has the rights to write to the verifiable storage.\n\t\tlet isTrustedNode = true;\n\t\tif (!Is.empty(options.trustedSynchronisedStorageComponentType)) {\n\t\t\tisTrustedNode = false;\n\n\t\t\t// If it is set then we used the trusted component to send changesets to\n\t\t\tthis._trustedSynchronisedStorageComponent =\n\t\t\t\tComponentFactory.get<ISynchronisedStorageComponent>(\n\t\t\t\t\toptions.trustedSynchronisedStorageComponentType\n\t\t\t\t);\n\t\t}\n\n\t\tthis._config = {\n\t\t\tentityUpdateIntervalMinutes:\n\t\t\t\toptions.config.entityUpdateIntervalMinutes ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_ENTITY_UPDATE_INTERVAL_MINUTES,\n\t\t\tconsolidationIntervalMinutes:\n\t\t\t\toptions.config.consolidationIntervalMinutes ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_INTERVAL_MINUTES,\n\t\t\tconsolidationBatchSize:\n\t\t\t\toptions.config.consolidationBatchSize ??\n\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_BATCH_SIZE,\n\t\t\tmaxConsolidations:\n\t\t\t\toptions.config.maxConsolidations ?? SynchronisedStorageService._DEFAULT_MAX_CONSOLIDATIONS,\n\t\t\tblobStorageEncryptionKeyId:\n\t\t\t\toptions.config.blobStorageEncryptionKeyId ?? \"synchronised-storage-blob-encryption-key\",\n\t\t\tverifiableStorageKeyId: options.config.verifiableStorageKeyId,\n\t\t\toverrideTrustGeneratorType: options.config.overrideTrustGeneratorType ?? \"\"\n\t\t};\n\n\t\tthis._synchronisedStorageKey =\n\t\t\tverifiableStorageKeys[\n\t\t\t\toptions.config.verifiableStorageKeyId as keyof typeof verifiableStorageKeys\n\t\t\t] ?? options.config.verifiableStorageKeyId;\n\n\t\tGuards.stringValue(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\t\"synchronisedStorageKey\",\n\t\t\tthis._synchronisedStorageKey\n\t\t);\n\n\t\tthis._blobStorageHelper = new BlobStorageHelper(\n\t\t\tthis._logging,\n\t\t\tthis._vaultConnector,\n\t\t\tthis._blobStorageConnector,\n\t\t\tthis._config.blobStorageEncryptionKeyId,\n\t\t\tisTrustedNode\n\t\t);\n\n\t\tthis._changeSetHelper = new ChangeSetHelper(\n\t\t\tthis._logging,\n\t\t\tthis._eventBusComponent,\n\t\t\tthis._blobStorageHelper\n\t\t);\n\n\t\tthis._localSyncStateHelper = new LocalSyncStateHelper(\n\t\t\tthis._logging,\n\t\t\tthis._localSyncSnapshotEntryEntityStorage,\n\t\t\tthis._changeSetHelper\n\t\t);\n\n\t\tthis._remoteSyncStateHelper = new RemoteSyncStateHelper(\n\t\t\tthis._logging,\n\t\t\tthis._eventBusComponent,\n\t\t\tthis._verifiableSyncPointerStorageConnector,\n\t\t\tthis._blobStorageHelper,\n\t\t\tthis._changeSetHelper,\n\t\t\tisTrustedNode,\n\t\t\tthis._config.maxConsolidations\n\t\t);\n\n\t\tthis._serviceStarted = false;\n\t\tthis._activeStorageKeys = {};\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn SynchronisedStorageService.CLASS_NAME;\n\t}\n\n\t/**\n\t * The component needs to be started when the node is initialized.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns A promise that resolves when the service is started and all event bus subscriptions are active.\n\t */\n\tpublic async start(nodeLoggingComponentType?: string): Promise<void> {\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Node);\n\t\tthis._nodeId = contextIds[ContextIdKeys.Node];\n\n\t\tthis._remoteSyncStateHelper.setNodeId(this._nodeId);\n\t\tthis._changeSetHelper.setNodeId(this._nodeId);\n\t\tthis._blobStorageHelper.setNodeId(this._nodeId);\n\n\t\tthis._remoteSyncStateHelper.setSynchronisedStorageKey(this._synchronisedStorageKey);\n\t\tthis._serviceStarted = true;\n\n\t\t// If this is not a trusted node we need to request the decryption key from a trusted node\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tconst trustPayload = await this._trustComponent.generate(\n\t\t\t\tthis._nodeId,\n\t\t\t\tthis._config.overrideTrustGeneratorType.length > 0\n\t\t\t\t\t? this._config.overrideTrustGeneratorType\n\t\t\t\t\t: undefined\n\t\t\t);\n\n\t\t\tconst decryptionKey =\n\t\t\t\tawait this._trustedSynchronisedStorageComponent.getDecryptionKey(trustPayload);\n\n\t\t\tconst blobStorageEncryptionKeyId = `${this._nodeId}/${this._config.blobStorageEncryptionKeyId}`;\n\n\t\t\t// If the key exists remove it and get a new one, in case the key has been rotated\n\t\t\tconst existingKey = await this._vaultConnector.getKey(blobStorageEncryptionKeyId);\n\n\t\t\tif (!Is.empty(existingKey)) {\n\t\t\t\tawait this._vaultConnector.removeKey(blobStorageEncryptionKeyId);\n\t\t\t}\n\n\t\t\tawait this._vaultConnector.addKey(\n\t\t\t\tblobStorageEncryptionKeyId,\n\t\t\t\tVaultKeyType.ChaCha20Poly1305,\n\t\t\t\tConverter.base64ToBytes(decryptionKey)\n\t\t\t);\n\t\t}\n\n\t\tawait this._eventBusComponent.subscribe<ISyncRegisterStorageKey>(\n\t\t\tSynchronisedStorageTopics.RegisterStorageKey,\n\t\t\tasync event => this.registerStorageKey(event.data)\n\t\t);\n\n\t\tawait this._eventBusComponent.subscribe<ISyncItemChange>(\n\t\t\tSynchronisedStorageTopics.LocalItemChange,\n\t\t\tasync event => {\n\t\t\t\t// Make sure the change event is from this node\n\t\t\t\tif (Is.stringValue(this._nodeId) && this._nodeId === event.data.nodeId) {\n\t\t\t\t\tawait this._localSyncStateHelper.addLocalChange(\n\t\t\t\t\t\tevent.data.storageKey,\n\t\t\t\t\t\tevent.data.operation,\n\t\t\t\t\t\tevent.data.id\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tawait this._remoteSyncStateHelper.start();\n\n\t\t// If there are already storage keys registered, we need to activate them\n\t\tfor (const storageKey in this._activeStorageKeys) {\n\t\t\tawait this.activateStorageKey(storageKey);\n\t\t}\n\t}\n\n\t/**\n\t * The component needs to be stopped when the node is closed.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns A promise that resolves when all scheduled tasks are removed and storage keys are deactivated.\n\t */\n\tpublic async stop(nodeLoggingComponentType?: string): Promise<void> {\n\t\tfor (const storageKey in this._activeStorageKeys) {\n\t\t\tthis._activeStorageKeys[storageKey] = false;\n\t\t\tawait this._taskSchedulerComponent.removeTask(`synchronised-storage-update-${storageKey}`);\n\t\t\tawait this._taskSchedulerComponent.removeTask(\n\t\t\t\t`synchronised-storage-consolidation-${storageKey}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Get the decryption key for the synchronised storage.\n\t * This is used to decrypt the data stored in the synchronised storage.\n\t * @param trustPayload Trust payload to verify the requesters identity.\n\t * @returns The decryption key.\n\t */\n\tpublic async getDecryptionKey(trustPayload: unknown): Promise<string> {\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tthrow new GeneralError(SynchronisedStorageService.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tconst trustInfo = await TrustHelper.verifyTrust(\n\t\t\tthis._trustComponent,\n\t\t\ttrustPayload,\n\t\t\t\"getDecryptionKey\"\n\t\t);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"decryptionKeyRequest\",\n\t\t\tdata: {\n\t\t\t\tnodeId: trustInfo.identity\n\t\t\t}\n\t\t});\n\n\t\tconst blobStorageEncryptionKeyId = `${this._nodeId}/${this._config.blobStorageEncryptionKeyId}`;\n\t\tconst key = await this._vaultConnector.getKey(blobStorageEncryptionKeyId);\n\t\tif (Is.undefined(key.privateKey)) {\n\t\t\tthrow new UnauthorizedError(SynchronisedStorageService.CLASS_NAME, \"decryptionKeyNotFound\");\n\t\t}\n\n\t\treturn Converter.bytesToBase64(key.privateKey);\n\t}\n\n\t/**\n\t * Synchronise a set of changes from an untrusted node, assumes this is a trusted node.\n\t * @param syncChangeSet The change set to synchronise.\n\t * @param trustPayload Trust payload to verify the requesters identity.\n\t * @returns A promise that resolves when the change set has been applied and the sync state updated.\n\t */\n\tpublic async syncChangeSet(syncChangeSet: ISyncChangeSet, trustPayload: unknown): Promise<void> {\n\t\tif (!Is.empty(this._trustedSynchronisedStorageComponent)) {\n\t\t\tthrow new GeneralError(SynchronisedStorageService.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tGuards.object<ISyncChangeSet>(\n\t\t\tSynchronisedStorageService.CLASS_NAME,\n\t\t\tnameof(syncChangeSet),\n\t\t\tsyncChangeSet\n\t\t);\n\t\tconst trustInfo = await TrustHelper.verifyTrust(\n\t\t\tthis._trustComponent,\n\t\t\ttrustPayload,\n\t\t\t\"syncChangeSet\"\n\t\t);\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"syncChangeSetForRemoteNode\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId: syncChangeSet.id,\n\t\t\t\tnodeId: trustInfo.identity\n\t\t\t}\n\t\t});\n\n\t\tconst copy = await this._changeSetHelper.copyChangeset(syncChangeSet);\n\n\t\tif (!Is.empty(copy)) {\n\t\t\t// Apply the changes to this node\n\t\t\tawait this._changeSetHelper.applyChangeset(copy.syncChangeSet);\n\n\t\t\t// And update the sync state with the latest changes\n\t\t\tawait this._remoteSyncStateHelper.addChangeSetToSyncState(\n\t\t\t\tcopy.syncChangeSet.storageKey,\n\t\t\t\tcopy.changeSetStorageId\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Start the sync with further updates after an interval.\n\t * @param storageKey The storage key to sync.\n\t * @returns A promise that resolves when the remote and local sync passes are complete.\n\t * @internal\n\t */\n\tprivate async startEntitySync(storageKey: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"startEntitySync\",\n\t\t\t\tdata: {\n\t\t\t\t\tstorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// First we check for remote changes\n\t\t\tawait this.updateFromRemoteSyncState(storageKey);\n\n\t\t\t// Now send any updates we have to the remote storage\n\t\t\tawait this.updateFromLocalSyncState(storageKey);\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"entitySyncFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Check for updates in the remote storage.\n\t * @param storageKey The storage key to check for updates.\n\t * @returns A promise that resolves when the local state has been updated from the remote sync state.\n\t * @internal\n\t */\n\tprivate async updateFromRemoteSyncState(storageKey: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"updateFromRemoteSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\n\t\t// Get the verifiable sync pointer store from the verifiable storage\n\t\tconst verifiableSyncPointerStore =\n\t\t\tawait this._remoteSyncStateHelper.getVerifiableSyncPointerStore();\n\n\t\tif (!Is.empty(verifiableSyncPointerStore.syncPointers[storageKey])) {\n\t\t\t// Load the sync state from the remote blob storage using the sync pointer\n\t\t\t// to load the sync state\n\t\t\tconst remoteSyncState = await this._remoteSyncStateHelper.getSyncState(\n\t\t\t\tverifiableSyncPointerStore.syncPointers[storageKey]\n\t\t\t);\n\n\t\t\t// If we got the sync state we can try and sync from it\n\t\t\tif (!Is.undefined(remoteSyncState)) {\n\t\t\t\tawait this._localSyncStateHelper.applySyncState(storageKey, remoteSyncState);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Find any local updates and send them to the remote storage.\n\t * @param storageKey The key of the storage to synchronise.\n\t * @returns A promise that resolves when local changes have been built into a changeset and dispatched.\n\t * @internal\n\t */\n\tprivate async updateFromLocalSyncState(storageKey: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"updateFromLocalSyncState\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\n\t\tconst localChangeSnapshots = await this._localSyncStateHelper.getSnapshots(storageKey, true);\n\n\t\tif (localChangeSnapshots.length > 0) {\n\t\t\tconst localChangeSnapshot = localChangeSnapshots[0];\n\n\t\t\tif (Is.arrayValue(localChangeSnapshot.changes)) {\n\t\t\t\tawait this._remoteSyncStateHelper.buildChangeSet(\n\t\t\t\t\tstorageKey,\n\t\t\t\t\tlocalChangeSnapshot.changes,\n\t\t\t\t\tasync (syncChangeSet, changeSetStorageId) => {\n\t\t\t\t\t\tif (Is.empty(syncChangeSet) && Is.empty(changeSetStorageId)) {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\tmessage: \"builtStorageChangeSetNone\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tstorageKey\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\tmessage: \"builtStorageChangeSet\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t// Send the local changes to the remote storage if we are a trusted node\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tIs.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\t\t\t\t\tIs.stringValue(changeSetStorageId)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// If we are a trusted node, we can add the change set to the sync state\n\t\t\t\t\t\t\t\t// and remove the local change snapshot\n\t\t\t\t\t\t\t\tawait this._remoteSyncStateHelper.addChangeSetToSyncState(\n\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tawait this._localSyncStateHelper.removeLocalChangeSnapshot(localChangeSnapshot);\n\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\t!Is.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\t\t\t\t\tIs.object(syncChangeSet) &&\n\t\t\t\t\t\t\t\tIs.stringValue(this._nodeId)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t// If we are not a trusted node, we need to send the changes to the trusted node\n\t\t\t\t\t\t\t\t// and then remove the local change snapshot\n\t\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\t\t\t\t\tmessage: \"sendingChangeSetToTrustedNode\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tstorageKey,\n\t\t\t\t\t\t\t\t\t\tchangeSetStorageId\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst trustPayload = await this._trustComponent.generate(\n\t\t\t\t\t\t\t\t\tthis._nodeId,\n\t\t\t\t\t\t\t\t\tthis._config.overrideTrustGeneratorType.length > 0\n\t\t\t\t\t\t\t\t\t\t? this._config.overrideTrustGeneratorType\n\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tawait this._trustedSynchronisedStorageComponent.syncChangeSet(\n\t\t\t\t\t\t\t\t\tsyncChangeSet,\n\t\t\t\t\t\t\t\t\ttrustPayload\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tawait this._localSyncStateHelper.removeLocalChangeSnapshot(localChangeSnapshot);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\t\tmessage: \"updateFromLocalSyncStateNoChanges\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tstorageKey\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Start the consolidation sync.\n\t * @param storageKey The storage key to consolidate.\n\t * @returns A promise that resolves when the consolidation batch request is dispatched.\n\t * @internal\n\t */\n\tprivate async startConsolidationSync(storageKey: string): Promise<void> {\n\t\ttry {\n\t\t\t// If we are going to perform a consolidation first take any local updates\n\t\t\t// we have and create a changeset from them, so that anybody applying\n\t\t\t// just changes since a consolidation can use the changeset\n\t\t\t// and skip the consolidation\n\t\t\tawait this.updateFromLocalSyncState(storageKey);\n\n\t\t\t// Now start the consolidation\n\t\t\tawait this._remoteSyncStateHelper.consolidationStart(\n\t\t\t\tstorageKey,\n\t\t\t\tthis._config.consolidationBatchSize ??\n\t\t\t\t\tSynchronisedStorageService._DEFAULT_CONSOLIDATION_BATCH_SIZE\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"consolidationSyncFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Register a new storage key for synchronisation.\n\t * @param syncRegisterStorageKey The registration payload containing the storage key.\n\t * @returns A promise that resolves when the storage key is registered and activated if the service has started.\n\t * @internal\n\t */\n\tprivate async registerStorageKey(syncRegisterStorageKey: ISyncRegisterStorageKey): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\tmessage: \"registerStorageKey\",\n\t\t\tdata: {\n\t\t\t\tstorageKey: syncRegisterStorageKey.storageKey\n\t\t\t}\n\t\t});\n\n\t\tif (Is.empty(this._activeStorageKeys[syncRegisterStorageKey.storageKey])) {\n\t\t\tthis._activeStorageKeys[syncRegisterStorageKey.storageKey] = false;\n\n\t\t\tif (this._serviceStarted) {\n\t\t\t\tawait this.activateStorageKey(syncRegisterStorageKey.storageKey);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Activate a storage key by scheduling update and consolidation tasks.\n\t * @param storageKey The storage key to activate.\n\t * @returns A promise that resolves when the scheduled tasks are registered.\n\t * @internal\n\t */\n\tprivate async activateStorageKey(storageKey: string): Promise<void> {\n\t\tif (!Is.empty(this._activeStorageKeys[storageKey]) && !this._activeStorageKeys[storageKey]) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: SynchronisedStorageService.CLASS_NAME,\n\t\t\t\tmessage: \"activateStorageKey\",\n\t\t\t\tdata: {\n\t\t\t\t\tstorageKey\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis._activeStorageKeys[storageKey] = true;\n\n\t\t\tif (this._config.entityUpdateIntervalMinutes > 0) {\n\t\t\t\tawait this._taskSchedulerComponent.addTask(\n\t\t\t\t\t`synchronised-storage-update-${storageKey}`,\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnextTriggerTime: Date.now(),\n\t\t\t\t\t\t\tintervalMinutes: this._config.entityUpdateIntervalMinutes\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tasync () => this.startEntitySync(storageKey)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!Is.empty(this._trustedSynchronisedStorageComponent) &&\n\t\t\t\tthis._config.consolidationIntervalMinutes > 0\n\t\t\t) {\n\t\t\t\tawait this._taskSchedulerComponent.addTask(\n\t\t\t\t\t`synchronised-storage-consolidation-${storageKey}`,\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnextTriggerTime: Date.now(),\n\t\t\t\t\t\t\tintervalMinutes: this._config.consolidationIntervalMinutes\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tasync () => this.startConsolidationSync(storageKey)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -38,7 +38,7 @@ export declare class BlobStorageHelper {
|
|
|
38
38
|
/**
|
|
39
39
|
* Remove a blob from storage.
|
|
40
40
|
* @param blobId The id of the blob to remove.
|
|
41
|
-
* @returns
|
|
41
|
+
* @returns A promise that resolves when the blob is removed.
|
|
42
42
|
*/
|
|
43
43
|
removeBlob(blobId: string): Promise<void>;
|
|
44
44
|
}
|