@twin.org/synchronised-storage-service 0.0.3-next.1 → 0.0.3-next.10

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.
Files changed (29) hide show
  1. package/README.md +2 -2
  2. package/dist/es/helpers/blobStorageHelper.js +14 -2
  3. package/dist/es/helpers/blobStorageHelper.js.map +1 -1
  4. package/dist/es/helpers/changeSetHelper.js +3 -3
  5. package/dist/es/helpers/changeSetHelper.js.map +1 -1
  6. package/dist/es/helpers/remoteSyncStateHelper.js +5 -5
  7. package/dist/es/helpers/remoteSyncStateHelper.js.map +1 -1
  8. package/dist/es/models/ISynchronisedStorageServiceConfig.js.map +1 -1
  9. package/dist/es/models/ISynchronisedStorageServiceConstructorOptions.js.map +1 -1
  10. package/dist/es/synchronisedStorageRoutes.js +7 -18
  11. package/dist/es/synchronisedStorageRoutes.js.map +1 -1
  12. package/dist/es/synchronisedStorageService.js +33 -72
  13. package/dist/es/synchronisedStorageService.js.map +1 -1
  14. package/dist/types/helpers/blobStorageHelper.d.ts +5 -0
  15. package/dist/types/models/ISynchronisedStorageServiceConfig.d.ts +4 -0
  16. package/dist/types/models/ISynchronisedStorageServiceConstructorOptions.d.ts +3 -4
  17. package/dist/types/synchronisedStorageService.d.ts +4 -5
  18. package/docs/changelog.md +128 -1
  19. package/docs/examples.md +80 -1
  20. package/docs/open-api/spec.json +15 -24
  21. package/docs/reference/classes/SyncSnapshotEntry.md +12 -12
  22. package/docs/reference/classes/SynchronisedStorageService.md +14 -14
  23. package/docs/reference/interfaces/ISyncPointerStore.md +2 -2
  24. package/docs/reference/interfaces/ISyncSnapshot.md +7 -7
  25. package/docs/reference/interfaces/ISyncState.md +3 -3
  26. package/docs/reference/interfaces/ISynchronisedStorageServiceConfig.md +19 -11
  27. package/docs/reference/interfaces/ISynchronisedStorageServiceConstructorOptions.md +21 -22
  28. package/locales/en.json +1 -4
  29. package/package.json +4 -7
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # TWIN Synchronised Storage Service
1
+ # Synchronised Storage Service
2
2
 
