@twin.org/synchronised-storage-service 0.0.3-next.6 → 0.0.3-next.8
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/dist/es/helpers/changeSetHelper.js +3 -3
- package/dist/es/helpers/changeSetHelper.js.map +1 -1
- package/dist/es/helpers/remoteSyncStateHelper.js +3 -3
- package/dist/es/helpers/remoteSyncStateHelper.js.map +1 -1
- package/dist/es/synchronisedStorageRoutes.js +1 -1
- package/dist/es/synchronisedStorageRoutes.js.map +1 -1
- package/docs/changelog.md +29 -0
- package/docs/open-api/spec.json +9 -14
- package/package.json +2 -2
|
@@ -95,7 +95,7 @@ export class ChangeSetHelper {
|
|
|
95
95
|
const syncChangeset = await this.getChangeset(changeSetStorageId);
|
|
96
96
|
// Only apply changesets from other nodes, we don't want to overwrite
|
|
97
97
|
// any changes we have made to local entity storage
|
|
98
|
-
if (!Is.empty(syncChangeset) && syncChangeset.
|
|
98
|
+
if (!Is.empty(syncChangeset) && syncChangeset.nodeIdentity !== this._nodeId) {
|
|
99
99
|
await this.applyChangeset(syncChangeset);
|
|
100
100
|
}
|
|
101
101
|
return syncChangeset;
|
|
@@ -130,7 +130,7 @@ export class ChangeSetHelper {
|
|
|
130
130
|
entity: {
|
|
131
131
|
...change.entity,
|
|
132
132
|
id: change.id,
|
|
133
|
-
|
|
133
|
+
nodeIdentity: syncChangeset.nodeIdentity
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
}
|
|
@@ -140,7 +140,7 @@ export class ChangeSetHelper {
|
|
|
140
140
|
await this._eventBusComponent.publish(SynchronisedStorageTopics.RemoteItemRemove, {
|
|
141
141
|
storageKey: syncChangeset.storageKey,
|
|
142
142
|
id: change.id,
|
|
143
|
-
nodeId: syncChangeset.
|
|
143
|
+
nodeId: syncChangeset.nodeIdentity
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
146
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeSetHelper.js","sourceRoot":"","sources":["../../../src/helpers/changeSetHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { BaseError, Converter, Is, ObjectHelper, RandomHelper } 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 ISyncChangeSet,\n\ttype ISyncItemRemove,\n\ttype ISyncItemSet,\n\ttype ISyncReset,\n\tSyncChangeOperation,\n\tSynchronisedStorageTopics,\n\ttype SyncNodeIdMode\n} from \"@twin.org/synchronised-storage-models\";\nimport type { BlobStorageHelper } from \"./blobStorageHelper.js\";\n\n/**\n * Class for performing change set operations.\n */\nexport class ChangeSetHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<ChangeSetHelper>();\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 to use for remote sync states.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\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 * Create a new instance of ChangeSetHelper.\n\t * @param logging The logging component to use for logging.\n\t * @param eventBusComponent The event bus component to use for events.\n\t * @param blobStorageHelper The blob storage component to use for remote sync states.\n\t */\n\tconstructor(\n\t\tlogging: ILoggingComponent | undefined,\n\t\teventBusComponent: IEventBusComponent,\n\t\tblobStorageHelper: BlobStorageHelper\n\t) {\n\t\tthis._logging = logging;\n\t\tthis._eventBusComponent = eventBusComponent;\n\t\tthis._blobStorageHelper = blobStorageHelper;\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 * Get a changeset.\n\t * @param changeSetStorageId The id of the sync changeset to apply.\n\t * @returns The changeset if it was verified.\n\t */\n\tpublic async getChangeset(changeSetStorageId: string): Promise<ISyncChangeSet | undefined> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"getChangeSet\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tconst syncChangeSet =\n\t\t\t\tawait this._blobStorageHelper.loadBlob<ISyncChangeSet>(changeSetStorageId);\n\n\t\t\treturn syncChangeSet;\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\tmessage: \"getChangeSetError\",\n\t\t\t\tdata: {\n\t\t\t\t\tchangeSetStorageId\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: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"getChangeSetEmpty\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Apply a sync changeset.\n\t * @param changeSetStorageId The id of the sync changeset to apply.\n\t * @returns The changeset if it existed.\n\t */\n\tpublic async getAndApplyChangeset(\n\t\tchangeSetStorageId: string\n\t): Promise<ISyncChangeSet | undefined> {\n\t\tconst syncChangeset = await this.getChangeset(changeSetStorageId);\n\n\t\t// Only apply changesets from other nodes, we don't want to overwrite\n\t\t// any changes we have made to local entity storage\n\t\tif (!Is.empty(syncChangeset) && syncChangeset.nodeId !== this._nodeId) {\n\t\t\tawait this.applyChangeset(syncChangeset);\n\t\t}\n\n\t\treturn syncChangeset;\n\t}\n\n\t/**\n\t * Apply a sync changeset.\n\t * @param syncChangeset The sync changeset to apply.\n\t * @returns Nothing.\n\t */\n\tpublic async applyChangeset(syncChangeset: ISyncChangeSet): Promise<void> {\n\t\tif (Is.arrayValue(syncChangeset.changes)) {\n\t\t\tfor (const change of syncChangeset.changes) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"changeSetApplyingChange\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: change.operation,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tswitch (change.operation) {\n\t\t\t\t\tcase SyncChangeOperation.Set:\n\t\t\t\t\t\tif (!Is.empty(change.entity)) {\n\t\t\t\t\t\t\t// The id was stripped from the entity as it is part of the operation\n\t\t\t\t\t\t\t// we make sure we reinstate it in the publish\n\t\t\t\t\t\t\t// Also the node identity was stripped when stored in the changeset\n\t\t\t\t\t\t\t// as the changeset is signed with the node identity.\n\t\t\t\t\t\t\t// so we need to restore it here.\n\t\t\t\t\t\t\tawait this._eventBusComponent.publish<ISyncItemSet>(\n\t\t\t\t\t\t\t\tSynchronisedStorageTopics.RemoteItemSet,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstorageKey: syncChangeset.storageKey,\n\t\t\t\t\t\t\t\t\tentity: {\n\t\t\t\t\t\t\t\t\t\t...change.entity,\n\t\t\t\t\t\t\t\t\t\tid: change.id,\n\t\t\t\t\t\t\t\t\t\tnodeId: syncChangeset.nodeId\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SyncChangeOperation.Delete:\n\t\t\t\t\t\tif (!Is.empty(change.id)) {\n\t\t\t\t\t\t\tawait this._eventBusComponent.publish<ISyncItemRemove>(\n\t\t\t\t\t\t\t\tSynchronisedStorageTopics.RemoteItemRemove,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstorageKey: syncChangeset.storageKey,\n\t\t\t\t\t\t\t\t\tid: change.id,\n\t\t\t\t\t\t\t\t\tnodeId: syncChangeset.nodeId\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Store the changeset.\n\t * @param syncChangeSet The sync change set to store.\n\t * @returns The id of the change set.\n\t */\n\tpublic async storeChangeSet(syncChangeSet: ISyncChangeSet): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"changeSetStoring\",\n\t\t\tdata: {\n\t\t\t\tid: syncChangeSet.id\n\t\t\t}\n\t\t});\n\n\t\treturn this._blobStorageHelper.saveBlob(syncChangeSet);\n\t}\n\n\t/**\n\t * Copy a change set.\n\t * @param syncChangeSet The sync changeset to copy.\n\t * @returns The id of the updated change set.\n\t */\n\tpublic async copyChangeset(syncChangeSet: ISyncChangeSet): Promise<\n\t\t| {\n\t\t\t\tsyncChangeSet: ISyncChangeSet;\n\t\t\t\tchangeSetStorageId: string;\n\t\t }\n\t\t| undefined\n\t> {\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\tmessage: \"copyChangeSet\",\n\t\t\t\tdata: {\n\t\t\t\t\tchangeSetStorageId: syncChangeSet.id\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Allocate a new id to the changeset copy\n\t\t\tconst copy = ObjectHelper.clone(syncChangeSet);\n\t\t\tcopy.id = Converter.bytesToHex(RandomHelper.generate(32));\n\n\t\t\t// Store the copy\n\t\t\treturn {\n\t\t\t\tsyncChangeSet: copy,\n\t\t\t\tchangeSetStorageId: await this.storeChangeSet(copy)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Reset the storage for a given storage key.\n\t * @param storageKey The key of the storage to reset.\n\t * @param resetMode The reset mode, this will use the nodeId in the entities to determine which are local/remote.\n\t * @returns Nothing.\n\t */\n\tpublic async reset(storageKey: string, resetMode: SyncNodeIdMode): Promise<void> {\n\t\t// If we are applying a consolidation we need to reset the local db\n\t\t// but keep any entries from the local node, as they might have been updated\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"storageReset\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\t\tawait this._eventBusComponent.publish<ISyncReset>(SynchronisedStorageTopics.Reset, {\n\t\t\tstorageKey,\n\t\t\tresetMode\n\t\t});\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"changeSetHelper.js","sourceRoot":"","sources":["../../../src/helpers/changeSetHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { BaseError, Converter, Is, ObjectHelper, RandomHelper } 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 ISyncChangeSet,\n\ttype ISyncItemRemove,\n\ttype ISyncItemSet,\n\ttype ISyncReset,\n\tSyncChangeOperation,\n\tSynchronisedStorageTopics,\n\ttype SyncNodeIdMode\n} from \"@twin.org/synchronised-storage-models\";\nimport type { BlobStorageHelper } from \"./blobStorageHelper.js\";\n\n/**\n * Class for performing change set operations.\n */\nexport class ChangeSetHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<ChangeSetHelper>();\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 to use for remote sync states.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageHelper: BlobStorageHelper;\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 * Create a new instance of ChangeSetHelper.\n\t * @param logging The logging component to use for logging.\n\t * @param eventBusComponent The event bus component to use for events.\n\t * @param blobStorageHelper The blob storage component to use for remote sync states.\n\t */\n\tconstructor(\n\t\tlogging: ILoggingComponent | undefined,\n\t\teventBusComponent: IEventBusComponent,\n\t\tblobStorageHelper: BlobStorageHelper\n\t) {\n\t\tthis._logging = logging;\n\t\tthis._eventBusComponent = eventBusComponent;\n\t\tthis._blobStorageHelper = blobStorageHelper;\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 * Get a changeset.\n\t * @param changeSetStorageId The id of the sync changeset to apply.\n\t * @returns The changeset if it was verified.\n\t */\n\tpublic async getChangeset(changeSetStorageId: string): Promise<ISyncChangeSet | undefined> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"getChangeSet\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tconst syncChangeSet =\n\t\t\t\tawait this._blobStorageHelper.loadBlob<ISyncChangeSet>(changeSetStorageId);\n\n\t\t\treturn syncChangeSet;\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"warn\",\n\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\tmessage: \"getChangeSetError\",\n\t\t\t\tdata: {\n\t\t\t\t\tchangeSetStorageId\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: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"getChangeSetEmpty\",\n\t\t\tdata: {\n\t\t\t\tchangeSetStorageId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Apply a sync changeset.\n\t * @param changeSetStorageId The id of the sync changeset to apply.\n\t * @returns The changeset if it existed.\n\t */\n\tpublic async getAndApplyChangeset(\n\t\tchangeSetStorageId: string\n\t): Promise<ISyncChangeSet | undefined> {\n\t\tconst syncChangeset = await this.getChangeset(changeSetStorageId);\n\n\t\t// Only apply changesets from other nodes, we don't want to overwrite\n\t\t// any changes we have made to local entity storage\n\t\tif (!Is.empty(syncChangeset) && syncChangeset.nodeIdentity !== this._nodeId) {\n\t\t\tawait this.applyChangeset(syncChangeset);\n\t\t}\n\n\t\treturn syncChangeset;\n\t}\n\n\t/**\n\t * Apply a sync changeset.\n\t * @param syncChangeset The sync changeset to apply.\n\t * @returns Nothing.\n\t */\n\tpublic async applyChangeset(syncChangeset: ISyncChangeSet): Promise<void> {\n\t\tif (Is.arrayValue(syncChangeset.changes)) {\n\t\t\tfor (const change of syncChangeset.changes) {\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"changeSetApplyingChange\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: change.operation,\n\t\t\t\t\t\tid: change.id\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tswitch (change.operation) {\n\t\t\t\t\tcase SyncChangeOperation.Set:\n\t\t\t\t\t\tif (!Is.empty(change.entity)) {\n\t\t\t\t\t\t\t// The id was stripped from the entity as it is part of the operation\n\t\t\t\t\t\t\t// we make sure we reinstate it in the publish\n\t\t\t\t\t\t\t// Also the node identity was stripped when stored in the changeset\n\t\t\t\t\t\t\t// as the changeset is signed with the node identity.\n\t\t\t\t\t\t\t// so we need to restore it here.\n\t\t\t\t\t\t\tawait this._eventBusComponent.publish<ISyncItemSet>(\n\t\t\t\t\t\t\t\tSynchronisedStorageTopics.RemoteItemSet,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstorageKey: syncChangeset.storageKey,\n\t\t\t\t\t\t\t\t\tentity: {\n\t\t\t\t\t\t\t\t\t\t...change.entity,\n\t\t\t\t\t\t\t\t\t\tid: change.id,\n\t\t\t\t\t\t\t\t\t\tnodeIdentity: syncChangeset.nodeIdentity\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SyncChangeOperation.Delete:\n\t\t\t\t\t\tif (!Is.empty(change.id)) {\n\t\t\t\t\t\t\tawait this._eventBusComponent.publish<ISyncItemRemove>(\n\t\t\t\t\t\t\t\tSynchronisedStorageTopics.RemoteItemRemove,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstorageKey: syncChangeset.storageKey,\n\t\t\t\t\t\t\t\t\tid: change.id,\n\t\t\t\t\t\t\t\t\tnodeId: syncChangeset.nodeIdentity\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Store the changeset.\n\t * @param syncChangeSet The sync change set to store.\n\t * @returns The id of the change set.\n\t */\n\tpublic async storeChangeSet(syncChangeSet: ISyncChangeSet): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"changeSetStoring\",\n\t\t\tdata: {\n\t\t\t\tid: syncChangeSet.id\n\t\t\t}\n\t\t});\n\n\t\treturn this._blobStorageHelper.saveBlob(syncChangeSet);\n\t}\n\n\t/**\n\t * Copy a change set.\n\t * @param syncChangeSet The sync changeset to copy.\n\t * @returns The id of the updated change set.\n\t */\n\tpublic async copyChangeset(syncChangeSet: ISyncChangeSet): Promise<\n\t\t| {\n\t\t\t\tsyncChangeSet: ISyncChangeSet;\n\t\t\t\tchangeSetStorageId: string;\n\t\t }\n\t\t| undefined\n\t> {\n\t\tif (Is.stringValue(this._nodeId)) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\t\tmessage: \"copyChangeSet\",\n\t\t\t\tdata: {\n\t\t\t\t\tchangeSetStorageId: syncChangeSet.id\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Allocate a new id to the changeset copy\n\t\t\tconst copy = ObjectHelper.clone(syncChangeSet);\n\t\t\tcopy.id = Converter.bytesToHex(RandomHelper.generate(32));\n\n\t\t\t// Store the copy\n\t\t\treturn {\n\t\t\t\tsyncChangeSet: copy,\n\t\t\t\tchangeSetStorageId: await this.storeChangeSet(copy)\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Reset the storage for a given storage key.\n\t * @param storageKey The key of the storage to reset.\n\t * @param resetMode The reset mode, this will use the nodeId in the entities to determine which are local/remote.\n\t * @returns Nothing.\n\t */\n\tpublic async reset(storageKey: string, resetMode: SyncNodeIdMode): Promise<void> {\n\t\t// If we are applying a consolidation we need to reset the local db\n\t\t// but keep any entries from the local node, as they might have been updated\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: ChangeSetHelper.CLASS_NAME,\n\t\t\tmessage: \"storageReset\",\n\t\t\tdata: {\n\t\t\t\tstorageKey\n\t\t\t}\n\t\t});\n\t\tawait this._eventBusComponent.publish<ISyncReset>(SynchronisedStorageTopics.Reset, {\n\t\t\tstorageKey,\n\t\t\tresetMode\n\t\t});\n\t}\n}\n"]}
|
|
@@ -187,7 +187,7 @@ export class RemoteSyncStateHelper {
|
|
|
187
187
|
ObjectHelper.propertyDelete(change.entity, "id");
|
|
188
188
|
// Remove the node identity as the changeset has this stored at the top level
|
|
189
189
|
// and we do not want to store it in the change itself to reduce redundancy
|
|
190
|
-
ObjectHelper.propertyDelete(change.entity, "
|
|
190
|
+
ObjectHelper.propertyDelete(change.entity, "nodeIdentity");
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
const now = new Date(Date.now()).toISOString();
|
|
@@ -199,7 +199,7 @@ export class RemoteSyncStateHelper {
|
|
|
199
199
|
dateModified: now,
|
|
200
200
|
storageKey,
|
|
201
201
|
changes,
|
|
202
|
-
|
|
202
|
+
nodeIdentity: this._nodeId
|
|
203
203
|
};
|
|
204
204
|
try {
|
|
205
205
|
// If this is a trusted node, we also store the changeset
|
|
@@ -476,7 +476,7 @@ export class RemoteSyncStateHelper {
|
|
|
476
476
|
id: change.id
|
|
477
477
|
})),
|
|
478
478
|
storageKey: response.storageKey,
|
|
479
|
-
|
|
479
|
+
nodeIdentity: this._nodeId
|
|
480
480
|
};
|
|
481
481
|
// Store the changeset in the blob storage
|
|
482
482
|
const changeSetStorageId = await this._changeSetHelper.storeChangeSet(syncChangeSet);
|
|
@@ -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, \"nodeId\");\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\tnodeId: 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\tnodeId: 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 */\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"]}
|
|
@@ -43,7 +43,7 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
|
|
|
43
43
|
id: "0909090909090909090909090909090909090909090909090909090909090909",
|
|
44
44
|
dateCreated: "2025-05-29T01:00:00.000Z",
|
|
45
45
|
dateModified: "2025-05-29T01:00:00.000Z",
|
|
46
|
-
|
|
46
|
+
nodeIdentity: "did:entity-storage:0xd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2",
|
|
47
47
|
changes: [
|
|
48
48
|
{
|
|
49
49
|
entity: {
|
|
@@ -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,
|
|
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};\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};\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"]}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.8](https://github.com/twinfoundation/synchronised-storage/compare/synchronised-storage-service-v0.0.3-next.7...synchronised-storage-service-v0.0.3-next.8) (2026-02-25)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add ts-to-jsonld-context tool ([16d7677](https://github.com/twinfoundation/synchronised-storage/commit/16d76776e7e3f75e6c4fb9f88cb32fed2967c4b6))
|
|
9
|
+
* update schemas ([7566c48](https://github.com/twinfoundation/synchronised-storage/commit/7566c4860baad5ead4327ac19cb5b647e63f2ca3))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Dependencies
|
|
13
|
+
|
|
14
|
+
* The following workspace dependencies were updated
|
|
15
|
+
* dependencies
|
|
16
|
+
* @twin.org/synchronised-storage-models bumped from 0.0.3-next.7 to 0.0.3-next.8
|
|
17
|
+
|
|
18
|
+
## [0.0.3-next.7](https://github.com/twinfoundation/synchronised-storage/compare/synchronised-storage-service-v0.0.3-next.6...synchronised-storage-service-v0.0.3-next.7) (2026-01-28)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* json ld contexts ([#36](https://github.com/twinfoundation/synchronised-storage/issues/36)) ([3a87a9f](https://github.com/twinfoundation/synchronised-storage/commit/3a87a9fb16d21baf672e44b4e8914cf1937b1d6a))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Dependencies
|
|
27
|
+
|
|
28
|
+
* The following workspace dependencies were updated
|
|
29
|
+
* dependencies
|
|
30
|
+
* @twin.org/synchronised-storage-models bumped from 0.0.3-next.6 to 0.0.3-next.7
|
|
31
|
+
|
|
3
32
|
## [0.0.3-next.6](https://github.com/twinfoundation/synchronised-storage/compare/synchronised-storage-service-v0.0.3-next.5...synchronised-storage-service-v0.0.3-next.6) (2026-01-22)
|
|
4
33
|
|
|
5
34
|
|
package/docs/open-api/spec.json
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"id": "0909090909090909090909090909090909090909090909090909090909090909",
|
|
66
66
|
"dateCreated": "2025-05-29T01:00:00.000Z",
|
|
67
67
|
"dateModified": "2025-05-29T01:00:00.000Z",
|
|
68
|
-
"
|
|
68
|
+
"nodeIdentity": "did:entity-storage:0xd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2",
|
|
69
69
|
"changes": [
|
|
70
70
|
{
|
|
71
71
|
"entity": {
|
|
@@ -259,7 +259,6 @@
|
|
|
259
259
|
"name",
|
|
260
260
|
"message"
|
|
261
261
|
],
|
|
262
|
-
"additionalProperties": false,
|
|
263
262
|
"description": "Model to describe serialized error."
|
|
264
263
|
},
|
|
265
264
|
"SyncChange": {
|
|
@@ -280,7 +279,6 @@
|
|
|
280
279
|
"operation",
|
|
281
280
|
"id"
|
|
282
281
|
],
|
|
283
|
-
"additionalProperties": false,
|
|
284
282
|
"description": "The object definition for a sync change."
|
|
285
283
|
},
|
|
286
284
|
"SyncChangeOperation": {
|
|
@@ -317,26 +315,26 @@
|
|
|
317
315
|
},
|
|
318
316
|
"storageKey": {
|
|
319
317
|
"type": "string",
|
|
320
|
-
"description": "The storage key of the change set. This is used to identify the entities being synchronised."
|
|
318
|
+
"description": "The storage key of the change set. This is used to identify the entities being synchronised. json-ld type:schema:identifier"
|
|
321
319
|
},
|
|
322
320
|
"dateCreated": {
|
|
323
321
|
"type": "string",
|
|
324
|
-
"description": "The date the change set was created."
|
|
322
|
+
"description": "The date the change set was created. json-ld namespace:schema"
|
|
325
323
|
},
|
|
326
324
|
"dateModified": {
|
|
327
325
|
"type": "string",
|
|
328
|
-
"description": "The date the change set was last modified."
|
|
326
|
+
"description": "The date the change set was last modified. json-ld namespace:schema"
|
|
329
327
|
},
|
|
330
|
-
"
|
|
328
|
+
"nodeIdentity": {
|
|
331
329
|
"type": "string",
|
|
332
|
-
"description": "The identity of the node that created the change set."
|
|
330
|
+
"description": "The identity of the node that created the change set. json-ld namespace:twin-common"
|
|
333
331
|
},
|
|
334
332
|
"changes": {
|
|
335
333
|
"type": "array",
|
|
336
334
|
"items": {
|
|
337
335
|
"$ref": "#/components/schemas/SyncChange"
|
|
338
336
|
},
|
|
339
|
-
"description": "The changes to apply after a snapshot."
|
|
337
|
+
"description": "The changes to apply after a snapshot. json-ld type:json"
|
|
340
338
|
}
|
|
341
339
|
},
|
|
342
340
|
"required": [
|
|
@@ -346,10 +344,9 @@
|
|
|
346
344
|
"storageKey",
|
|
347
345
|
"dateCreated",
|
|
348
346
|
"dateModified",
|
|
349
|
-
"
|
|
347
|
+
"nodeIdentity",
|
|
350
348
|
"changes"
|
|
351
349
|
],
|
|
352
|
-
"additionalProperties": false,
|
|
353
350
|
"description": "The object definition for a sync change set."
|
|
354
351
|
},
|
|
355
352
|
"SyncDecryptionKeyResponse": {
|
|
@@ -363,7 +360,6 @@
|
|
|
363
360
|
"required": [
|
|
364
361
|
"decryptionKey"
|
|
365
362
|
],
|
|
366
|
-
"additionalProperties": false,
|
|
367
363
|
"description": "The body of the response."
|
|
368
364
|
},
|
|
369
365
|
"SynchronisedEntityCore": {
|
|
@@ -371,13 +367,12 @@
|
|
|
371
367
|
"properties": {
|
|
372
368
|
"dateModified": {
|
|
373
369
|
"type": "string",
|
|
374
|
-
"description": "The date the entry was modified."
|
|
370
|
+
"description": "The date the entry was modified. json-ld namespace:schema"
|
|
375
371
|
}
|
|
376
372
|
},
|
|
377
373
|
"required": [
|
|
378
374
|
"dateModified"
|
|
379
375
|
],
|
|
380
|
-
"additionalProperties": false,
|
|
381
376
|
"description": "The base definition for synchronised entries."
|
|
382
377
|
}
|
|
383
378
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/synchronised-storage-service",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.8",
|
|
4
4
|
"description": "Synchronised storage contract implementation and REST endpoint definitions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@twin.org/nameof": "next",
|
|
29
29
|
"@twin.org/standards-w3c-did": "next",
|
|
30
30
|
"@twin.org/standards-w3c-odrl": "next",
|
|
31
|
-
"@twin.org/synchronised-storage-models": "0.0.3-next.
|
|
31
|
+
"@twin.org/synchronised-storage-models": "0.0.3-next.8",
|
|
32
32
|
"@twin.org/trust-models": "next",
|
|
33
33
|
"@twin.org/verifiable-storage-models": "next",
|
|
34
34
|
"@twin.org/web": "next"
|