@dcl/sdk 7.25.1-30310486734.commit-5ffe873 → 7.25.1-30391610123.commit-26cb925
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composite-provider.js +4 -9
- package/internal/utf8.d.ts +15 -0
- package/internal/utf8.js +172 -0
- package/network/binary-message-bus.d.ts +3 -6
- package/network/binary-message-bus.js +5 -9
- package/network/index.d.ts +2 -8
- package/network/index.js +3 -16
- package/network/message-bus-sync.d.ts +1 -14
- package/network/message-bus-sync.js +103 -161
- package/network/state.js +5 -3
- package/package.json +6 -7
- package/src/composite-provider.ts +3 -10
- package/src/internal/utf8.ts +167 -0
- package/src/network/binary-message-bus.ts +4 -9
- package/src/network/index.ts +3 -40
- package/src/network/message-bus-sync.ts +110 -174
- package/src/network/state.ts +4 -3
- package/src/text-codec.ts +59 -12
- package/text-codec.d.ts +23 -8
- package/text-codec.js +55 -13
- package/atom.d.ts +0 -19
- package/atom.js +0 -83
- package/future.d.ts +0 -8
- package/future.js +0 -26
- package/network/chunking.d.ts +0 -5
- package/network/chunking.js +0 -38
- package/network/events/implementation.d.ts +0 -93
- package/network/events/implementation.js +0 -221
- package/network/events/index.d.ts +0 -42
- package/network/events/index.js +0 -43
- package/network/events/protocol.d.ts +0 -27
- package/network/events/protocol.js +0 -66
- package/network/events/registry.d.ts +0 -8
- package/network/events/registry.js +0 -3
- package/network/server/index.d.ts +0 -14
- package/network/server/index.js +0 -219
- package/network/server/utils.d.ts +0 -18
- package/network/server/utils.js +0 -135
- package/server/env-var.d.ts +0 -15
- package/server/env-var.js +0 -31
- package/server/index.d.ts +0 -2
- package/server/index.js +0 -3
- package/server/storage/constants.d.ts +0 -79
- package/server/storage/constants.js +0 -19
- package/server/storage/index.d.ts +0 -45
- package/server/storage/index.js +0 -51
- package/server/storage/player.d.ts +0 -45
- package/server/storage/player.js +0 -198
- package/server/storage/scene.d.ts +0 -40
- package/server/storage/scene.js +0 -188
- package/server/storage/value-cache.d.ts +0 -1
- package/server/storage/value-cache.js +0 -52
- package/server/storage/write-queue.d.ts +0 -1
- package/server/storage/write-queue.js +0 -71
- package/server/storage-url.d.ts +0 -13
- package/server/storage-url.js +0 -42
- package/server/utils.d.ts +0 -35
- package/server/utils.js +0 -61
- package/src/atom.ts +0 -98
- package/src/ethereum-provider/text-encoding.d.ts +0 -4
- package/src/future.ts +0 -38
- package/src/network/chunking.ts +0 -45
- package/src/network/events/implementation.ts +0 -271
- package/src/network/events/index.ts +0 -48
- package/src/network/events/protocol.ts +0 -94
- package/src/network/events/registry.ts +0 -18
- package/src/network/server/index.ts +0 -301
- package/src/network/server/utils.ts +0 -189
- package/src/server/env-var.ts +0 -36
- package/src/server/index.ts +0 -12
- package/src/server/storage/constants.ts +0 -111
- package/src/server/storage/index.ts +0 -74
- package/src/server/storage/player.ts +0 -289
- package/src/server/storage/scene.ts +0 -270
- package/src/server/storage/value-cache.ts +0 -92
- package/src/server/storage/write-queue.ts +0 -131
- package/src/server/storage-url.ts +0 -49
- package/src/server/utils.ts +0 -76
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { StorageOptions } from './constants';
|
|
2
|
-
import { ISceneStorage } from './scene';
|
|
3
|
-
import { IPlayerStorage } from './player';
|
|
4
|
-
export { GetOptions, GetValuesOptions, GetValuesResult, SetOptions, StorageOptions } from './constants';
|
|
5
|
-
export { ISceneStorage } from './scene';
|
|
6
|
-
export { IPlayerStorage } from './player';
|
|
7
|
-
/**
|
|
8
|
-
* Storage interface with methods for scene-scoped and player-scoped storage.
|
|
9
|
-
*/
|
|
10
|
-
export interface IStorage extends ISceneStorage {
|
|
11
|
-
/** Player-scoped storage for key-value pairs */
|
|
12
|
-
player: IPlayerStorage;
|
|
13
|
-
/**
|
|
14
|
-
* Sets module-wide defaults for both scene-scoped and player-scoped storage.
|
|
15
|
-
* Merges the given partial options into the current configuration.
|
|
16
|
-
* Note: cacheMaxEntries applies per scope (scene and player each keep their
|
|
17
|
-
* own cache) and bounds entry count, not bytes (entries hold serialized
|
|
18
|
-
* value bodies).
|
|
19
|
-
*/
|
|
20
|
-
configure(options: StorageOptions): void;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Storage provides methods to store and retrieve key-value data from the
|
|
24
|
-
* Server Side Storage service.
|
|
25
|
-
*
|
|
26
|
-
* - Use Storage.get/set/delete/getValues for scene-scoped storage
|
|
27
|
-
* - Use Storage.player.get/set/delete/getValues for player-scoped storage
|
|
28
|
-
* - Use Storage.configure to change module-wide defaults (e.g. skipIfUnchanged, cacheReads)
|
|
29
|
-
*
|
|
30
|
-
* Reads are cached by default: get() serves values known from a network
|
|
31
|
-
* round-trip within the last cacheMaxAgeMs (including confirmed "not found"
|
|
32
|
-
* results) without hitting the service, and concurrent gets for the same key
|
|
33
|
-
* share one request. Overlapping writes to the same key are serialized so the
|
|
34
|
-
* service commits them in issue order, and rapid writes coalesce to the
|
|
35
|
-
* latest value; every set()/delete() resolves once its value (or the newer
|
|
36
|
-
* value that superseded it) is durably applied. By default (skipIfUnchanged)
|
|
37
|
-
* an unchanged set is skipped, but only when a previous confirmed round-trip
|
|
38
|
-
* proved the exact value is already stored. Out-of-band writers (e.g. CLI storage commands)
|
|
39
|
-
* may not be visible for up to cacheMaxAgeMs; use get(key, { fresh: true })
|
|
40
|
-
* for an authoritative read or Storage.configure({ cacheReads: false }) to
|
|
41
|
-
* disable read caching.
|
|
42
|
-
*
|
|
43
|
-
* This module only works when running on server-side scenes.
|
|
44
|
-
*/
|
|
45
|
-
export declare const Storage: IStorage;
|
package/server/storage/index.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { createStorageConfig } from './constants';
|
|
2
|
-
import { createSceneStorage } from './scene';
|
|
3
|
-
import { createPlayerStorage } from './player';
|
|
4
|
-
/**
|
|
5
|
-
* Creates the Storage module with scene-scoped and player-scoped storage.
|
|
6
|
-
*/
|
|
7
|
-
const createStorage = () => {
|
|
8
|
-
const config = createStorageConfig();
|
|
9
|
-
const sceneStorage = createSceneStorage(config);
|
|
10
|
-
const playerStorage = createPlayerStorage(config);
|
|
11
|
-
return {
|
|
12
|
-
// Spread scene storage methods at top level
|
|
13
|
-
get: sceneStorage.get,
|
|
14
|
-
set: sceneStorage.set,
|
|
15
|
-
delete: sceneStorage.delete,
|
|
16
|
-
getValues: sceneStorage.getValues,
|
|
17
|
-
// Keep player as nested property
|
|
18
|
-
player: playerStorage,
|
|
19
|
-
configure(options) {
|
|
20
|
-
for (const [key, value] of Object.entries(options)) {
|
|
21
|
-
if (value !== undefined)
|
|
22
|
-
config[key] = value;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* Storage provides methods to store and retrieve key-value data from the
|
|
29
|
-
* Server Side Storage service.
|
|
30
|
-
*
|
|
31
|
-
* - Use Storage.get/set/delete/getValues for scene-scoped storage
|
|
32
|
-
* - Use Storage.player.get/set/delete/getValues for player-scoped storage
|
|
33
|
-
* - Use Storage.configure to change module-wide defaults (e.g. skipIfUnchanged, cacheReads)
|
|
34
|
-
*
|
|
35
|
-
* Reads are cached by default: get() serves values known from a network
|
|
36
|
-
* round-trip within the last cacheMaxAgeMs (including confirmed "not found"
|
|
37
|
-
* results) without hitting the service, and concurrent gets for the same key
|
|
38
|
-
* share one request. Overlapping writes to the same key are serialized so the
|
|
39
|
-
* service commits them in issue order, and rapid writes coalesce to the
|
|
40
|
-
* latest value; every set()/delete() resolves once its value (or the newer
|
|
41
|
-
* value that superseded it) is durably applied. By default (skipIfUnchanged)
|
|
42
|
-
* an unchanged set is skipped, but only when a previous confirmed round-trip
|
|
43
|
-
* proved the exact value is already stored. Out-of-band writers (e.g. CLI storage commands)
|
|
44
|
-
* may not be visible for up to cacheMaxAgeMs; use get(key, { fresh: true })
|
|
45
|
-
* for an authoritative read or Storage.configure({ cacheReads: false }) to
|
|
46
|
-
* disable read caching.
|
|
47
|
-
*
|
|
48
|
-
* This module only works when running on server-side scenes.
|
|
49
|
-
*/
|
|
50
|
-
export const Storage = createStorage();
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2UvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFrQixNQUFNLGFBQWEsQ0FBQTtBQUNqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQWlCLE1BQU0sU0FBUyxDQUFBO0FBQzNELE9BQU8sRUFBRSxtQkFBbUIsRUFBa0IsTUFBTSxVQUFVLENBQUE7QUF3QjlEOztHQUVHO0FBQ0gsTUFBTSxhQUFhLEdBQUcsR0FBYSxFQUFFO0lBQ25DLE1BQU0sTUFBTSxHQUFHLG1CQUFtQixFQUFFLENBQUE7SUFDcEMsTUFBTSxZQUFZLEdBQUcsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDL0MsTUFBTSxhQUFhLEdBQUcsbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUE7SUFFakQsT0FBTztRQUNMLDRDQUE0QztRQUM1QyxHQUFHLEVBQUUsWUFBWSxDQUFDLEdBQUc7UUFDckIsR0FBRyxFQUFFLFlBQVksQ0FBQyxHQUFHO1FBQ3JCLE1BQU0sRUFBRSxZQUFZLENBQUMsTUFBTTtRQUMzQixTQUFTLEVBQUUsWUFBWSxDQUFDLFNBQVM7UUFDakMsaUNBQWlDO1FBQ2pDLE1BQU0sRUFBRSxhQUFhO1FBQ3JCLFNBQVMsQ0FBQyxPQUF1QjtZQUMvQixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtnQkFDbEQsSUFBSSxLQUFLLEtBQUssU0FBUztvQkFBRyxNQUE2QyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQTthQUNyRjtRQUNILENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyxDQUFBO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQWEsYUFBYSxFQUFFLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVTdG9yYWdlQ29uZmlnLCBTdG9yYWdlT3B0aW9ucyB9IGZyb20gJy4vY29uc3RhbnRzJ1xuaW1wb3J0IHsgY3JlYXRlU2NlbmVTdG9yYWdlLCBJU2NlbmVTdG9yYWdlIH0gZnJvbSAnLi9zY2VuZSdcbmltcG9ydCB7IGNyZWF0ZVBsYXllclN0b3JhZ2UsIElQbGF5ZXJTdG9yYWdlIH0gZnJvbSAnLi9wbGF5ZXInXG5cbi8vIFJlLWV4cG9ydCBpbnRlcmZhY2VzIGFuZCB0eXBlc1xuZXhwb3J0IHsgR2V0T3B0aW9ucywgR2V0VmFsdWVzT3B0aW9ucywgR2V0VmFsdWVzUmVzdWx0LCBTZXRPcHRpb25zLCBTdG9yYWdlT3B0aW9ucyB9IGZyb20gJy4vY29uc3RhbnRzJ1xuZXhwb3J0IHsgSVNjZW5lU3RvcmFnZSB9IGZyb20gJy4vc2NlbmUnXG5leHBvcnQgeyBJUGxheWVyU3RvcmFnZSB9IGZyb20gJy4vcGxheWVyJ1xuXG4vKipcbiAqIFN0b3JhZ2UgaW50ZXJmYWNlIHdpdGggbWV0aG9kcyBmb3Igc2NlbmUtc2NvcGVkIGFuZCBwbGF5ZXItc2NvcGVkIHN0b3JhZ2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVN0b3JhZ2UgZXh0ZW5kcyBJU2NlbmVTdG9yYWdlIHtcbiAgLyoqIFBsYXllci1zY29wZWQgc3RvcmFnZSBmb3Iga2V5LXZhbHVlIHBhaXJzICovXG4gIHBsYXllcjogSVBsYXllclN0b3JhZ2VcblxuICAvKipcbiAgICogU2V0cyBtb2R1bGUtd2lkZSBkZWZhdWx0cyBmb3IgYm90aCBzY2VuZS1zY29wZWQgYW5kIHBsYXllci1zY29wZWQgc3RvcmFnZS5cbiAgICogTWVyZ2VzIHRoZSBnaXZlbiBwYXJ0aWFsIG9wdGlvbnMgaW50byB0aGUgY3VycmVudCBjb25maWd1cmF0aW9uLlxuICAgKiBOb3RlOiBjYWNoZU1heEVudHJpZXMgYXBwbGllcyBwZXIgc2NvcGUgKHNjZW5lIGFuZCBwbGF5ZXIgZWFjaCBrZWVwIHRoZWlyXG4gICAqIG93biBjYWNoZSkgYW5kIGJvdW5kcyBlbnRyeSBjb3VudCwgbm90IGJ5dGVzIChlbnRyaWVzIGhvbGQgc2VyaWFsaXplZFxuICAgKiB2YWx1ZSBib2RpZXMpLlxuICAgKi9cbiAgY29uZmlndXJlKG9wdGlvbnM6IFN0b3JhZ2VPcHRpb25zKTogdm9pZFxufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIFN0b3JhZ2UgbW9kdWxlIHdpdGggc2NlbmUtc2NvcGVkIGFuZCBwbGF5ZXItc2NvcGVkIHN0b3JhZ2UuXG4gKi9cbmNvbnN0IGNyZWF0ZVN0b3JhZ2UgPSAoKTogSVN0b3JhZ2UgPT4ge1xuICBjb25zdCBjb25maWcgPSBjcmVhdGVTdG9yYWdlQ29uZmlnKClcbiAgY29uc3Qgc2NlbmVTdG9yYWdlID0gY3JlYXRlU2NlbmVTdG9yYWdlKGNvbmZpZylcbiAgY29uc3QgcGxheWVyU3RvcmFnZSA9IGNyZWF0ZVBsYXllclN0b3JhZ2UoY29uZmlnKVxuXG4gIHJldHVybiB7XG4gICAgLy8gU3ByZWFkIHNjZW5lIHN0b3JhZ2UgbWV0aG9kcyBhdCB0b3AgbGV2ZWxcbiAgICBnZXQ6IHNjZW5lU3RvcmFnZS5nZXQsXG4gICAgc2V0OiBzY2VuZVN0b3JhZ2Uuc2V0LFxuICAgIGRlbGV0ZTogc2NlbmVTdG9yYWdlLmRlbGV0ZSxcbiAgICBnZXRWYWx1ZXM6IHNjZW5lU3RvcmFnZS5nZXRWYWx1ZXMsXG4gICAgLy8gS2VlcCBwbGF5ZXIgYXMgbmVzdGVkIHByb3BlcnR5XG4gICAgcGxheWVyOiBwbGF5ZXJTdG9yYWdlLFxuICAgIGNvbmZpZ3VyZShvcHRpb25zOiBTdG9yYWdlT3B0aW9ucyk6IHZvaWQge1xuICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcbiAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIChjb25maWcgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilba2V5XSA9IHZhbHVlXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogU3RvcmFnZSBwcm92aWRlcyBtZXRob2RzIHRvIHN0b3JlIGFuZCByZXRyaWV2ZSBrZXktdmFsdWUgZGF0YSBmcm9tIHRoZVxuICogU2VydmVyIFNpZGUgU3RvcmFnZSBzZXJ2aWNlLlxuICpcbiAqIC0gVXNlIFN0b3JhZ2UuZ2V0L3NldC9kZWxldGUvZ2V0VmFsdWVzIGZvciBzY2VuZS1zY29wZWQgc3RvcmFnZVxuICogLSBVc2UgU3RvcmFnZS5wbGF5ZXIuZ2V0L3NldC9kZWxldGUvZ2V0VmFsdWVzIGZvciBwbGF5ZXItc2NvcGVkIHN0b3JhZ2VcbiAqIC0gVXNlIFN0b3JhZ2UuY29uZmlndXJlIHRvIGNoYW5nZSBtb2R1bGUtd2lkZSBkZWZhdWx0cyAoZS5nLiBza2lwSWZVbmNoYW5nZWQsIGNhY2hlUmVhZHMpXG4gKlxuICogUmVhZHMgYXJlIGNhY2hlZCBieSBkZWZhdWx0OiBnZXQoKSBzZXJ2ZXMgdmFsdWVzIGtub3duIGZyb20gYSBuZXR3b3JrXG4gKiByb3VuZC10cmlwIHdpdGhpbiB0aGUgbGFzdCBjYWNoZU1heEFnZU1zIChpbmNsdWRpbmcgY29uZmlybWVkIFwibm90IGZvdW5kXCJcbiAqIHJlc3VsdHMpIHdpdGhvdXQgaGl0dGluZyB0aGUgc2VydmljZSwgYW5kIGNvbmN1cnJlbnQgZ2V0cyBmb3IgdGhlIHNhbWUga2V5XG4gKiBzaGFyZSBvbmUgcmVxdWVzdC4gT3ZlcmxhcHBpbmcgd3JpdGVzIHRvIHRoZSBzYW1lIGtleSBhcmUgc2VyaWFsaXplZCBzbyB0aGVcbiAqIHNlcnZpY2UgY29tbWl0cyB0aGVtIGluIGlzc3VlIG9yZGVyLCBhbmQgcmFwaWQgd3JpdGVzIGNvYWxlc2NlIHRvIHRoZVxuICogbGF0ZXN0IHZhbHVlOyBldmVyeSBzZXQoKS9kZWxldGUoKSByZXNvbHZlcyBvbmNlIGl0cyB2YWx1ZSAob3IgdGhlIG5ld2VyXG4gKiB2YWx1ZSB0aGF0IHN1cGVyc2VkZWQgaXQpIGlzIGR1cmFibHkgYXBwbGllZC4gQnkgZGVmYXVsdCAoc2tpcElmVW5jaGFuZ2VkKVxuICogYW4gdW5jaGFuZ2VkIHNldCBpcyBza2lwcGVkLCBidXQgb25seSB3aGVuIGEgcHJldmlvdXMgY29uZmlybWVkIHJvdW5kLXRyaXBcbiAqIHByb3ZlZCB0aGUgZXhhY3QgdmFsdWUgaXMgYWxyZWFkeSBzdG9yZWQuIE91dC1vZi1iYW5kIHdyaXRlcnMgKGUuZy4gQ0xJIHN0b3JhZ2UgY29tbWFuZHMpXG4gKiBtYXkgbm90IGJlIHZpc2libGUgZm9yIHVwIHRvIGNhY2hlTWF4QWdlTXM7IHVzZSBnZXQoa2V5LCB7IGZyZXNoOiB0cnVlIH0pXG4gKiBmb3IgYW4gYXV0aG9yaXRhdGl2ZSByZWFkIG9yIFN0b3JhZ2UuY29uZmlndXJlKHsgY2FjaGVSZWFkczogZmFsc2UgfSkgdG9cbiAqIGRpc2FibGUgcmVhZCBjYWNoaW5nLlxuICpcbiAqIFRoaXMgbW9kdWxlIG9ubHkgd29ya3Mgd2hlbiBydW5uaW5nIG9uIHNlcnZlci1zaWRlIHNjZW5lcy5cbiAqL1xuZXhwb3J0IGNvbnN0IFN0b3JhZ2U6IElTdG9yYWdlID0gY3JlYXRlU3RvcmFnZSgpXG4iXX0=
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { GetOptions, GetValuesOptions, GetValuesResult, SetOptions } from './constants';
|
|
2
|
-
/**
|
|
3
|
-
* Player-scoped storage interface for key-value pairs from the Server Side Storage service.
|
|
4
|
-
* This is NOT filesystem storage - data is stored in the remote storage service.
|
|
5
|
-
*/
|
|
6
|
-
export interface IPlayerStorage {
|
|
7
|
-
/**
|
|
8
|
-
* Retrieves a value from a player's storage by key from the Server Side Storage service.
|
|
9
|
-
*
|
|
10
|
-
* By default (cacheReads), values read or written during the last cacheMaxAgeMs
|
|
11
|
-
* are served from a local cache without a network request, including confirmed
|
|
12
|
-
* "not found" results. Concurrent gets for the same player and key share one
|
|
13
|
-
* request. Out-of-band writers (e.g. CLI storage commands) may not be visible
|
|
14
|
-
* for up to cacheMaxAgeMs — pass { fresh: true } to force a network read.
|
|
15
|
-
* @param address - The player's wallet address
|
|
16
|
-
* @param key - The key to retrieve
|
|
17
|
-
* @param options - Optional { fresh } to bypass the read cache
|
|
18
|
-
* @returns A promise that resolves to the parsed JSON value, or null if not found
|
|
19
|
-
*/
|
|
20
|
-
get<T = unknown>(address: string, key: string, options?: GetOptions): Promise<T | null>;
|
|
21
|
-
/**
|
|
22
|
-
* Stores a value in a player's storage in the Server Side Storage service.
|
|
23
|
-
* @param address - The player's wallet address
|
|
24
|
-
* @param key - The key to store the value under
|
|
25
|
-
* @param value - The value to store (will be JSON serialized)
|
|
26
|
-
* @param options - Optional { skipIfUnchanged } to skip the network write when the value is already stored
|
|
27
|
-
* @returns A promise that resolves to true if successful, false otherwise
|
|
28
|
-
*/
|
|
29
|
-
set<T = unknown>(address: string, key: string, value: T, options?: SetOptions): Promise<boolean>;
|
|
30
|
-
/**
|
|
31
|
-
* Deletes a value from a player's storage in the Server Side Storage service.
|
|
32
|
-
* @param address - The player's wallet address
|
|
33
|
-
* @param key - The key to delete
|
|
34
|
-
* @returns A promise that resolves to true if deleted, false if not found
|
|
35
|
-
*/
|
|
36
|
-
delete(address: string, key: string): Promise<boolean>;
|
|
37
|
-
/**
|
|
38
|
-
* Returns key-value entries from a player's storage, optionally filtered by prefix.
|
|
39
|
-
* Supports pagination via limit and offset.
|
|
40
|
-
* @param address - The player's wallet address
|
|
41
|
-
* @param options - Optional { prefix, limit, offset } for filtering and pagination.
|
|
42
|
-
* @returns A promise that resolves to { data, pagination: { offset, total } } for pagination UI
|
|
43
|
-
*/
|
|
44
|
-
getValues(address: string, options?: GetValuesOptions): Promise<GetValuesResult>;
|
|
45
|
-
}
|
package/server/storage/player.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { getStorageServerUrl } from '../storage-url';
|
|
2
|
-
import { assertIsServer, wrapSignedFetch } from '../utils';
|
|
3
|
-
import { createStorageConfig, MODULE_NAME } from './constants';
|
|
4
|
-
import { createValueCache } from './value-cache';
|
|
5
|
-
import { createWriteQueue } from './write-queue';
|
|
6
|
-
/**
|
|
7
|
-
* Creates player-scoped storage that provides methods to interact with
|
|
8
|
-
* player-specific key-value pairs from the Server Side Storage service.
|
|
9
|
-
* This module only works when running on server-side scenes.
|
|
10
|
-
* @internal
|
|
11
|
-
*/
|
|
12
|
-
export const createPlayerStorage = (config = createStorageConfig()) => {
|
|
13
|
-
const cache = createValueCache(config);
|
|
14
|
-
// Each in-flight GET is tracked by a wrapper object whose identity marks
|
|
15
|
-
// ownership: set()/delete() drop the wrapper, detaching the pending GET so
|
|
16
|
-
// its stale response cannot overwrite the newer cache entry.
|
|
17
|
-
const inflightGets = new Map();
|
|
18
|
-
// Ethereum addresses are case-insensitive (checksum casing only), so
|
|
19
|
-
// mixed-case callers must share the same cache entry. The NUL separator
|
|
20
|
-
// cannot appear in an address, making the pair unambiguous.
|
|
21
|
-
const cacheKey = (address, key) => `${address.toLowerCase()}\u0000${key}`;
|
|
22
|
-
// Writes to the same player key are serialized (and rapid ones coalesced to
|
|
23
|
-
// the latest value) so the service commits them in issue order — overlapping
|
|
24
|
-
// PUTs would otherwise leave both the kept value and the cached value to
|
|
25
|
-
// response-order chance. Keyed by the same case-insensitive cache key.
|
|
26
|
-
const writes = createWriteQueue();
|
|
27
|
-
async function executeSet(address, key, ck, body) {
|
|
28
|
-
const baseUrl = await getStorageServerUrl();
|
|
29
|
-
const url = `${baseUrl}/players/${encodeURIComponent(address)}/values/${encodeURIComponent(key)}`;
|
|
30
|
-
const [error] = await wrapSignedFetch({
|
|
31
|
-
url,
|
|
32
|
-
init: {
|
|
33
|
-
method: 'PUT',
|
|
34
|
-
headers: {
|
|
35
|
-
'content-type': 'application/json'
|
|
36
|
-
},
|
|
37
|
-
body
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
// Either way the entry changed server-side (or may have): detach any
|
|
41
|
-
// overlapping in-flight GET so its stale response is not cached.
|
|
42
|
-
inflightGets.delete(ck);
|
|
43
|
-
if (error) {
|
|
44
|
-
// The PUT may have reached the server, so the cached body is no
|
|
45
|
-
// longer reliable.
|
|
46
|
-
cache.delete(ck);
|
|
47
|
-
console.error(`Failed to set player storage value '${key}' for '${address}': ${error}`);
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
cache.set(ck, { body });
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
async function executeDelete(address, key, ck) {
|
|
54
|
-
const baseUrl = await getStorageServerUrl();
|
|
55
|
-
const url = `${baseUrl}/players/${encodeURIComponent(address)}/values/${encodeURIComponent(key)}`;
|
|
56
|
-
const [error, , status] = await wrapSignedFetch({
|
|
57
|
-
url,
|
|
58
|
-
init: {
|
|
59
|
-
method: 'DELETE',
|
|
60
|
-
headers: {}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
// Detach again: a GET may have started while the DELETE was in flight.
|
|
64
|
-
inflightGets.delete(ck);
|
|
65
|
-
if (error) {
|
|
66
|
-
// A 404 still confirms the key is absent server-side.
|
|
67
|
-
if (status === 404)
|
|
68
|
-
cache.setAbsent(ck);
|
|
69
|
-
console.error(`Failed to delete player storage value '${key}' for '${address}': ${error}`);
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
cache.setAbsent(ck);
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
async get(address, key, options) {
|
|
77
|
-
assertIsServer(MODULE_NAME);
|
|
78
|
-
const ck = cacheKey(address, key);
|
|
79
|
-
if (config.cacheReads && !options?.fresh) {
|
|
80
|
-
const entry = cache.get(ck);
|
|
81
|
-
if (entry?.absent)
|
|
82
|
-
return null;
|
|
83
|
-
// Parse per hit so each caller gets a fresh object (no shared mutation).
|
|
84
|
-
if (entry?.body !== undefined)
|
|
85
|
-
return JSON.parse(entry.body).value;
|
|
86
|
-
}
|
|
87
|
-
// Coalesce concurrent gets (even fresh ones: an in-flight response is
|
|
88
|
-
// milliseconds old, not TTL-stale) into a single network request.
|
|
89
|
-
const joined = inflightGets.get(ck);
|
|
90
|
-
if (joined)
|
|
91
|
-
return joined.promise;
|
|
92
|
-
const inflight = {};
|
|
93
|
-
inflight.promise = (async () => {
|
|
94
|
-
try {
|
|
95
|
-
const baseUrl = await getStorageServerUrl();
|
|
96
|
-
const url = `${baseUrl}/players/${encodeURIComponent(address)}/values/${encodeURIComponent(key)}`;
|
|
97
|
-
const [error, data, status] = await wrapSignedFetch({ url });
|
|
98
|
-
const isOwner = inflightGets.get(ck) === inflight;
|
|
99
|
-
if (error) {
|
|
100
|
-
// A confirmed 404 is a first-class "absent" outcome, not a failure.
|
|
101
|
-
if (status === 404) {
|
|
102
|
-
if (isOwner)
|
|
103
|
-
cache.setAbsent(ck);
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
console.error(`Failed to get player storage value '${key}' for '${address}': ${error}`);
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
if (data && data.value !== undefined) {
|
|
110
|
-
// Same serialization shape as set()'s PUT body, so a read followed by
|
|
111
|
-
// an unchanged write can be skipped.
|
|
112
|
-
const body = JSON.stringify({ value: data.value });
|
|
113
|
-
if (isOwner)
|
|
114
|
-
cache.set(ck, { body });
|
|
115
|
-
return data.value;
|
|
116
|
-
}
|
|
117
|
-
// 200 with a missing value is ambiguous: neither a confirmed value
|
|
118
|
-
// nor a confirmed absence, so cache nothing.
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
if (inflightGets.get(ck) === inflight)
|
|
123
|
-
inflightGets.delete(ck);
|
|
124
|
-
}
|
|
125
|
-
})();
|
|
126
|
-
inflightGets.set(ck, inflight);
|
|
127
|
-
return inflight.promise;
|
|
128
|
-
},
|
|
129
|
-
async set(address, key, value, options) {
|
|
130
|
-
assertIsServer(MODULE_NAME);
|
|
131
|
-
const ck = cacheKey(address, key);
|
|
132
|
-
const body = JSON.stringify({ value });
|
|
133
|
-
const skipIfUnchanged = options?.skipIfUnchanged ?? config.skipIfUnchanged;
|
|
134
|
-
// Dedup against confirmed state only while no write is pending — a
|
|
135
|
-
// pending write makes the cache momentarily stale; enqueue() coalesces
|
|
136
|
-
// against pending writes instead.
|
|
137
|
-
if (skipIfUnchanged && writes.pending(ck) === undefined && cache.get(ck)?.body === body) {
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
return writes.enqueue(ck, body, (b) => executeSet(address, key, ck, b), skipIfUnchanged);
|
|
141
|
-
},
|
|
142
|
-
async delete(address, key) {
|
|
143
|
-
assertIsServer(MODULE_NAME);
|
|
144
|
-
const ck = cacheKey(address, key);
|
|
145
|
-
// Invalidate immediately — even while the DELETE waits behind other
|
|
146
|
-
// writes, reads must not serve the doomed value, and a stale
|
|
147
|
-
// "unchanged" skip would lose a future write.
|
|
148
|
-
cache.delete(ck);
|
|
149
|
-
inflightGets.delete(ck);
|
|
150
|
-
return writes.enqueue(ck, null, () => executeDelete(address, key, ck), true);
|
|
151
|
-
},
|
|
152
|
-
async getValues(address, options) {
|
|
153
|
-
assertIsServer(MODULE_NAME);
|
|
154
|
-
const { prefix, limit, offset } = options ?? {};
|
|
155
|
-
const baseUrl = await getStorageServerUrl();
|
|
156
|
-
const parts = [];
|
|
157
|
-
if (!!prefix) {
|
|
158
|
-
parts.push(`prefix=${encodeURIComponent(prefix)}`);
|
|
159
|
-
}
|
|
160
|
-
if (!!limit) {
|
|
161
|
-
parts.push(`limit=${limit}`);
|
|
162
|
-
}
|
|
163
|
-
if (!!offset) {
|
|
164
|
-
parts.push(`offset=${offset}`);
|
|
165
|
-
}
|
|
166
|
-
const query = parts.join('&');
|
|
167
|
-
const url = query
|
|
168
|
-
? `${baseUrl}/players/${encodeURIComponent(address)}/values?${query}`
|
|
169
|
-
: `${baseUrl}/players/${encodeURIComponent(address)}/values`;
|
|
170
|
-
const [error, response] = await wrapSignedFetch({ url });
|
|
171
|
-
if (error) {
|
|
172
|
-
console.error(`Failed to get player storage values for '${address}': ${error}`);
|
|
173
|
-
return { data: [], pagination: { offset: 0, total: 0 } };
|
|
174
|
-
}
|
|
175
|
-
const data = response?.data ?? [];
|
|
176
|
-
// Seed the per-key cache so subsequent get()/set() on returned keys can
|
|
177
|
-
// skip the network. Only keys with no live entry and no pending write
|
|
178
|
-
// are seeded: existing per-key state comes from a confirmed operation
|
|
179
|
-
// that this page snapshot — whose request started earlier — must not
|
|
180
|
-
// clobber with stale data. Absence is never seeded (prefix/pagination
|
|
181
|
-
// make it non-authoritative). A page larger than cacheMaxEntries churns
|
|
182
|
-
// the cache; entries repopulate lazily.
|
|
183
|
-
for (const entry of data) {
|
|
184
|
-
const ck = cacheKey(address, entry.key);
|
|
185
|
-
if (entry.value !== undefined && !writes.isPending(ck) && cache.get(ck) === undefined) {
|
|
186
|
-
cache.set(ck, { body: JSON.stringify({ value: entry.value }) });
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
const requestedOffset = offset ?? 0;
|
|
190
|
-
const pagination = {
|
|
191
|
-
offset: response?.pagination?.offset ?? requestedOffset,
|
|
192
|
-
total: response?.pagination?.total ?? data.length
|
|
193
|
-
};
|
|
194
|
-
return { data, pagination };
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxheWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci9zdG9yYWdlL3BsYXllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsY0FBYyxFQUFFLGVBQWUsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUMxRCxPQUFPLEVBQ0wsbUJBQW1CLEVBSW5CLFdBQVcsRUFHWixNQUFNLGFBQWEsQ0FBQTtBQUNwQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDaEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZUFBZSxDQUFBO0FBa0RoRDs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLENBQUMsU0FBNkIsbUJBQW1CLEVBQUUsRUFBa0IsRUFBRTtJQUN4RyxNQUFNLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUN0Qyx5RUFBeUU7SUFDekUsMkVBQTJFO0lBQzNFLDZEQUE2RDtJQUM3RCxNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBeUMsQ0FBQTtJQUVyRSxxRUFBcUU7SUFDckUsd0VBQXdFO0lBQ3hFLDREQUE0RDtJQUM1RCxNQUFNLFFBQVEsR0FBRyxDQUFDLE9BQWUsRUFBRSxHQUFXLEVBQUUsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLFdBQVcsRUFBRSxTQUFTLEdBQUcsRUFBRSxDQUFBO0lBRXpGLDRFQUE0RTtJQUM1RSw2RUFBNkU7SUFDN0UseUVBQXlFO0lBQ3pFLHVFQUF1RTtJQUN2RSxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsRUFBRSxDQUFBO0lBRWpDLEtBQUssVUFBVSxVQUFVLENBQUMsT0FBZSxFQUFFLEdBQVcsRUFBRSxFQUFVLEVBQUUsSUFBWTtRQUM5RSxNQUFNLE9BQU8sR0FBRyxNQUFNLG1CQUFtQixFQUFFLENBQUE7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LEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO2lCQUNoRTthQUNGO1lBRUQsTUFBTSxlQUFlLEdBQUcsTUFBTSxJQUFJLENBQUMsQ0FBQTtZQUNuQyxNQUFNLFVBQVUsR0FBRztnQkFDakIsTUFBTSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxJQUFJLGVBQWU7Z0JBQ3ZELEtBQUssRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTTthQUNsRCxDQUFBO1lBRUQsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQTtRQUM3QixDQUFDO0tBQ0YsQ0FBQTtBQUNILENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldFN0b3JhZ2VTZXJ2ZXJVcmwgfSBmcm9tICcuLi9zdG9yYWdlLXVybCdcbmltcG9ydCB7IGFzc2VydElzU2VydmVyLCB3cmFwU2lnbmVkRmV0Y2ggfSBmcm9tICcuLi91dGlscydcbmltcG9ydCB7XG4gIGNyZWF0ZVN0b3JhZ2VDb25maWcsXG4gIEdldE9wdGlvbnMsXG4gIEdldFZhbHVlc09wdGlvbnMsXG4gIEdldFZhbHVlc1Jlc3VsdCxcbiAgTU9EVUxFX05BTUUsXG4gIFNldE9wdGlvbnMsXG4gIFN0b3JhZ2VDb25maWdTdGF0ZVxufSBmcm9tICcuL2NvbnN0YW50cydcbmltcG9ydCB7IGNyZWF0ZVZhbHVlQ2FjaGUgfSBmcm9tICcuL3ZhbHVlLWNhY2hlJ1xuaW1wb3J0IHsgY3JlYXRlV3JpdGVRdWV1ZSB9IGZyb20gJy4vd3JpdGUtcXVldWUnXG5cbi8qKlxuICogUGxheWVyLXNjb3BlZCBzdG9yYWdlIGludGVyZmFjZSBmb3Iga2V5LXZhbHVlIHBhaXJzIGZyb20gdGhlIFNlcnZlciBTaWRlIFN0b3JhZ2Ugc2VydmljZS5cbiAqIFRoaXMgaXMgTk9UIGZpbGVzeXN0ZW0gc3RvcmFnZSAtIGRhdGEgaXMgc3RvcmVkIGluIHRoZSByZW1vdGUgc3RvcmFnZSBzZXJ2aWNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElQbGF5ZXJTdG9yYWdlIHtcbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHZhbHVlIGZyb20gYSBwbGF5ZXIncyBzdG9yYWdlIGJ5IGtleSBmcm9tIHRoZSBTZXJ2ZXIgU2lkZSBTdG9yYWdlIHNlcnZpY2UuXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQgKGNhY2hlUmVhZHMpLCB2YWx1ZXMgcmVhZCBvciB3cml0dGVuIGR1cmluZyB0aGUgbGFzdCBjYWNoZU1heEFnZU1zXG4gICAqIGFyZSBzZXJ2ZWQgZnJvbSBhIGxvY2FsIGNhY2hlIHdpdGhvdXQgYSBuZXR3b3JrIHJlcXVlc3QsIGluY2x1ZGluZyBjb25maXJtZWRcbiAgICogXCJub3QgZm91bmRcIiByZXN1bHRzLiBDb25jdXJyZW50IGdldHMgZm9yIHRoZSBzYW1lIHBsYXllciBhbmQga2V5IHNoYXJlIG9uZVxuICAgKiByZXF1ZXN0LiBPdXQtb2YtYmFuZCB3cml0ZXJzIChlLmcuIENMSSBzdG9yYWdlIGNvbW1hbmRzKSBtYXkgbm90IGJlIHZpc2libGVcbiAgICogZm9yIHVwIHRvIGNhY2hlTWF4QWdlTXMg4oCUIHBhc3MgeyBmcmVzaDogdHJ1ZSB9IHRvIGZvcmNlIGEgbmV0d29yayByZWFkLlxuICAgKiBAcGFyYW0gYWRkcmVzcyAtIFRoZSBwbGF5ZXIncyB3YWxsZXQgYWRkcmVzc1xuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB0byByZXRyaWV2ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIHsgZnJlc2ggfSB0byBieXBhc3MgdGhlIHJlYWQgY2FjaGVcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHBhcnNlZCBKU09OIHZhbHVlLCBvciBudWxsIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgZ2V0PFQgPSB1bmtub3duPihhZGRyZXNzOiBzdHJpbmcsIGtleTogc3RyaW5nLCBvcHRpb25zPzogR2V0T3B0aW9ucyk6IFByb21pc2U8VCB8IG51bGw+XG5cbiAgLyoqXG4gICAqIFN0b3JlcyBhIHZhbHVlIGluIGEgcGxheWVyJ3Mgc3RvcmFnZSBpbiB0aGUgU2VydmVyIFNpZGUgU3RvcmFnZSBzZXJ2aWNlLlxuICAgKiBAcGFyYW0gYWRkcmVzcyAtIFRoZSBwbGF5ZXIncyB3YWxsZXQgYWRkcmVzc1xuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB0byBzdG9yZSB0aGUgdmFsdWUgdW5kZXJcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIHZhbHVlIHRvIHN0b3JlICh3aWxsIGJlIEpTT04gc2VyaWFsaXplZClcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCB7IHNraXBJZlVuY2hhbmdlZCB9IHRvIHNraXAgdGhlIG5ldHdvcmsgd3JpdGUgd2hlbiB0aGUgdmFsdWUgaXMgYWxyZWFkeSBzdG9yZWRcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiBzdWNjZXNzZnVsLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHNldDxUID0gdW5rbm93bj4oYWRkcmVzczogc3RyaW5nLCBrZXk6IHN0cmluZywgdmFsdWU6IFQsIG9wdGlvbnM/OiBTZXRPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPlxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGEgdmFsdWUgZnJvbSBhIHBsYXllcidzIHN0b3JhZ2UgaW4gdGhlIFNlcnZlciBTaWRlIFN0b3JhZ2Ugc2VydmljZS5cbiAgICogQHBhcmFtIGFkZHJlc3MgLSBUaGUgcGxheWVyJ3Mgd2FsbGV0IGFkZHJlc3NcbiAgICogQHBhcmFtIGtleSAtIFRoZSBrZXkgdG8gZGVsZXRlXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgaWYgZGVsZXRlZCwgZmFsc2UgaWYgbm90IGZvdW5kXG4gICAqL1xuICBkZWxldGUoYWRkcmVzczogc3RyaW5nLCBrZXk6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj5cblxuICAvKipcbiAgICogUmV0dXJucyBrZXktdmFsdWUgZW50cmllcyBmcm9tIGEgcGxheWVyJ3Mgc3RvcmFnZSwgb3B0aW9uYWxseSBmaWx0ZXJlZCBieSBwcmVmaXguXG4gICAqIFN1cHBvcnRzIHBhZ2luYXRpb24gdmlhIGxpbWl0IGFuZCBvZmZzZXQuXG4gICAqIEBwYXJhbSBhZGRyZXNzIC0gVGhlIHBsYXllcidzIHdhbGxldCBhZGRyZXNzXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgeyBwcmVmaXgsIGxpbWl0LCBvZmZzZXQgfSBmb3IgZmlsdGVyaW5nIGFuZCBwYWdpbmF0aW9uLlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB7IGRhdGEsIHBhZ2luYXRpb246IHsgb2Zmc2V0LCB0b3RhbCB9IH0gZm9yIHBhZ2luYXRpb24gVUlcbiAgICovXG4gIGdldFZhbHVlcyhhZGRyZXNzOiBzdHJpbmcsIG9wdGlvbnM/OiBHZXRWYWx1ZXNPcHRpb25zKTogUHJvbWlzZTxHZXRWYWx1ZXNSZXN1bHQ+XG59XG5cbi8qKlxuICogQ3JlYXRlcyBwbGF5ZXItc2NvcGVkIHN0b3JhZ2UgdGhhdCBwcm92aWRlcyBtZXRob2RzIHRvIGludGVyYWN0IHdpdGhcbiAqIHBsYXllci1zcGVjaWZpYyBrZXktdmFsdWUgcGFpcnMgZnJvbSB0aGUgU2VydmVyIFNpZGUgU3RvcmFnZSBzZXJ2aWNlLlxuICogVGhpcyBtb2R1bGUgb25seSB3b3JrcyB3aGVuIHJ1bm5pbmcgb24gc2VydmVyLXNpZGUgc2NlbmVzLlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBjb25zdCBjcmVhdGVQbGF5ZXJTdG9yYWdlID0gKGNvbmZpZzogU3RvcmFnZUNvbmZpZ1N0YXRlID0gY3JlYXRlU3RvcmFnZUNvbmZpZygpKTogSVBsYXllclN0b3JhZ2UgPT4ge1xuICBjb25zdCBjYWNoZSA9IGNyZWF0ZVZhbHVlQ2FjaGUoY29uZmlnKVxuICAvLyBFYWNoIGluLWZsaWdodCBHRVQgaXMgdHJhY2tlZCBieSBhIHdyYXBwZXIgb2JqZWN0IHdob3NlIGlkZW50aXR5IG1hcmtzXG4gIC8vIG93bmVyc2hpcDogc2V0KCkvZGVsZXRlKCkgZHJvcCB0aGUgd3JhcHBlciwgZGV0YWNoaW5nIHRoZSBwZW5kaW5nIEdFVCBzb1xuICAvLyBpdHMgc3RhbGUgcmVzcG9uc2UgY2Fubm90IG92ZXJ3cml0ZSB0aGUgbmV3ZXIgY2FjaGUgZW50cnkuXG4gIGNvbnN0IGluZmxpZ2h0R2V0cyA9IG5ldyBNYXA8c3RyaW5nLCB7IHByb21pc2U6IFByb21pc2U8dW5rbm93bj4gfT4oKVxuXG4gIC8vIEV0aGVyZXVtIGFkZHJlc3NlcyBhcmUgY2FzZS1pbnNlbnNpdGl2ZSAoY2hlY2tzdW0gY2FzaW5nIG9ubHkpLCBzb1xuICAvLyBtaXhlZC1jYXNlIGNhbGxlcnMgbXVzdCBzaGFyZSB0aGUgc2FtZSBjYWNoZSBlbnRyeS4gVGhlIE5VTCBzZXBhcmF0b3JcbiAgLy8gY2Fubm90IGFwcGVhciBpbiBhbiBhZGRyZXNzLCBtYWtpbmcgdGhlIHBhaXIgdW5hbWJpZ3VvdXMuXG4gIGNvbnN0IGNhY2hlS2V5ID0gKGFkZHJlc3M6IHN0cmluZywga2V5OiBzdHJpbmcpID0+IGAke2FkZHJlc3MudG9Mb3dlckNhc2UoKX1cXHUwMDAwJHtrZXl9YFxuXG4gIC8vIFdyaXRlcyB0byB0aGUgc2FtZSBwbGF5ZXIga2V5IGFyZSBzZXJpYWxpemVkIChhbmQgcmFwaWQgb25lcyBjb2FsZXNjZWQgdG9cbiAgLy8gdGhlIGxhdGVzdCB2YWx1ZSkgc28gdGhlIHNlcnZpY2UgY29tbWl0cyB0aGVtIGluIGlzc3VlIG9yZGVyIOKAlCBvdmVybGFwcGluZ1xuICAvLyBQVVRzIHdvdWxkIG90aGVyd2lzZSBsZWF2ZSBib3RoIHRoZSBrZXB0IHZhbHVlIGFuZCB0aGUgY2FjaGVkIHZhbHVlIHRvXG4gIC8vIHJlc3BvbnNlLW9yZGVyIGNoYW5jZS4gS2V5ZWQgYnkgdGhlIHNhbWUgY2FzZS1pbnNlbnNpdGl2ZSBjYWNoZSBrZXkuXG4gIGNvbnN0IHdyaXRlcyA9IGNyZWF0ZVdyaXRlUXVldWUoKVxuXG4gIGFzeW5jIGZ1bmN0aW9uIGV4ZWN1dGVTZXQoYWRkcmVzczogc3RyaW5nLCBrZXk6IHN0cmluZywgY2s6IHN0cmluZywgYm9keTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYmFzZVVybCA9IGF3YWl0IGdldFN0b3JhZ2VTZXJ2ZXJVcmwoKVxuICAgIGNvbnN0IHVybCA9IGAke2Jhc2VVcmx9L3BsYXllcnMvJHtlbmNvZGVVUklDb21wb25lbnQoYWRkcmVzcyl9L3ZhbHVlcy8ke2VuY29kZVVSSUNvbXBvbmVudChrZXkpfWBcblxuICAgIGNvbnN0IFtlcnJvcl0gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2goe1xuICAgICAgdXJsLFxuICAgICAgaW5pdDoge1xuICAgICAgICBtZXRob2Q6ICdQVVQnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ2NvbnRlbnQtdHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgICB9LFxuICAgICAgICBib2R5XG4gICAgICB9XG4gICAgfSlcblxuICAgIC8vIEVpdGhlciB3YXkgdGhlIGVudHJ5IGNoYW5nZWQgc2VydmVyLXNpZGUgKG9yIG1heSBoYXZlKTogZGV0YWNoIGFueVxuICAgIC8vIG92ZXJsYXBwaW5nIGluLWZsaWdodCBHRVQgc28gaXRzIHN0YWxlIHJlc3BvbnNlIGlzIG5vdCBjYWNoZWQuXG4gICAgaW5mbGlnaHRHZXRzLmRlbGV0ZShjaylcblxuICAgIGlmIChlcnJvcikge1xuICAgICAgLy8gVGhlIFBVVCBtYXkgaGF2ZSByZWFjaGVkIHRoZSBzZXJ2ZXIsIHNvIHRoZSBjYWNoZWQgYm9keSBpcyBub1xuICAgICAgLy8gbG9uZ2VyIHJlbGlhYmxlLlxuICAgICAgY2FjaGUuZGVsZXRlKGNrKVxuICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIHNldCBwbGF5ZXIgc3RvcmFnZSB2YWx1ZSAnJHtrZXl9JyBmb3IgJyR7YWRkcmVzc30nOiAke2Vycm9yfWApXG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICBjYWNoZS5zZXQoY2ssIHsgYm9keSB9KVxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBleGVjdXRlRGVsZXRlKGFkZHJlc3M6IHN0cmluZywga2V5OiBzdHJpbmcsIGNrOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBiYXNlVXJsID0gYXdhaXQgZ2V0U3RvcmFnZVNlcnZlclVybCgpXG4gICAgY29uc3QgdXJsID0gYCR7YmFzZVVybH0vcGxheWVycy8ke2VuY29kZVVSSUNvbXBvbmVudChhZGRyZXNzKX0vdmFsdWVzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KGtleSl9YFxuXG4gICAgY29uc3QgW2Vycm9yLCAsIHN0YXR1c10gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2goe1xuICAgICAgdXJsLFxuICAgICAgaW5pdDoge1xuICAgICAgICBtZXRob2Q6ICdERUxFVEUnLFxuICAgICAgICBoZWFkZXJzOiB7fVxuICAgICAgfVxuICAgIH0pXG5cbiAgICAvLyBEZXRhY2ggYWdhaW46IGEgR0VUIG1heSBoYXZlIHN0YXJ0ZWQgd2hpbGUgdGhlIERFTEVURSB3YXMgaW4gZmxpZ2h0LlxuICAgIGluZmxpZ2h0R2V0cy5kZWxldGUoY2spXG5cbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIC8vIEEgNDA0IHN0aWxsIGNvbmZpcm1zIHRoZSBrZXkgaXMgYWJzZW50IHNlcnZlci1zaWRlLlxuICAgICAgaWYgKHN0YXR1cyA9PT0gNDA0KSBjYWNoZS5zZXRBYnNlbnQoY2spXG4gICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlIHBsYXllciBzdG9yYWdlIHZhbHVlICcke2tleX0nIGZvciAnJHthZGRyZXNzfSc6ICR7ZXJyb3J9YClcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIGNhY2hlLnNldEFic2VudChjaylcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBhc3luYyBnZXQ8VCA9IHVua25vd24+KGFkZHJlc3M6IHN0cmluZywga2V5OiBzdHJpbmcsIG9wdGlvbnM/OiBHZXRPcHRpb25zKTogUHJvbWlzZTxUIHwgbnVsbD4ge1xuICAgICAgYXNzZXJ0SXNTZXJ2ZXIoTU9EVUxFX05BTUUpXG5cbiAgICAgIGNvbnN0IGNrID0gY2FjaGVLZXkoYWRkcmVzcywga2V5KVxuXG4gICAgICBpZiAoY29uZmlnLmNhY2hlUmVhZHMgJiYgIW9wdGlvbnM/LmZyZXNoKSB7XG4gICAgICAgIGNvbnN0IGVudHJ5ID0gY2FjaGUuZ2V0KGNrKVxuICAgICAgICBpZiAoZW50cnk/LmFic2VudCkgcmV0dXJuIG51bGxcbiAgICAgICAgLy8gUGFyc2UgcGVyIGhpdCBzbyBlYWNoIGNhbGxlciBnZXRzIGEgZnJlc2ggb2JqZWN0IChubyBzaGFyZWQgbXV0YXRpb24pLlxuICAgICAgICBpZiAoZW50cnk/LmJvZHkgIT09IHVuZGVmaW5lZCkgcmV0dXJuIEpTT04ucGFyc2UoZW50cnkuYm9keSkudmFsdWUgYXMgVFxuICAgICAgfVxuXG4gICAgICAvLyBDb2FsZXNjZSBjb25jdXJyZW50IGdldHMgKGV2ZW4gZnJlc2ggb25lczogYW4gaW4tZmxpZ2h0IHJlc3BvbnNlIGlzXG4gICAgICAvLyBtaWxsaXNlY29uZHMgb2xkLCBub3QgVFRMLXN0YWxlKSBpbnRvIGEgc2luZ2xlIG5ldHdvcmsgcmVxdWVzdC5cbiAgICAgIGNvbnN0IGpvaW5lZCA9IGluZmxpZ2h0R2V0cy5nZXQoY2spXG4gICAgICBpZiAoam9pbmVkKSByZXR1cm4gam9pbmVkLnByb21pc2UgYXMgUHJvbWlzZTxUIHwgbnVsbD5cblxuICAgICAgY29uc3QgaW5mbGlnaHQgPSB7fSBhcyB7IHByb21pc2U6IFByb21pc2U8VCB8IG51bGw+IH1cbiAgICAgIGluZmxpZ2h0LnByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGJhc2VVcmwgPSBhd2FpdCBnZXRTdG9yYWdlU2VydmVyVXJsKClcbiAgICAgICAgICBjb25zdCB1cmwgPSBgJHtiYXNlVXJsfS9wbGF5ZXJzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KGFkZHJlc3MpfS92YWx1ZXMvJHtlbmNvZGVVUklDb21wb25lbnQoa2V5KX1gXG5cbiAgICAgICAgICBjb25zdCBbZXJyb3IsIGRhdGEsIHN0YXR1c10gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2g8eyB2YWx1ZTogVCB9Pih7IHVybCB9KVxuXG4gICAgICAgICAgY29uc3QgaXNPd25lciA9IGluZmxpZ2h0R2V0cy5nZXQoY2spID09PSBpbmZsaWdodFxuXG4gICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBBIGNvbmZpcm1lZCA0MDQgaXMgYSBmaXJzdC1jbGFzcyBcImFic2VudFwiIG91dGNvbWUsIG5vdCBhIGZhaWx1cmUuXG4gICAgICAgICAgICBpZiAoc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgICAgICAgaWYgKGlzT3duZXIpIGNhY2hlLnNldEFic2VudChjaylcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBnZXQgcGxheWVyIHN0b3JhZ2UgdmFsdWUgJyR7a2V5fScgZm9yICcke2FkZHJlc3N9JzogJHtlcnJvcn1gKVxuICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoZGF0YSAmJiBkYXRhLnZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIFNhbWUgc2VyaWFsaXphdGlvbiBzaGFwZSBhcyBzZXQoKSdzIFBVVCBib2R5LCBzbyBhIHJlYWQgZm9sbG93ZWQgYnlcbiAgICAgICAgICAgIC8vIGFuIHVuY2hhbmdlZCB3cml0ZSBjYW4gYmUgc2tpcHBlZC5cbiAgICAgICAgICAgIGNvbnN0IGJvZHkgPSBKU09OLnN0cmluZ2lmeSh7IHZhbHVlOiBkYXRhLnZhbHVlIH0pXG4gICAgICAgICAgICBpZiAoaXNPd25lcikgY2FjaGUuc2V0KGNrLCB7IGJvZHkgfSlcbiAgICAgICAgICAgIHJldHVybiBkYXRhLnZhbHVlXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gMjAwIHdpdGggYSBtaXNzaW5nIHZhbHVlIGlzIGFtYmlndW91czogbmVpdGhlciBhIGNvbmZpcm1lZCB2YWx1ZVxuICAgICAgICAgIC8vIG5vciBhIGNvbmZpcm1lZCBhYnNlbmNlLCBzbyBjYWNoZSBub3RoaW5nLlxuICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgaWYgKGluZmxpZ2h0R2V0cy5nZXQoY2spID09PSBpbmZsaWdodCkgaW5mbGlnaHRHZXRzLmRlbGV0ZShjaylcbiAgICAgICAgfVxuICAgICAgfSkoKVxuXG4gICAgICBpbmZsaWdodEdldHMuc2V0KGNrLCBpbmZsaWdodClcbiAgICAgIHJldHVybiBpbmZsaWdodC5wcm9taXNlXG4gICAgfSxcblxuICAgIGFzeW5jIHNldDxUID0gdW5rbm93bj4oYWRkcmVzczogc3RyaW5nLCBrZXk6IHN0cmluZywgdmFsdWU6IFQsIG9wdGlvbnM/OiBTZXRPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICBhc3NlcnRJc1NlcnZlcihNT0RVTEVfTkFNRSlcblxuICAgICAgY29uc3QgY2sgPSBjYWNoZUtleShhZGRyZXNzLCBrZXkpXG4gICAgICBjb25zdCBib2R5ID0gSlNPTi5zdHJpbmdpZnkoeyB2YWx1ZSB9KVxuICAgICAgY29uc3Qgc2tpcElmVW5jaGFuZ2VkID0gb3B0aW9ucz8uc2tpcElmVW5jaGFuZ2VkID8/IGNvbmZpZy5za2lwSWZVbmNoYW5nZWRcblxuICAgICAgLy8gRGVkdXAgYWdhaW5zdCBjb25maXJtZWQgc3RhdGUgb25seSB3aGlsZSBubyB3cml0ZSBpcyBwZW5kaW5nIOKAlCBhXG4gICAgICAvLyBwZW5kaW5nIHdyaXRlIG1ha2VzIHRoZSBjYWNoZSBtb21lbnRhcmlseSBzdGFsZTsgZW5xdWV1ZSgpIGNvYWxlc2Nlc1xuICAgICAgLy8gYWdhaW5zdCBwZW5kaW5nIHdyaXRlcyBpbnN0ZWFkLlxuICAgICAgaWYgKHNraXBJZlVuY2hhbmdlZCAmJiB3cml0ZXMucGVuZGluZyhjaykgPT09IHVuZGVmaW5lZCAmJiBjYWNoZS5nZXQoY2spPy5ib2R5ID09PSBib2R5KSB7XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB3cml0ZXMuZW5xdWV1ZShjaywgYm9keSwgKGIpID0+IGV4ZWN1dGVTZXQoYWRkcmVzcywga2V5LCBjaywgYiBhcyBzdHJpbmcpLCBza2lwSWZVbmNoYW5nZWQpXG4gICAgfSxcblxuICAgIGFzeW5jIGRlbGV0ZShhZGRyZXNzOiBzdHJpbmcsIGtleTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICBhc3NlcnRJc1NlcnZlcihNT0RVTEVfTkFNRSlcblxuICAgICAgY29uc3QgY2sgPSBjYWNoZUtleShhZGRyZXNzLCBrZXkpXG5cbiAgICAgIC8vIEludmFsaWRhdGUgaW1tZWRpYXRlbHkg4oCUIGV2ZW4gd2hpbGUgdGhlIERFTEVURSB3YWl0cyBiZWhpbmQgb3RoZXJcbiAgICAgIC8vIHdyaXRlcywgcmVhZHMgbXVzdCBub3Qgc2VydmUgdGhlIGRvb21lZCB2YWx1ZSwgYW5kIGEgc3RhbGVcbiAgICAgIC8vIFwidW5jaGFuZ2VkXCIgc2tpcCB3b3VsZCBsb3NlIGEgZnV0dXJlIHdyaXRlLlxuICAgICAgY2FjaGUuZGVsZXRlKGNrKVxuICAgICAgaW5mbGlnaHRHZXRzLmRlbGV0ZShjaylcblxuICAgICAgcmV0dXJuIHdyaXRlcy5lbnF1ZXVlKGNrLCBudWxsLCAoKSA9PiBleGVjdXRlRGVsZXRlKGFkZHJlc3MsIGtleSwgY2spLCB0cnVlKVxuICAgIH0sXG5cbiAgICBhc3luYyBnZXRWYWx1ZXMoYWRkcmVzczogc3RyaW5nLCBvcHRpb25zPzogR2V0VmFsdWVzT3B0aW9ucyk6IFByb21pc2U8R2V0VmFsdWVzUmVzdWx0PiB7XG4gICAgICBhc3NlcnRJc1NlcnZlcihNT0RVTEVfTkFNRSlcblxuICAgICAgY29uc3QgeyBwcmVmaXgsIGxpbWl0LCBvZmZzZXQgfSA9IG9wdGlvbnMgPz8ge31cbiAgICAgIGNvbnN0IGJhc2VVcmwgPSBhd2FpdCBnZXRTdG9yYWdlU2VydmVyVXJsKClcbiAgICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdXG5cbiAgICAgIGlmICghIXByZWZpeCkge1xuICAgICAgICBwYXJ0cy5wdXNoKGBwcmVmaXg9JHtlbmNvZGVVUklDb21wb25lbnQocHJlZml4KX1gKVxuICAgICAgfVxuXG4gICAgICBpZiAoISFsaW1pdCkge1xuICAgICAgICBwYXJ0cy5wdXNoKGBsaW1pdD0ke2xpbWl0fWApXG4gICAgICB9XG5cbiAgICAgIGlmICghIW9mZnNldCkge1xuICAgICAgICBwYXJ0cy5wdXNoKGBvZmZzZXQ9JHtvZmZzZXR9YClcbiAgICAgIH1cblxuICAgICAgY29uc3QgcXVlcnkgPSBwYXJ0cy5qb2luKCcmJylcbiAgICAgIGNvbnN0IHVybCA9IHF1ZXJ5XG4gICAgICAgID8gYCR7YmFzZVVybH0vcGxheWVycy8ke2VuY29kZVVSSUNvbXBvbmVudChhZGRyZXNzKX0vdmFsdWVzPyR7cXVlcnl9YFxuICAgICAgICA6IGAke2Jhc2VVcmx9L3BsYXllcnMvJHtlbmNvZGVVUklDb21wb25lbnQoYWRkcmVzcyl9L3ZhbHVlc2BcblxuICAgICAgY29uc3QgW2Vycm9yLCByZXNwb25zZV0gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2g8R2V0VmFsdWVzUmVzdWx0Pih7IHVybCB9KVxuXG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGdldCBwbGF5ZXIgc3RvcmFnZSB2YWx1ZXMgZm9yICcke2FkZHJlc3N9JzogJHtlcnJvcn1gKVxuICAgICAgICByZXR1cm4geyBkYXRhOiBbXSwgcGFnaW5hdGlvbjogeyBvZmZzZXQ6IDAsIHRvdGFsOiAwIH0gfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBkYXRhID0gcmVzcG9uc2U/LmRhdGEgPz8gW11cblxuICAgICAgLy8gU2VlZCB0aGUgcGVyLWtleSBjYWNoZSBzbyBzdWJzZXF1ZW50IGdldCgpL3NldCgpIG9uIHJldHVybmVkIGtleXMgY2FuXG4gICAgICAvLyBza2lwIHRoZSBuZXR3b3JrLiBPbmx5IGtleXMgd2l0aCBubyBsaXZlIGVudHJ5IGFuZCBubyBwZW5kaW5nIHdyaXRlXG4gICAgICAvLyBhcmUgc2VlZGVkOiBleGlzdGluZyBwZXIta2V5IHN0YXRlIGNvbWVzIGZyb20gYSBjb25maXJtZWQgb3BlcmF0aW9uXG4gICAgICAvLyB0aGF0IHRoaXMgcGFnZSBzbmFwc2hvdCDigJQgd2hvc2UgcmVxdWVzdCBzdGFydGVkIGVhcmxpZXIg4oCUIG11c3Qgbm90XG4gICAgICAvLyBjbG9iYmVyIHdpdGggc3RhbGUgZGF0YS4gQWJzZW5jZSBpcyBuZXZlciBzZWVkZWQgKHByZWZpeC9wYWdpbmF0aW9uXG4gICAgICAvLyBtYWtlIGl0IG5vbi1hdXRob3JpdGF0aXZlKS4gQSBwYWdlIGxhcmdlciB0aGFuIGNhY2hlTWF4RW50cmllcyBjaHVybnNcbiAgICAgIC8vIHRoZSBjYWNoZTsgZW50cmllcyByZXBvcHVsYXRlIGxhemlseS5cbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZGF0YSkge1xuICAgICAgICBjb25zdCBjayA9IGNhY2hlS2V5KGFkZHJlc3MsIGVudHJ5LmtleSlcbiAgICAgICAgaWYgKGVudHJ5LnZhbHVlICE9PSB1bmRlZmluZWQgJiYgIXdyaXRlcy5pc1BlbmRpbmcoY2spICYmIGNhY2hlLmdldChjaykgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGNhY2hlLnNldChjaywgeyBib2R5OiBKU09OLnN0cmluZ2lmeSh7IHZhbHVlOiBlbnRyeS52YWx1ZSB9KSB9KVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlcXVlc3RlZE9mZnNldCA9IG9mZnNldCA/PyAwXG4gICAgICBjb25zdCBwYWdpbmF0aW9uID0ge1xuICAgICAgICBvZmZzZXQ6IHJlc3BvbnNlPy5wYWdpbmF0aW9uPy5vZmZzZXQgPz8gcmVxdWVzdGVkT2Zmc2V0LFxuICAgICAgICB0b3RhbDogcmVzcG9uc2U/LnBhZ2luYXRpb24/LnRvdGFsID8/IGRhdGEubGVuZ3RoXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7IGRhdGEsIHBhZ2luYXRpb24gfVxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { GetOptions, GetValuesOptions, GetValuesResult, SetOptions } from './constants';
|
|
2
|
-
/**
|
|
3
|
-
* Scene-scoped storage interface for key-value pairs from the Server Side Storage service.
|
|
4
|
-
* This is NOT filesystem storage - data is stored in the remote storage service.
|
|
5
|
-
*/
|
|
6
|
-
export interface ISceneStorage {
|
|
7
|
-
/**
|
|
8
|
-
* Retrieves a value from scene storage by key from the Server Side Storage service.
|
|
9
|
-
*
|
|
10
|
-
* By default (cacheReads), values read or written during the last cacheMaxAgeMs
|
|
11
|
-
* are served from a local cache without a network request, including confirmed
|
|
12
|
-
* "not found" results. Concurrent gets for the same key share one request.
|
|
13
|
-
* Out-of-band writers (e.g. CLI storage commands) may not be visible for up to
|
|
14
|
-
* cacheMaxAgeMs — pass { fresh: true } to force a network read.
|
|
15
|
-
* @param key - The key to retrieve
|
|
16
|
-
* @param options - Optional { fresh } to bypass the read cache
|
|
17
|
-
* @returns A promise that resolves to the parsed JSON value, or null if not found
|
|
18
|
-
*/
|
|
19
|
-
get<T = unknown>(key: string, options?: GetOptions): Promise<T | null>;
|
|
20
|
-
/**
|
|
21
|
-
* Stores a value in scene storage in the Server Side Storage service.
|
|
22
|
-
* @param key - The key to store the value under
|
|
23
|
-
* @param value - The value to store (will be JSON serialized)
|
|
24
|
-
* @param options - Optional { skipIfUnchanged } to skip the network write when the value is already stored
|
|
25
|
-
*/
|
|
26
|
-
set<T = unknown>(key: string, value: T, options?: SetOptions): Promise<boolean>;
|
|
27
|
-
/**
|
|
28
|
-
* Deletes a value from scene storage in the Server Side Storage service.
|
|
29
|
-
* @param key - The key to delete
|
|
30
|
-
* @returns A promise that resolves to true if deleted, false if not found
|
|
31
|
-
*/
|
|
32
|
-
delete(key: string): Promise<boolean>;
|
|
33
|
-
/**
|
|
34
|
-
* Returns key-value entries from scene storage, optionally filtered by prefix.
|
|
35
|
-
* Supports pagination via limit and offset.
|
|
36
|
-
* @param options - Optional { prefix, limit, offset } for filtering and pagination.
|
|
37
|
-
* @returns A promise that resolves to { data, pagination: { offset, total } } for pagination UI
|
|
38
|
-
*/
|
|
39
|
-
getValues(options?: GetValuesOptions): Promise<GetValuesResult>;
|
|
40
|
-
}
|