3
- Synchronised storage contract implementation and REST endpoint definitions.
3
+ This package provides the synchronisation service layer responsible for tracking local and remote change state, scheduling update cycles, and handling trusted interactions around key and change propagation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -33,6 +33,11 @@ export class BlobStorageHelper {
33
33
  * @internal
34
34
  */
35
35
  _isTrustedNode;
36
+ /**
37
+ * The node id of this node.
38
+ * @internal
39
+ */
40
+ _nodeId;
36
41
  /**
37
42
  * Create a new instance of BlobStorageHelper.
38
43
  * @param logging The logging component to use for logging.
@@ -48,6 +53,13 @@ export class BlobStorageHelper {
48
53
  this._blobStorageEncryptionKeyId = blobStorageEncryptionKeyId;
49
54
  this._isTrustedNode = isTrustedNode;
50
55
  }
56
+ /**
57
+ * Set the node id of this node.
58
+ * @param nodeId The node id to set.
59
+ */
60
+ setNodeId(nodeId) {
61
+ this._nodeId = nodeId;
62
+ }
51
63
  /**
52
64
  * Load a blob from storage.
53
65
  * @param blobId The id of the blob to apply.
@@ -65,7 +77,7 @@ export class BlobStorageHelper {
65
77
  try {
66
78
  const encryptedBlob = await this._blobStorageConnector.get(blobId);
67
79
  if (Is.uint8Array(encryptedBlob)) {
68
- const compressedBlob = await this._vaultConnector.decrypt(this._blobStorageEncryptionKeyId, VaultEncryptionType.ChaCha20Poly1305, encryptedBlob);
80
+ const compressedBlob = await this._vaultConnector.decrypt(`${this._nodeId}/${this._blobStorageEncryptionKeyId}`, VaultEncryptionType.ChaCha20Poly1305, encryptedBlob);
69
81
  const decompressedBlob = await Compression.decompress(compressedBlob, CompressionType.Gzip);
70
82
  await this._logging?.log({
71
83
  level: "info",
@@ -113,7 +125,7 @@ export class BlobStorageHelper {
113
125
  throw new GeneralError(BlobStorageHelper.CLASS_NAME, "notTrustedNode");
114
126
  }
115
127
  const compressedBlob = await Compression.compress(ObjectHelper.toBytes(blob), CompressionType.Gzip);
116
- const encryptedBlob = await this._vaultConnector.encrypt(this._blobStorageEncryptionKeyId, VaultEncryptionType.ChaCha20Poly1305, compressedBlob);
128
+ const encryptedBlob = await this._vaultConnector.encrypt(`${this._nodeId}/${this._blobStorageEncryptionKeyId}`, VaultEncryptionType.ChaCha20Poly1305, compressedBlob);
117
129
  try {
118
130
  const blobId = await this._blobStorageConnector.set(encryptedBlob);
119
131
  await this._logging?.log({
@@ -1 +1 @@
1
- {"version":3,"file":"blobStorageHelper.js","sourceRoot":"","sources":["../../../src/helpers/blobStorageHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IBlobStorageConnector } from \"@twin.org/blob-storage-models\";\nimport {\n\tBaseError,\n\tCompression,\n\tCompressionType,\n\tGeneralError,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { type IVaultConnector, VaultEncryptionType } from \"@twin.org/vault-models\";\n\n/**\n * Class for performing blob storage operations.\n */\nexport class BlobStorageHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<BlobStorageHelper>();\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 vault connector.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector: IVaultConnector;\n\n\t/**\n\t * The blob storage connector to use.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageConnector: IBlobStorageConnector;\n\n\t/**\n\t * The id of the vault key to use for encrypting/decrypting blobs.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageEncryptionKeyId: string;\n\n\t/**\n\t * Is this a trusted node.\n\t * @internal\n\t */\n\tprivate readonly _isTrustedNode: boolean;\n\n\t/**\n\t * Create a new instance of BlobStorageHelper.\n\t * @param logging The logging component to use for logging.\n\t * @param vaultConnector The vault connector to use for for the encryption key.\n\t * @param blobStorageConnector The blob storage component to use.\n\t * @param blobStorageEncryptionKeyId The id of the vault key to use for encrypting/decrypting blobs.\n\t * @param isTrustedNode Is this a trusted node.\n\t */\n\tconstructor(\n\t\tlogging: ILoggingComponent | undefined,\n\t\tvaultConnector: IVaultConnector,\n\t\tblobStorageConnector: IBlobStorageConnector,\n\t\tblobStorageEncryptionKeyId: string,\n\t\tisTrustedNode: boolean\n\t) {\n\t\tthis._logging = logging;\n\t\tthis._vaultConnector = vaultConnector;\n\t\tthis._blobStorageConnector = blobStorageConnector;\n\t\tthis._blobStorageEncryptionKeyId = blobStorageEncryptionKeyId;\n\t\tthis._isTrustedNode = isTrustedNode;\n\t}\n\n\t/**\n\t * Load a blob from storage.\n\t * @param blobId The id of the blob to apply.\n\t * @returns The blob.\n\t */\n\tpublic async loadBlob<T>(blobId: string): Promise<T | undefined> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"loadBlob\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tconst encryptedBlob = await this._blobStorageConnector.get(blobId);\n\n\t\t\tif (Is.uint8Array(encryptedBlob)) {\n\t\t\t\tconst compressedBlob = await this._vaultConnector.decrypt(\n\t\t\t\t\tthis._blobStorageEncryptionKeyId,\n\t\t\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\t\t\tencryptedBlob\n\t\t\t\t);\n\n\t\t\t\tconst decompressedBlob = await Compression.decompress(compressedBlob, CompressionType.Gzip);\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"loadedBlob\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tblobId\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn ObjectHelper.fromBytes<T>(decompressedBlob);\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: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"loadBlobFailed\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\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: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"loadBlobEmpty\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Save a blob.\n\t * @param blob The blob to save.\n\t * @returns The id of the blob.\n\t */\n\tpublic async saveBlob<T>(blob: T): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"saveBlob\"\n\t\t});\n\n\t\tif (!this._isTrustedNode) {\n\t\t\tthrow new GeneralError(BlobStorageHelper.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tconst compressedBlob = await Compression.compress(\n\t\t\tObjectHelper.toBytes(blob),\n\t\t\tCompressionType.Gzip\n\t\t);\n\n\t\tconst encryptedBlob = await this._vaultConnector.encrypt(\n\t\t\tthis._blobStorageEncryptionKeyId,\n\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\tcompressedBlob\n\t\t);\n\n\t\ttry {\n\t\t\tconst blobId = await this._blobStorageConnector.set(encryptedBlob);\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"savedBlob\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn blobId;\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"saveBlobFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Remove a blob from storage.\n\t * @param blobId The id of the blob to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBlob(blobId: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"removeBlob\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tawait this._blobStorageConnector.remove(blobId);\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"removedBlob\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\n\t\t\t\t}\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: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"removeBlobFailed\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\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: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"removeBlobEmpty\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"blobStorageHelper.js","sourceRoot":"","sources":["../../../src/helpers/blobStorageHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IBlobStorageConnector } from \"@twin.org/blob-storage-models\";\nimport {\n\tBaseError,\n\tCompression,\n\tCompressionType,\n\tGeneralError,\n\tIs,\n\tObjectHelper\n} from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { type IVaultConnector, VaultEncryptionType } from \"@twin.org/vault-models\";\n\n/**\n * Class for performing blob storage operations.\n */\nexport class BlobStorageHelper {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<BlobStorageHelper>();\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 vault connector.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector: IVaultConnector;\n\n\t/**\n\t * The blob storage connector to use.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageConnector: IBlobStorageConnector;\n\n\t/**\n\t * The id of the vault key to use for encrypting/decrypting blobs.\n\t * @internal\n\t */\n\tprivate readonly _blobStorageEncryptionKeyId: string;\n\n\t/**\n\t * Is this a trusted node.\n\t * @internal\n\t */\n\tprivate readonly _isTrustedNode: boolean;\n\n\t/**\n\t * The node id of this node.\n\t * @internal\n\t */\n\tprivate _nodeId?: string;\n\n\t/**\n\t * Create a new instance of BlobStorageHelper.\n\t * @param logging The logging component to use for logging.\n\t * @param vaultConnector The vault connector to use for for the encryption key.\n\t * @param blobStorageConnector The blob storage component to use.\n\t * @param blobStorageEncryptionKeyId The id of the vault key to use for encrypting/decrypting blobs.\n\t * @param isTrustedNode Is this a trusted node.\n\t */\n\tconstructor(\n\t\tlogging: ILoggingComponent | undefined,\n\t\tvaultConnector: IVaultConnector,\n\t\tblobStorageConnector: IBlobStorageConnector,\n\t\tblobStorageEncryptionKeyId: string,\n\t\tisTrustedNode: boolean\n\t) {\n\t\tthis._logging = logging;\n\t\tthis._vaultConnector = vaultConnector;\n\t\tthis._blobStorageConnector = blobStorageConnector;\n\t\tthis._blobStorageEncryptionKeyId = blobStorageEncryptionKeyId;\n\t\tthis._isTrustedNode = isTrustedNode;\n\t}\n\n\t/**\n\t * Set the node id of this node.\n\t * @param nodeId The node id to set.\n\t */\n\tpublic setNodeId(nodeId: string): void {\n\t\tthis._nodeId = nodeId;\n\t}\n\n\t/**\n\t * Load a blob from storage.\n\t * @param blobId The id of the blob to apply.\n\t * @returns The blob.\n\t */\n\tpublic async loadBlob<T>(blobId: string): Promise<T | undefined> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"loadBlob\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tconst encryptedBlob = await this._blobStorageConnector.get(blobId);\n\n\t\t\tif (Is.uint8Array(encryptedBlob)) {\n\t\t\t\tconst compressedBlob = await this._vaultConnector.decrypt(\n\t\t\t\t\t`${this._nodeId}/${this._blobStorageEncryptionKeyId}`,\n\t\t\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\t\t\tencryptedBlob\n\t\t\t\t);\n\n\t\t\t\tconst decompressedBlob = await Compression.decompress(compressedBlob, CompressionType.Gzip);\n\t\t\t\tawait this._logging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\t\tmessage: \"loadedBlob\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tblobId\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn ObjectHelper.fromBytes<T>(decompressedBlob);\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: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"loadBlobFailed\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\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: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"loadBlobEmpty\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Save a blob.\n\t * @param blob The blob to save.\n\t * @returns The id of the blob.\n\t */\n\tpublic async saveBlob<T>(blob: T): Promise<string> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"saveBlob\"\n\t\t});\n\n\t\tif (!this._isTrustedNode) {\n\t\t\tthrow new GeneralError(BlobStorageHelper.CLASS_NAME, \"notTrustedNode\");\n\t\t}\n\n\t\tconst compressedBlob = await Compression.compress(\n\t\t\tObjectHelper.toBytes(blob),\n\t\t\tCompressionType.Gzip\n\t\t);\n\n\t\tconst encryptedBlob = await this._vaultConnector.encrypt(\n\t\t\t`${this._nodeId}/${this._blobStorageEncryptionKeyId}`,\n\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\tcompressedBlob\n\t\t);\n\n\t\ttry {\n\t\t\tconst blobId = await this._blobStorageConnector.set(encryptedBlob);\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"savedBlob\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn blobId;\n\t\t} catch (error) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"saveBlobFailed\",\n\t\t\t\terror: BaseError.fromError(error)\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Remove a blob from storage.\n\t * @param blobId The id of the blob to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeBlob(blobId: string): Promise<void> {\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"removeBlob\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\tawait this._blobStorageConnector.remove(blobId);\n\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"removedBlob\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\n\t\t\t\t}\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: BlobStorageHelper.CLASS_NAME,\n\t\t\t\tmessage: \"removeBlobFailed\",\n\t\t\t\tdata: {\n\t\t\t\t\tblobId\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: BlobStorageHelper.CLASS_NAME,\n\t\t\tmessage: \"removeBlobEmpty\",\n\t\t\tdata: {\n\t\t\t\tblobId\n\t\t\t}\n\t\t});\n\t}\n}\n"]}
@@ -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.nodeId !== this._nodeId) {
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
- nodeId: syncChangeset.nodeId
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.nodeId
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,19 +187,19 @@ 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, "nodeId");
190
+ ObjectHelper.propertyDelete(change.entity, "nodeIdentity");
191
191
  }
192
192
  }
193
193
  const now = new Date(Date.now()).toISOString();
194
194
  const syncChangeSet = {
195
- "@context": SynchronisedStorageContexts.ContextRoot,
195
+ "@context": SynchronisedStorageContexts.Context,
196
196
  type: SynchronisedStorageTypes.ChangeSet,
197
197
  id: Converter.bytesToHex(RandomHelper.generate(32)),
198
198
  dateCreated: now,
199
199
  dateModified: now,
200
200
  storageKey,
201
201
  changes,
202
- nodeId: this._nodeId
202
+ nodeIdentity: this._nodeId
203
203
  };
204
204
  try {
205
205
  // If this is a trusted node, we also store the changeset
@@ -466,7 +466,7 @@ export class RemoteSyncStateHelper {
466
466
  const now = new Date(Date.now()).toISOString();
467
467
  // Create a new snapshot entry for the current batch
468
468
  const syncChangeSet = {
469
- "@context": SynchronisedStorageContexts.ContextRoot,
469
+ "@context": SynchronisedStorageContexts.Context,
470
470
  type: SynchronisedStorageTypes.ChangeSet,
471
471
  id: Converter.bytesToHex(RandomHelper.generate(32)),
472
472
  dateCreated: now,
@@ -476,7 +476,7 @@ export class RemoteSyncStateHelper {
476
476
  id: change.id
477
477
  })),
478
478
  storageKey: response.storageKey,
479
- nodeId: this._nodeId
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.ContextRoot,\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.ContextRoot,\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ISynchronisedStorageServiceConfig.js","sourceRoot":"","sources":["../../../src/models/ISynchronisedStorageServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the Synchronised Storage Service.\n */\nexport interface ISynchronisedStorageServiceConfig {\n\t/**\n\t * How often to check for entity updates in minutes.\n\t * @default 5\n\t */\n\tentityUpdateIntervalMinutes?: number;\n\n\t/**\n\t * Interval to perform consolidation of changesets, only used if this is a trusted node.\n\t * @default 60\n\t */\n\tconsolidationIntervalMinutes?: number;\n\n\t/**\n\t * The number of entities to process in a single consolidation batch, only used if this is a trusted node.\n\t * @default 1000\n\t */\n\tconsolidationBatchSize?: number;\n\n\t/**\n\t * The maximum number of consolidations to keep in storage, only used if this is a trusted node.\n\t * @default 5\n\t */\n\tmaxConsolidations?: number;\n\n\t/**\n\t * The encryption key id from the vault to use for blob storage, only required for trusted nodes, untrusted nodes will request the key.\n\t * @default synchronised-storage-blob-encryption-key\n\t */\n\tblobStorageEncryptionKeyId?: string;\n\n\t/**\n\t * The verifiable storage key to use, already expected to be created.\n\t * if the key is not found in the keys.json it is considered to be a custom verifiable storage id.\n\t * @default local\n\t */\n\tverifiableStorageKeyId: \"mainnet\" | \"testnet\" | \"devnet\" | string;\n}\n"]}
1
+ {"version":3,"file":"ISynchronisedStorageServiceConfig.js","sourceRoot":"","sources":["../../../src/models/ISynchronisedStorageServiceConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the Synchronised Storage Service.\n */\nexport interface ISynchronisedStorageServiceConfig {\n\t/**\n\t * How often to check for entity updates in minutes.\n\t * @default 5\n\t */\n\tentityUpdateIntervalMinutes?: number;\n\n\t/**\n\t * Interval to perform consolidation of changesets, only used if this is a trusted node.\n\t * @default 60\n\t */\n\tconsolidationIntervalMinutes?: number;\n\n\t/**\n\t * The number of entities to process in a single consolidation batch, only used if this is a trusted node.\n\t * @default 1000\n\t */\n\tconsolidationBatchSize?: number;\n\n\t/**\n\t * The maximum number of consolidations to keep in storage, only used if this is a trusted node.\n\t * @default 5\n\t */\n\tmaxConsolidations?: number;\n\n\t/**\n\t * The encryption key id from the vault to use for blob storage, only required for trusted nodes, untrusted nodes will request the key.\n\t * @default synchronised-storage-blob-encryption-key\n\t */\n\tblobStorageEncryptionKeyId?: string;\n\n\t/**\n\t * The verifiable storage key to use, already expected to be created.\n\t * if the key is not found in the keys.json it is considered to be a custom verifiable storage id.\n\t * @default local\n\t */\n\tverifiableStorageKeyId: \"mainnet\" | \"testnet\" | \"devnet\" | string;\n\n\t/**\n\t * Override the default trust generator.\n\t */\n\toverrideTrustGeneratorType?: string;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ISynchronisedStorageServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/ISynchronisedStorageServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ISynchronisedStorageServiceConfig } from \"./ISynchronisedStorageServiceConfig.js\";\n\n/**\n * Options for the Synchronised Storage Service constructor.\n */\nexport interface ISynchronisedStorageServiceConstructorOptions {\n\t/**\n\t * The logging component.\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * The event bus component type.\n\t */\n\teventBusComponentType?: string;\n\n\t/**\n\t * The vault connector type.\n\t */\n\tvaultConnectorType?: string;\n\n\t/**\n\t * The entity storage connector type to use for sync snapshots.\n\t * @default sync-snapshot-entry\n\t */\n\tsyncSnapshotStorageConnectorType?: string;\n\n\t/**\n\t * The blob storage connector used for remote sync state.\n\t * @default blob-storage\n\t */\n\tblobStorageConnectorType?: string;\n\n\t/**\n\t * The verifiable storage connector type to use for decentralised state.\n\t * @default verifiable-storage\n\t */\n\tverifiableStorageConnectorType?: string;\n\n\t/**\n\t * The task scheduler component.\n\t * @default task-scheduler\n\t */\n\ttaskSchedulerComponentType?: string;\n\n\t/**\n\t * The rights management enforcement component to use for verifying untrusted node access.\n\t * Only required on a trusted node to enforce access control.\n\t * @default policy-enforcement-point\n\t */\n\tpolicyEnforcementPointComponentType?: string;\n\n\t/**\n\t * The synchronised entity storage component type to use if this node is not trusted.\n\t * If this is set, this node uses it as the trusted node to store changesets.\n\t */\n\ttrustedSynchronisedStorageComponentType?: string;\n\n\t/**\n\t * The configuration for the connector.\n\t */\n\tconfig: ISynchronisedStorageServiceConfig;\n}\n"]}
1
+ {"version":3,"file":"ISynchronisedStorageServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/ISynchronisedStorageServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ISynchronisedStorageServiceConfig } from \"./ISynchronisedStorageServiceConfig.js\";\n\n/**\n * Options for the Synchronised Storage Service constructor.\n */\nexport interface ISynchronisedStorageServiceConstructorOptions {\n\t/**\n\t * The logging component.\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * The event bus component type.\n\t */\n\teventBusComponentType?: string;\n\n\t/**\n\t * The vault connector type.\n\t */\n\tvaultConnectorType?: string;\n\n\t/**\n\t * The entity storage connector type to use for sync snapshots.\n\t * @default sync-snapshot-entry\n\t */\n\tsyncSnapshotStorageConnectorType?: string;\n\n\t/**\n\t * The blob storage connector used for remote sync state.\n\t * @default blob-storage\n\t */\n\tblobStorageConnectorType?: string;\n\n\t/**\n\t * The verifiable storage connector type to use for decentralised state.\n\t * @default verifiable-storage\n\t */\n\tverifiableStorageConnectorType?: string;\n\n\t/**\n\t * The task scheduler component.\n\t * @default task-scheduler\n\t */\n\ttaskSchedulerComponentType?: string;\n\n\t/**\n\t * The type of the trust component.\n\t * @default trust\n\t */\n\ttrustComponentType?: string;\n\n\t/**\n\t * The synchronised entity storage component type to use if this node is not trusted.\n\t * If this is set, this node uses it as the trusted node to store changesets.\n\t */\n\ttrustedSynchronisedStorageComponentType?: string;\n\n\t/**\n\t * The configuration for the connector.\n\t */\n\tconfig: ISynchronisedStorageServiceConfig;\n}\n"]}
@@ -1,7 +1,6 @@
1
- import { ContextIdKeys } from "@twin.org/context";
2
1
  import { ComponentFactory, Guards } from "@twin.org/core";
3
2
  import { SynchronisedStorageContexts, SynchronisedStorageTypes } from "@twin.org/synchronised-storage-models";
4
- import { HeaderTypes, HttpStatusCode } from "@twin.org/web";
3
+ import { HeaderHelper, HeaderTypes, HttpStatusCode } from "@twin.org/web";
5
4
  /**
6
5
  * The source used when communicating about these routes.
7
6
  */
@@ -39,12 +38,12 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
39
38
  [HeaderTypes.Authorization]: "z3V32BP9ShC...z3V32BP9ShC"
40
39
  },
41
40
  body: {
42
- "@context": SynchronisedStorageContexts.ContextRoot,
41
+ "@context": SynchronisedStorageContexts.Context,
43
42
  type: SynchronisedStorageTypes.ChangeSet,
44
43
  id: "0909090909090909090909090909090909090909090909090909090909090909",
45
44
  dateCreated: "2025-05-29T01:00:00.000Z",
46
45
  dateModified: "2025-05-29T01:00:00.000Z",
47
- nodeId: "did:entity-storage:0xd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2",
46
+ nodeIdentity: "did:entity-storage:0xd2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2",
48
47
  changes: [
49
48
  {
50
49
  entity: {
@@ -65,11 +64,7 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
65
64
  type: "INoContentResponse"
66
65
  }
67
66
  ],
68
- skipAuth: true,
69
- processorFeatures: ["verifiableCredential"],
70
- processorData: {
71
- verifiableCredential: { contextId: ContextIdKeys.Organization }
72
- }
67
+ skipAuth: true
73
68
  };
74
69
  const getDecryptionKeyRoute = {
75
70
  operationId: "synchronisedStorageGetDecryptionKeyRequest",
@@ -105,11 +100,7 @@ export function generateRestRoutesSynchronisedStorage(baseRouteName, componentNa
105
100
  type: "IUnauthorizedResponse"
106
101
  }
107
102
  ],
108
- skipAuth: true,
109
- processorFeatures: ["verifiableCredential"],
110
- processorData: {
111
- verifiableCredential: { contextId: ContextIdKeys.Organization }
112
- }
103
+ skipAuth: true
113
104
  };
114
105
  return [syncChangeSetRoute, getDecryptionKeyRoute];
115
106
  }
@@ -125,8 +116,7 @@ export async function synchronisedStorageSyncChangeSetRequest(httpRequestContext
125
116
  Guards.object(ROUTES_SOURCE, "request", request);
126
117
  Guards.object(ROUTES_SOURCE, "request.body", request.body);
127
118
  const component = ComponentFactory.get(componentName);
128
- await component.syncChangeSet(request.body, httpRequestContext.processorState
129
- .verifiableCredentialSubject);
119
+ await component.syncChangeSet(request.body, HeaderHelper.extractBearer(request.headers?.[HeaderTypes.Authorization]));
130
120
  return {
131
121
  statusCode: HttpStatusCode.noContent
132
122
  };
@@ -142,8 +132,7 @@ export async function synchronisedStorageGetDecryptionKeyRequest(httpRequestCont
142
132
  Guards.object(ROUTES_SOURCE, "request.headers", request.headers);
143
133
  Guards.object(ROUTES_SOURCE, "request", request);
144
134
  const component = ComponentFactory.get(componentName);
145
- const key = await component.getDecryptionKey(httpRequestContext.processorState
146
- .verifiableCredentialSubject);
135
+ const key = await component.getDecryptionKey(HeaderHelper.extractBearer(request.headers?.[HeaderTypes.Authorization]));
147
136
  return {
148
137
  body: {
149
138
  decryptionKey: key
@@ -1 +1 @@
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 { ContextIdKeys } from \"@twin.org/context\";\nimport { ComponentFactory, Guards } from \"@twin.org/core\";\nimport type { IIdentityAuthenticationActionRequest } from \"@twin.org/identity-authentication\";\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 { 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.ContextRoot,\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\tnodeId:\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\tprocessorFeatures: [\"verifiableCredential\"],\n\t\tprocessorData: {\n\t\t\tverifiableCredential: { contextId: ContextIdKeys.Organization }\n\t\t}\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\tprocessorFeatures: [\"verifiableCredential\"],\n\t\tprocessorData: {\n\t\t\tverifiableCredential: { contextId: ContextIdKeys.Organization }\n\t\t}\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\thttpRequestContext.processorState\n\t\t\t.verifiableCredentialSubject as IIdentityAuthenticationActionRequest\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\thttpRequestContext.processorState\n\t\t\t.verifiableCredentialSubject as IIdentityAuthenticationActionRequest\n\t);\n\treturn {\n\t\tbody: {\n\t\t\tdecryptionKey: key\n\t\t}\n\t};\n}\n"]}
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;KACd,CAAC;IAEF,MAAM,qBAAqB,GAAsE;QAChG,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,6BAA6B;QACtC,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,0CAA0C,CAAC,kBAAkB,EAAE,aAAa,EAAE,OAAO,CAAC;QACvF,WAAW,EAAE;YACZ,IAAI,yBAAiC;YACrC,QAAQ,EAAE;gBACT;oBACC,EAAE,EAAE,uDAAuD;oBAC3D,OAAO,EAAE,EAAE;iBACX;aACD;SACD;QACD,YAAY,EAAE;YACb;gBACC,IAAI,8BAAsC;gBAC1C,QAAQ,EAAE;oBACT;wBACC,EAAE,EAAE,wDAAwD;wBAC5D,QAAQ,EAAE;4BACT,IAAI,EAAE;gCACL,aAAa,EACZ,2FAA2F;6BAC5F;yBACD;qBACD;iBACD;aACD;YACD;gBACC,IAAI,yBAAiC;aACrC;SACD;QACD,QAAQ,EAAE,IAAI;KACd,CAAC;IAEF,OAAO,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAC5D,kBAAuC,EACvC,aAAqB,EACrB,OAA8B;IAE9B,MAAM,CAAC,MAAM,CACZ,aAAa,qBAEb,OAAO,CAAC,OAAO,CACf,CAAC;IACF,MAAM,CAAC,MAAM,CAAwB,aAAa,aAAmB,OAAO,CAAC,CAAC;IAC9E,MAAM,CAAC,MAAM,CAAgC,aAAa,kBAAwB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhG,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAgC,aAAa,CAAC,CAAC;IACrF,MAAM,SAAS,CAAC,aAAa,CAC5B,OAAO,CAAC,IAAI,EACZ,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CACxE,CAAC;IACF,OAAO;QACN,UAAU,EAAE,cAAc,CAAC,SAAS;KACpC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC/D,kBAAuC,EACvC,aAAqB,EACrB,OAAkC;IAElC,MAAM,CAAC,MAAM,CACZ,aAAa,qBAEb,OAAO,CAAC,OAAO,CACf,CAAC;IACF,MAAM,CAAC,MAAM,CAA4B,aAAa,aAAmB,OAAO,CAAC,CAAC;IAElF,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAgC,aAAa,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,gBAAgB,CAC3C,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CACxE,CAAC;IACF,OAAO;QACN,IAAI,EAAE;YACL,aAAa,EAAE,GAAG;SAClB;KACD,CAAC;AACH,CAAC","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"]}