@dcl/sdk 7.30.2-37804519171.commit-60e3717 → 7.30.2-37807847179.commit-24c42ea
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/atom.d.ts +19 -0
- package/atom.js +83 -0
- package/future.d.ts +8 -0
- package/future.js +26 -0
- package/internal/transports/rendererTransport.js +5 -2
- package/network/binary-message-bus.d.ts +6 -3
- package/network/binary-message-bus.js +9 -5
- package/network/chunking.d.ts +5 -0
- package/network/chunking.js +38 -0
- package/network/events/implementation.d.ts +93 -0
- package/network/events/implementation.js +221 -0
- package/network/events/index.d.ts +42 -0
- package/network/events/index.js +43 -0
- package/network/events/protocol.d.ts +27 -0
- package/network/events/protocol.js +66 -0
- package/network/events/registry.d.ts +8 -0
- package/network/events/registry.js +3 -0
- package/network/index.d.ts +8 -2
- package/network/index.js +16 -3
- package/network/message-bus-sync.d.ts +16 -3
- package/network/message-bus-sync.js +164 -103
- package/network/server/index.d.ts +14 -0
- package/network/server/index.js +256 -0
- package/network/server/utils.d.ts +18 -0
- package/network/server/utils.js +135 -0
- package/network/state.js +3 -5
- package/package.json +6 -6
- package/server/env-var.d.ts +15 -0
- package/server/env-var.js +31 -0
- package/server/index.d.ts +2 -0
- package/server/index.js +3 -0
- package/server/storage/constants.d.ts +80 -0
- package/server/storage/constants.js +19 -0
- package/server/storage/error-message.d.ts +1 -0
- package/server/storage/error-message.js +9 -0
- package/server/storage/index.d.ts +54 -0
- package/server/storage/index.js +60 -0
- package/server/storage/player.d.ts +60 -0
- package/server/storage/player.js +244 -0
- package/server/storage/scene.d.ts +55 -0
- package/server/storage/scene.js +232 -0
- package/server/storage/serialize.d.ts +1 -0
- package/server/storage/serialize.js +135 -0
- package/server/storage/value-cache.d.ts +1 -0
- package/server/storage/value-cache.js +67 -0
- package/server/storage/write-queue.d.ts +1 -0
- package/server/storage/write-queue.js +113 -0
- package/server/storage-url.d.ts +13 -0
- package/server/storage-url.js +42 -0
- package/server/utils.d.ts +35 -0
- package/server/utils.js +69 -0
- package/src/atom.ts +98 -0
- package/src/future.ts +38 -0
- package/src/internal/transports/rendererTransport.ts +4 -1
- package/src/network/binary-message-bus.ts +9 -4
- package/src/network/chunking.ts +45 -0
- package/src/network/events/implementation.ts +271 -0
- package/src/network/events/index.ts +48 -0
- package/src/network/events/protocol.ts +94 -0
- package/src/network/events/registry.ts +18 -0
- package/src/network/index.ts +40 -3
- package/src/network/message-bus-sync.ts +180 -112
- package/src/network/server/index.ts +341 -0
- package/src/network/server/utils.ts +189 -0
- package/src/network/state.ts +3 -4
- package/src/server/env-var.ts +36 -0
- package/src/server/index.ts +12 -0
- package/src/server/storage/constants.ts +112 -0
- package/src/server/storage/error-message.ts +8 -0
- package/src/server/storage/index.ts +83 -0
- package/src/server/storage/player.ts +345 -0
- package/src/server/storage/scene.ts +324 -0
- package/src/server/storage/serialize.ts +132 -0
- package/src/server/storage/value-cache.ts +119 -0
- package/src/server/storage/write-queue.ts +174 -0
- package/src/server/storage-url.ts +49 -0
- package/src/server/utils.ts +83 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const LONE_SURROGATE = /[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;
|
|
2
|
+
const UNSTORABLE_TEXT = /\u0000/;
|
|
3
|
+
const MAX_KEY_LENGTH = 255;
|
|
4
|
+
/**
|
|
5
|
+
* JSON.stringify always writes NUL as `\u0000` and an unpaired surrogate as a `\udXXX` escape (ES2019),
|
|
6
|
+
* while paired surrogates stay raw; an escaped backslash in front means the text is literal.
|
|
7
|
+
*/
|
|
8
|
+
const ESCAPED_UNSTORABLE_TEXT = /(?<!\\)(?:\\\\)*\\u(?:0000|d[89a-f][0-9a-f]{2})/i;
|
|
9
|
+
/** Raised from inside the replacer, so it is not mistaken for an engine error. */
|
|
10
|
+
class UnstorableValueError extends TypeError {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The `{ value }` PUT body. Rejects, at any depth, what JSON would drop or change: functions,
|
|
14
|
+
* symbols, non-finite numbers, `undefined` array elements and holes, built-ins with no JSON form
|
|
15
|
+
* (Map, Set, typed arrays, RegExp, Error, ...), and text the service cannot store. An `undefined`
|
|
16
|
+
* object property is dropped, as it reads back the same.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export function serializeStorageValue(value, callSite) {
|
|
20
|
+
const body = stringify(value, callSite, fastReason);
|
|
21
|
+
// Text is checked once on the output; only a rejection pays for locating the offending item.
|
|
22
|
+
if (ESCAPED_UNSTORABLE_TEXT.test(body)) {
|
|
23
|
+
stringify(value, callSite, unstorable);
|
|
24
|
+
throw new TypeError(`${callSite}: value must not contain an unpaired surrogate or a NUL character.`);
|
|
25
|
+
}
|
|
26
|
+
if (body === '{}') {
|
|
27
|
+
throw new TypeError(`${callSite}: value must be JSON-serializable. Use delete() to remove a key.`);
|
|
28
|
+
}
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
function stringify(value, callSite, reason) {
|
|
32
|
+
const envelope = { value };
|
|
33
|
+
try {
|
|
34
|
+
return JSON.stringify(envelope, function (property, item) {
|
|
35
|
+
const why = reason(this, property, item);
|
|
36
|
+
if (why) {
|
|
37
|
+
const where = this === envelope ? 'the value' : `"${property}"`;
|
|
38
|
+
throw new UnstorableValueError(`${callSite}: value must be JSON-serializable, but ${where} ${why}. Use delete() to remove a key.`);
|
|
39
|
+
}
|
|
40
|
+
return item;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof UnstorableValueError)
|
|
45
|
+
throw error;
|
|
46
|
+
const cause = error instanceof Error ? error.message.split('\n')[0] : String(error);
|
|
47
|
+
throw new TypeError(`${callSite}: value must be JSON-serializable (${cause}). Use delete() to remove a key.`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Everything but the text checks, with plain objects and arrays skipping the built-in check. */
|
|
51
|
+
function fastReason(holder, property, item) {
|
|
52
|
+
switch (typeof item) {
|
|
53
|
+
case 'function':
|
|
54
|
+
case 'symbol':
|
|
55
|
+
return `is a ${typeof item}`;
|
|
56
|
+
case 'number':
|
|
57
|
+
return Number.isFinite(item) ? undefined : `is the non-finite number ${item}`;
|
|
58
|
+
case 'undefined':
|
|
59
|
+
if (Array.isArray(holder))
|
|
60
|
+
return 'is undefined or a hole in an array';
|
|
61
|
+
return holder[property] !== undefined ? 'has a toJSON() that returns undefined' : undefined;
|
|
62
|
+
case 'object': {
|
|
63
|
+
if (item === null || Array.isArray(item))
|
|
64
|
+
return undefined;
|
|
65
|
+
const prototype = Object.getPrototypeOf(item);
|
|
66
|
+
return prototype === Object.prototype || prototype === null ? undefined : builtInReason(item);
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Every check, per item: used to name the item a text rejection comes from. */
|
|
73
|
+
function unstorable(holder, property, item) {
|
|
74
|
+
const fast = fastReason(holder, property, item);
|
|
75
|
+
if (fast)
|
|
76
|
+
return fast;
|
|
77
|
+
if (typeof item === 'string' && (LONE_SURROGATE.test(item) || UNSTORABLE_TEXT.test(item))) {
|
|
78
|
+
return 'contains an unpaired surrogate or a NUL character';
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(holder) && (LONE_SURROGATE.test(property) || UNSTORABLE_TEXT.test(property))) {
|
|
81
|
+
return 'is a key with an unpaired surrogate or a NUL character';
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
function builtInReason(item) {
|
|
86
|
+
const builtIn = builtInName(item);
|
|
87
|
+
return builtIn ? `is ${/^[AEIO]/.test(builtIn) ? 'an' : 'a'} ${builtIn}, which has no JSON form` : undefined;
|
|
88
|
+
}
|
|
89
|
+
function builtInName(item) {
|
|
90
|
+
if (item === null || typeof item !== 'object')
|
|
91
|
+
return undefined;
|
|
92
|
+
if (item instanceof Map)
|
|
93
|
+
return 'Map';
|
|
94
|
+
if (item instanceof Set)
|
|
95
|
+
return 'Set';
|
|
96
|
+
if (item instanceof WeakMap)
|
|
97
|
+
return 'WeakMap';
|
|
98
|
+
if (item instanceof WeakSet)
|
|
99
|
+
return 'WeakSet';
|
|
100
|
+
if (item instanceof RegExp)
|
|
101
|
+
return 'RegExp';
|
|
102
|
+
if (item instanceof Error)
|
|
103
|
+
return 'Error';
|
|
104
|
+
if (item instanceof Promise)
|
|
105
|
+
return 'Promise';
|
|
106
|
+
if (item instanceof ArrayBuffer)
|
|
107
|
+
return 'ArrayBuffer';
|
|
108
|
+
if (ArrayBuffer.isView(item))
|
|
109
|
+
return item.constructor?.name ?? 'typed array';
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Keys and player addresses go into the request path, where `.`, `..` and an empty segment are
|
|
114
|
+
* resolved away by URL parsing, so they would address a different resource.
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
export function assertStorageKey(key, callSite) {
|
|
118
|
+
if (typeof key !== 'string' || key === '' || key === '.' || key === '..') {
|
|
119
|
+
throw new TypeError(`${callSite}: key must be a non-empty string other than "." and "..".`);
|
|
120
|
+
}
|
|
121
|
+
if (LONE_SURROGATE.test(key) || UNSTORABLE_TEXT.test(key)) {
|
|
122
|
+
throw new TypeError(`${callSite}: key must not contain an unpaired surrogate or a NUL character.`);
|
|
123
|
+
}
|
|
124
|
+
// Counted in characters, as the service counts them.
|
|
125
|
+
if ([...key].length > MAX_KEY_LENGTH) {
|
|
126
|
+
throw new TypeError(`${callSite}: key must be at most ${MAX_KEY_LENGTH} characters.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** @internal */
|
|
130
|
+
export function assertPlayerAddress(address, callSite) {
|
|
131
|
+
if (typeof address !== 'string' || !/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
132
|
+
throw new TypeError(`${callSite}: address must be a 0x-prefixed 20-byte hex address.`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsaXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci9zdG9yYWdlL3NlcmlhbGl6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLGNBQWMsR0FBRyx3RUFBd0UsQ0FBQTtBQUMvRixNQUFNLGVBQWUsR0FBRyxRQUFRLENBQUE7QUFDaEMsTUFBTSxjQUFjLEdBQUcsR0FBRyxDQUFBO0FBRTFCOzs7R0FHRztBQUNILE1BQU0sdUJBQXVCLEdBQUcsa0RBQWtELENBQUE7QUFFbEYsa0ZBQWtGO0FBQ2xGLE1BQU0sb0JBQXFCLFNBQVEsU0FBUztDQUFHO0FBSS9DOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxLQUFjLEVBQUUsUUFBZ0I7SUFDcEUsTUFBTSxJQUFJLEdBQUcsU0FBUyxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDbkQsNkZBQTZGO0lBQzdGLElBQUksdUJBQXVCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQ3RDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBQ3RDLE1BQU0sSUFBSSxTQUFTLENBQUMsR0FBRyxRQUFRLG9FQUFvRSxDQUFDLENBQUE7S0FDckc7SUFDRCxJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxJQUFJLFNBQVMsQ0FBQyxHQUFHLFFBQVEsa0VBQWtFLENBQUMsQ0FBQTtLQUNuRztJQUNELE9BQU8sSUFBSSxDQUFBO0FBQ2IsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEtBQWMsRUFBRSxRQUFnQixFQUFFLE1BQWM7SUFDakUsTUFBTSxRQUFRLEdBQUcsRUFBRSxLQUFLLEVBQUUsQ0FBQTtJQUMxQixJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxVQUF5QyxRQUFRLEVBQUUsSUFBSTtZQUNyRixNQUFNLEdB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QixDQUFDLEdBQVksRUFBRSxRQUFnQjtJQUM3RCxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLEtBQUssRUFBRSxJQUFJLEdBQUcsS0FBSyxHQUFHLElBQUksR0FBRyxLQUFLLElBQUksRUFBRTtRQUN4RSxNQUFNLElBQUksU0FBUyxDQUFDLEdBQUcsUUFBUSwyREFBMkQsQ0FBQyxDQUFBO0tBQzVGO0lBQ0QsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUU7UUFDekQsTUFBTSxJQUFJLFNBQVMsQ0FBQyxHQUFHLFFBQVEsa0VBQWtFLENBQUMsQ0FBQTtLQUNuRztJQUNELHFEQUFxRDtJQUNyRCxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxNQUFNLEdBQUcsY0FBYyxFQUFFO1FBQ3BDLE1BQU0sSUFBSSxTQUFTLENBQUMsR0FBRyxRQUFRLHlCQUF5QixjQUFjLGNBQWMsQ0FBQyxDQUFBO0tBQ3RGO0FBQ0gsQ0FBQztBQUVELGdCQUFnQjtBQUNoQixNQUFNLFVBQVUsbUJBQW1CLENBQUMsT0FBZ0IsRUFBRSxRQUFnQjtJQUNwRSxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUN2RSxNQUFNLElBQUksU0FBUyxDQUFDLEdBQUcsUUFBUSxzREFBc0QsQ0FBQyxDQUFBO0tBQ3ZGO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImNvbnN0IExPTkVfU1VSUk9HQVRFID0gL1tcXHVkODAwLVxcdWRiZmZdKD8hW1xcdWRjMDAtXFx1ZGZmZl0pfCg/PCFbXFx1ZDgwMC1cXHVkYmZmXSlbXFx1ZGMwMC1cXHVkZmZmXS9cbmNvbnN0IFVOU1RPUkFCTEVfVEVYVCA9IC9cXHUwMDAwL1xuY29uc3QgTUFYX0tFWV9MRU5HVEggPSAyNTVcblxuLyoqXG4gKiBKU09OLnN0cmluZ2lmeSBhbHdheXMgd3JpdGVzIE5VTCBhcyBgXFx1MDAwMGAgYW5kIGFuIHVucGFpcmVkIHN1cnJvZ2F0ZSBhcyBhIGBcXHVkWFhYYCBlc2NhcGUgKEVTMjAxOSksXG4gKiB3aGlsZSBwYWlyZWQgc3Vycm9nYXRlcyBzdGF5IHJhdzsgYW4gZXNjYXBlZCBiYWNrc2xhc2ggaW4gZnJvbnQgbWVhbnMgdGhlIHRleHQgaXMgbGl0ZXJhbC5cbiAqL1xuY29uc3QgRVNDQVBFRF9VTlNUT1JBQkxFX1RFWFQgPSAvKD88IVxcXFwpKD86XFxcXFxcXFwpKlxcXFx1KD86MDAwMHxkWzg5YS1mXVswLTlhLWZdezJ9KS9pXG5cbi8qKiBSYWlzZWQgZnJvbSBpbnNpZGUgdGhlIHJlcGxhY2VyLCBzbyBpdCBpcyBub3QgbWlzdGFrZW4gZm9yIGFuIGVuZ2luZSBlcnJvci4gKi9cbmNsYXNzIFVuc3RvcmFibGVWYWx1ZUVycm9yIGV4dGVuZHMgVHlwZUVycm9yIHt9XG5cbnR5cGUgUmVhc29uID0gKGhvbGRlcjogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHByb3BlcnR5OiBzdHJpbmcsIGl0ZW06IHVua25vd24pID0+IHN0cmluZyB8IHVuZGVmaW5lZFxuXG4vKipcbiAqIFRoZSBgeyB2YWx1ZSB9YCBQVVQgYm9keS4gUmVqZWN0cywgYXQgYW55IGRlcHRoLCB3aGF0IEpTT04gd291bGQgZHJvcCBvciBjaGFuZ2U6IGZ1bmN0aW9ucyxcbiAqIHN5bWJvbHMsIG5vbi1maW5pdGUgbnVtYmVycywgYHVuZGVmaW5lZGAgYXJyYXkgZWxlbWVudHMgYW5kIGhvbGVzLCBidWlsdC1pbnMgd2l0aCBubyBKU09OIGZvcm1cbiAqIChNYXAsIFNldCwgdHlwZWQgYXJyYXlzLCBSZWdFeHAsIEVycm9yLCAuLi4pLCBhbmQgdGV4dCB0aGUgc2VydmljZSBjYW5ub3Qgc3RvcmUuIEFuIGB1bmRlZmluZWRgXG4gKiBvYmplY3QgcHJvcGVydHkgaXMgZHJvcHBlZCwgYXMgaXQgcmVhZHMgYmFjayB0aGUgc2FtZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplU3RvcmFnZVZhbHVlKHZhbHVlOiB1bmtub3duLCBjYWxsU2l0ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgYm9keSA9IHN0cmluZ2lmeSh2YWx1ZSwgY2FsbFNpdGUsIGZhc3RSZWFzb24pXG4gIC8vIFRleHQgaXMgY2hlY2tlZCBvbmNlIG9uIHRoZSBvdXRwdXQ7IG9ubHkgYSByZWplY3Rpb24gcGF5cyBmb3IgbG9jYXRpbmcgdGhlIG9mZmVuZGluZyBpdGVtLlxuICBpZiAoRVNDQVBFRF9VTlNUT1JBQkxFX1RFWFQudGVzdChib2R5KSkge1xuICAgIHN0cmluZ2lmeSh2YWx1ZSwgY2FsbFNpdGUsIHVuc3RvcmFibGUpXG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtjYWxsU2l0ZX06IHZhbHVlIG11c3Qgbm90IGNvbnRhaW4gYW4gdW5wYWlyZWQgc3Vycm9nYXRlIG9yIGEgTlVMIGNoYXJhY3Rlci5gKVxuICB9XG4gIGlmIChib2R5ID09PSAne30nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtjYWxsU2l0ZX06IHZhbHVlIG11c3QgYmUgSlNPTi1zZXJpYWxpemFibGUuIFVzZSBkZWxldGUoKSB0byByZW1vdmUgYSBrZXkuYClcbiAgfVxuICByZXR1cm4gYm9keVxufVxuXG5mdW5jdGlvbiBzdHJpbmdpZnkodmFsdWU6IHVua25vd24sIGNhbGxTaXRlOiBzdHJpbmcsIHJlYXNvbjogUmVhc29uKTogc3RyaW5nIHtcbiAgY29uc3QgZW52ZWxvcGUgPSB7IHZhbHVlIH1cbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUsIGZ1bmN0aW9uICh0aGlzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgcHJvcGVydHksIGl0ZW0pIHtcbiAgICAgIGNvbnN0IHdoeSA9IHJlYXNvbih0aGlzLCBwcm9wZXJ0eSwgaXRlbSlcbiAgICAgIGlmICh3aHkpIHtcbiAgICAgICAgY29uc3Qgd2hlcmUgPSB0aGlzID09PSBlbnZlbG9wZSA/ICd0aGUgdmFsdWUnIDogYFwiJHtwcm9wZXJ0eX1cImBcbiAgICAgICAgdGhyb3cgbmV3IFVuc3RvcmFibGVWYWx1ZUVycm9yKFxuICAgICAgICAgIGAke2NhbGxTaXRlfTogdmFsdWUgbXVzdCBiZSBKU09OLXNlcmlhbGl6YWJsZSwgYnV0ICR7d2hlcmV9ICR7d2h5fS4gVXNlIGRlbGV0ZSgpIHRvIHJlbW92ZSBhIGtleS5gXG4gICAgICAgIClcbiAgICAgIH1cbiAgICAgIHJldHVybiBpdGVtXG4gICAgfSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVbnN0b3JhYmxlVmFsdWVFcnJvcikgdGhyb3cgZXJyb3JcbiAgICBjb25zdCBjYXVzZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlLnNwbGl0KCdcXG4nKVswXSA6IFN0cmluZyhlcnJvcilcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGAke2NhbGxTaXRlfTogdmFsdWUgbXVzdCBiZSBKU09OLXNlcmlhbGl6YWJsZSAoJHtjYXVzZX0pLiBVc2UgZGVsZXRlKCkgdG8gcmVtb3ZlIGEga2V5LmApXG4gIH1cbn1cblxuLyoqIEV2ZXJ5dGhpbmcgYnV0IHRoZSB0ZXh0IGNoZWNrcywgd2l0aCBwbGFpbiBvYmplY3RzIGFuZCBhcnJheXMgc2tpcHBpbmcgdGhlIGJ1aWx0LWluIGNoZWNrLiAqL1xuZnVuY3Rpb24gZmFzdFJlYXNvbihob2xkZXI6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBwcm9wZXJ0eTogc3RyaW5nLCBpdGVtOiB1bmtub3duKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgc3dpdGNoICh0eXBlb2YgaXRlbSkge1xuICAgIGNhc2UgJ2Z1bmN0aW9uJzpcbiAgICBjYXNlICdzeW1ib2wnOlxuICAgICAgcmV0dXJuIGBpcyBhICR7dHlwZW9mIGl0ZW19YFxuICAgIGNhc2UgJ251bWJlcic6XG4gICAgICByZXR1cm4gTnVtYmVyLmlzRmluaXRlKGl0ZW0pID8gdW5kZWZpbmVkIDogYGlzIHRoZSBub24tZmluaXRlIG51bWJlciAke2l0ZW19YFxuICAgIGNhc2UgJ3VuZGVmaW5lZCc6XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShob2xkZXIpKSByZXR1cm4gJ2lzIHVuZGVmaW5lZCBvciBhIGhvbGUgaW4gYW4gYXJyYXknXG4gICAgICByZXR1cm4gaG9sZGVyW3Byb3BlcnR5XSAhPT0gdW5kZWZpbmVkID8gJ2hhcyBhIHRvSlNPTigpIHRoYXQgcmV0dXJucyB1bmRlZmluZWQnIDogdW5kZWZpbmVkXG4gICAgY2FzZSAnb2JqZWN0Jzoge1xuICAgICAgaWYgKGl0ZW0gPT09IG51bGwgfHwgQXJyYXkuaXNBcnJheShpdGVtKSkgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgY29uc3QgcHJvdG90eXBlID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKGl0ZW0pXG4gICAgICByZXR1cm4gcHJvdG90eXBlID09PSBPYmplY3QucHJvdG90eXBlIHx8IHByb3RvdHlwZSA9PT0gbnVsbCA/IHVuZGVmaW5lZCA6IGJ1aWx0SW5SZWFzb24oaXRlbSlcbiAgICB9XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgfVxufVxuXG4vKiogRXZlcnkgY2hlY2ssIHBlciBpdGVtOiB1c2VkIHRvIG5hbWUgdGhlIGl0ZW0gYSB0ZXh0IHJlamVjdGlvbiBjb21lcyBmcm9tLiAqL1xuZnVuY3Rpb24gdW5zdG9yYWJsZShob2xkZXI6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBwcm9wZXJ0eTogc3RyaW5nLCBpdGVtOiB1bmtub3duKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZmFzdCA9IGZhc3RSZWFzb24oaG9sZGVyLCBwcm9wZXJ0eSwgaXRlbSlcbiAgaWYgKGZhc3QpIHJldHVybiBmYXN0XG4gIGlmICh0eXBlb2YgaXRlbSA9PT0gJ3N0cmluZycgJiYgKExPTkVfU1VSUk9HQVRFLnRlc3QoaXRlbSkgfHwgVU5TVE9SQUJMRV9URVhULnRlc3QoaXRlbSkpKSB7XG4gICAgcmV0dXJuICdjb250YWlucyBhbiB1bnBhaXJlZCBzdXJyb2dhdGUgb3IgYSBOVUwgY2hhcmFjdGVyJ1xuICB9XG4gIGlmICghQXJyYXkuaXNBcnJheShob2xkZXIpICYmIChMT05FX1NVUlJPR0FURS50ZXN0KHByb3BlcnR5KSB8fCBVTlNUT1JBQkxFX1RFWFQudGVzdChwcm9wZXJ0eSkpKSB7XG4gICAgcmV0dXJuICdpcyBhIGtleSB3aXRoIGFuIHVucGFpcmVkIHN1cnJvZ2F0ZSBvciBhIE5VTCBjaGFyYWN0ZXInXG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZFxufVxuXG5mdW5jdGlvbiBidWlsdEluUmVhc29uKGl0ZW06IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBidWlsdEluID0gYnVpbHRJbk5hbWUoaXRlbSlcbiAgcmV0dXJuIGJ1aWx0SW4gPyBgaXMgJHsvXltBRUlPXS8udGVzdChidWlsdEluKSA/ICdhbicgOiAnYSd9ICR7YnVpbHRJbn0sIHdoaWNoIGhhcyBubyBKU09OIGZvcm1gIDogdW5kZWZpbmVkXG59XG5cbmZ1bmN0aW9uIGJ1aWx0SW5OYW1lKGl0ZW06IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoaXRlbSA9PT0gbnVsbCB8fCB0eXBlb2YgaXRlbSAhPT0gJ29iamVjdCcpIHJldHVybiB1bmRlZmluZWRcbiAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBNYXApIHJldHVybiAnTWFwJ1xuICBpZiAoaXRlbSBpbnN0YW5jZW9mIFNldCkgcmV0dXJuICdTZXQnXG4gIGlmIChpdGVtIGluc3RhbmNlb2YgV2Vha01hcCkgcmV0dXJuICdXZWFrTWFwJ1xuICBpZiAoaXRlbSBpbnN0YW5jZW9mIFdlYWtTZXQpIHJldHVybiAnV2Vha1NldCdcbiAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBSZWdFeHApIHJldHVybiAnUmVnRXhwJ1xuICBpZiAoaXRlbSBpbnN0YW5jZW9mIEVycm9yKSByZXR1cm4gJ0Vycm9yJ1xuICBpZiAoaXRlbSBpbnN0YW5jZW9mIFByb21pc2UpIHJldHVybiAnUHJvbWlzZSdcbiAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgcmV0dXJuICdBcnJheUJ1ZmZlcidcbiAgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhpdGVtKSkgcmV0dXJuIGl0ZW0uY29uc3RydWN0b3I/Lm5hbWUgPz8gJ3R5cGVkIGFycmF5J1xuICByZXR1cm4gdW5kZWZpbmVkXG59XG5cbi8qKlxuICogS2V5cyBhbmQgcGxheWVyIGFkZHJlc3NlcyBnbyBpbnRvIHRoZSByZXF1ZXN0IHBhdGgsIHdoZXJlIGAuYCwgYC4uYCBhbmQgYW4gZW1wdHkgc2VnbWVudCBhcmVcbiAqIHJlc29sdmVkIGF3YXkgYnkgVVJMIHBhcnNpbmcsIHNvIHRoZXkgd291bGQgYWRkcmVzcyBhIGRpZmZlcmVudCByZXNvdXJjZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0U3RvcmFnZUtleShrZXk6IHVua25vd24sIGNhbGxTaXRlOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKHR5cGVvZiBrZXkgIT09ICdzdHJpbmcnIHx8IGtleSA9PT0gJycgfHwga2V5ID09PSAnLicgfHwga2V5ID09PSAnLi4nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtjYWxsU2l0ZX06IGtleSBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZyBvdGhlciB0aGFuIFwiLlwiIGFuZCBcIi4uXCIuYClcbiAgfVxuICBpZiAoTE9ORV9TVVJST0dBVEUudGVzdChrZXkpIHx8IFVOU1RPUkFCTEVfVEVYVC50ZXN0KGtleSkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGAke2NhbGxTaXRlfToga2V5IG11c3Qgbm90IGNvbnRhaW4gYW4gdW5wYWlyZWQgc3Vycm9nYXRlIG9yIGEgTlVMIGNoYXJhY3Rlci5gKVxuICB9XG4gIC8vIENvdW50ZWQgaW4gY2hhcmFjdGVycywgYXMgdGhlIHNlcnZpY2UgY291bnRzIHRoZW0uXG4gIGlmIChbLi4ua2V5XS5sZW5ndGggPiBNQVhfS0VZX0xFTkdUSCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYCR7Y2FsbFNpdGV9OiBrZXkgbXVzdCBiZSBhdCBtb3N0ICR7TUFYX0tFWV9MRU5HVEh9IGNoYXJhY3RlcnMuYClcbiAgfVxufVxuXG4vKiogQGludGVybmFsICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0UGxheWVyQWRkcmVzcyhhZGRyZXNzOiB1bmtub3duLCBjYWxsU2l0ZTogc3RyaW5nKTogdm9pZCB7XG4gIGlmICh0eXBlb2YgYWRkcmVzcyAhPT0gJ3N0cmluZycgfHwgIS9eMHhbMC05YS1mQS1GXXs0MH0kLy50ZXN0KGFkZHJlc3MpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtjYWxsU2l0ZX06IGFkZHJlc3MgbXVzdCBiZSBhIDB4LXByZWZpeGVkIDIwLWJ5dGUgaGV4IGFkZHJlc3MuYClcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DEFAULT_STORAGE_CONFIG } from './constants';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the bounded value cache shared by a storage scope.
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export function createValueCache(config) {
|
|
7
|
+
const entries = new Map();
|
|
8
|
+
const watchers = new Set();
|
|
9
|
+
function noteMutation(key) {
|
|
10
|
+
for (const seen of watchers)
|
|
11
|
+
seen.add(key);
|
|
12
|
+
}
|
|
13
|
+
function insert(key, entry) {
|
|
14
|
+
noteMutation(key);
|
|
15
|
+
// Delete + re-insert moves refreshed keys to the end of the Map's
|
|
16
|
+
// insertion order, so eviction below drops the least-recently-written.
|
|
17
|
+
entries.delete(key);
|
|
18
|
+
entries.set(key, { ...entry, storedAt: Date.now() });
|
|
19
|
+
// Guard against misconfiguration: a negative bound would loop forever on
|
|
20
|
+
// an empty map, and a NaN bound would silently disable eviction.
|
|
21
|
+
const maxEntries = !Number.isNaN(config.cacheMaxEntries)
|
|
22
|
+
? Math.max(0, config.cacheMaxEntries)
|
|
23
|
+
: DEFAULT_STORAGE_CONFIG.cacheMaxEntries;
|
|
24
|
+
while (entries.size > maxEntries) {
|
|
25
|
+
entries.delete(entries.keys().next().value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
get(key) {
|
|
30
|
+
const entry = entries.get(key);
|
|
31
|
+
if (!entry)
|
|
32
|
+
return undefined;
|
|
33
|
+
// Guard against misconfiguration, mirroring cacheMaxEntries: a NaN
|
|
34
|
+
// bound would silently disable expiry (NaN comparisons are false).
|
|
35
|
+
// Negative values need no guard — they just expire everything.
|
|
36
|
+
const maxAgeMs = !Number.isNaN(config.cacheMaxAgeMs) ? config.cacheMaxAgeMs : DEFAULT_STORAGE_CONFIG.cacheMaxAgeMs;
|
|
37
|
+
// Lazy max-age expiry: storedAt is never refreshed on hits, so the age
|
|
38
|
+
// bounds the time since the last actual network confirmation.
|
|
39
|
+
if (Date.now() - entry.storedAt > maxAgeMs) {
|
|
40
|
+
entries.delete(key);
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return entry;
|
|
44
|
+
},
|
|
45
|
+
set(key, entry) {
|
|
46
|
+
insert(key, entry);
|
|
47
|
+
},
|
|
48
|
+
setAbsent(key) {
|
|
49
|
+
insert(key, { absent: true });
|
|
50
|
+
},
|
|
51
|
+
delete(key) {
|
|
52
|
+
noteMutation(key);
|
|
53
|
+
entries.delete(key);
|
|
54
|
+
},
|
|
55
|
+
watch() {
|
|
56
|
+
const seen = new Set();
|
|
57
|
+
watchers.add(seen);
|
|
58
|
+
return {
|
|
59
|
+
mutated: (key) => seen.has(key),
|
|
60
|
+
stop: () => {
|
|
61
|
+
watchers.delete(seen);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsdWUtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2UvdmFsdWUtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHNCQUFzQixFQUFzQixNQUFNLGFBQWEsQ0FBQTtBQTRDeEU7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLE1BQTBCO0lBQ3pELE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUE2QyxDQUFBO0lBQ3BFLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFlLENBQUE7SUFFdkMsU0FBUyxZQUFZLENBQUMsR0FBVztRQUMvQixLQUFLLE1BQU0sSUFBSSxJQUFJLFFBQVE7WUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQzVDLENBQUM7SUFFRCxTQUFTLE1BQU0sQ0FBQyxHQUFXLEVBQUUsS0FBaUI7UUFDNUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ2pCLGtFQUFrRTtRQUNsRSx1RUFBdUU7UUFDdkUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNuQixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBRXBELHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsTUFBTSxVQUFVLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUM7WUFDdEQsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUM7WUFDckMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLGVBQWUsQ0FBQTtRQUUxQyxPQUFPLE9BQU8sQ0FBQyxJQUFJLEdBQUcsVUFBVSxFQUFFO1lBQ2hDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEtBQU0sQ0FBQyxDQUFBO1NBQzdDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxHQUFHLENBQUMsR0FBVztZQUNiLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDOUIsSUFBSSxDQUFDLEtBQUs7Z0JBQUUsT0FBTyxTQUFTLENBQUE7WUFFNUIsbUVBQW1FO1lBQ25FLG1FQUFtRTtZQUNuRSwrREFBK0Q7WUFDL0QsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsYUFBYSxDQUFBO1lBRWxILHVFQUF1RTtZQUN2RSw4REFBOEQ7WUFDOUQsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLFFBQVEsR0FBRyxRQUFRLEVBQUU7Z0JBQzFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ25CLE9BQU8sU0FBUyxDQUFBO2FBQ2pCO1lBRUQsT0FBTyxLQUFLLENBQUE7UUFDZCxDQUFDO1FBRUQsR0FBRyxDQUFDLEdBQVcsRUFBRSxLQUF1QjtZQUN0QyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQ3BCLENBQUM7UUFFRCxTQUFTLENBQUMsR0FBVztZQUNuQixNQUFNLENBQUMsR0FBRyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUE7UUFDL0IsQ0FBQztRQUVELE1BQU0sQ0FBQyxHQUFXO1lBQ2hCLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUNqQixPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ3JCLENBQUM7UUFFRCxLQUFLO1lBQ0gsTUFBTSxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQTtZQUM5QixRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ2xCLE9BQU87Z0JBQ0wsT0FBTyxFQUFFLENBQUMsR0FBVyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztnQkFDdkMsSUFBSSxFQUFFLEdBQUcsRUFBRTtvQkFDVCxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFBO2dCQUN2QixDQUFDO2FBQ0YsQ0FBQTtRQUNILENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERFRkFVTFRfU1RPUkFHRV9DT05GSUcsIFN0b3JhZ2VDb25maWdTdGF0ZSB9IGZyb20gJy4vY29uc3RhbnRzJ1xuXG4vKipcbiAqIEEgY2FjaGVkIGZhY3QgYWJvdXQgYSBrZXkncyBzZXJ2ZXItc2lkZSBzdGF0ZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlRW50cnkge1xuICAvKipcbiAgICogU2VyaWFsaXplZCBgeyB2YWx1ZSB9YCBib2R5OyBhYnNlbnQgZm9yIG5lZ2F0aXZlIGVudHJpZXMuIFBhcnNlZCBwZXIgcmVhZFxuICAgKiBoaXQgc28gY2FsbGVycyBuZXZlciBzaGFyZSBvYmplY3QgcmVmZXJlbmNlcywgYW5kIGNvbXBhcmVkIHZlcmJhdGltIGZvclxuICAgKiB3cml0ZSBkZWR1cCAoZXhhY3QgZXF1YWxpdHkg4oCUIG5vIGhhc2gtY29sbGlzaW9uIHJpc2spLlxuICAgKi9cbiAgYm9keT86IHN0cmluZ1xuICAvKiogVHJ1ZSB3aGVuIHRoZSBzZXJ2ZXIgY29uZmlybWVkIHRoZSBrZXkgZG9lcyBub3QgZXhpc3QgKEdFVCA0MDQgb3Igc3VjY2Vzc2Z1bCBERUxFVEUpLiAqL1xuICBhYnNlbnQ/OiBib29sZWFuXG59XG5cbi8qKlxuICogQm91bmRlZCwgbGF6aWx5LWV4cGlyaW5nIGNhY2hlIG9mIGtleSBzdGF0ZXMsIGJhY2tpbmcgYm90aCB3cml0ZSBkZWR1cFxuICogKHNraXAgc3RvcmFnZSB3cml0ZXMgd2hvc2UgdmFsdWUgaXMgYWxyZWFkeSBrbm93biB0byBiZSBzdG9yZWQpIGFuZCByZWFkXG4gKiBjYWNoaW5nIChzZXJ2ZSBnZXQoKSB3aXRob3V0IGEgbmV0d29yayByZXF1ZXN0IHdpdGhpbiB0aGUgVFRMKS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFZhbHVlQ2FjaGUge1xuICAvKiogUmV0dXJucyB0aGUgZW50cnkgaWYgcHJlc2VudCBhbmQgZnJlc2g7IGxhemlseSBldmljdHMgZXhwaXJlZCBlbnRyaWVzLiAqL1xuICBnZXQoa2V5OiBzdHJpbmcpOiBDYWNoZUVudHJ5IHwgdW5kZWZpbmVkXG4gIC8qKiBTdG9yZXMgb3IgcmVmcmVzaGVzIGEga25vd24gdmFsdWUgKHNlcmlhbGl6ZWQgYm9keSk7IG92ZXJ3cml0ZXMgbmVnYXRpdmUgZW50cmllcy4gKi9cbiAgc2V0KGtleTogc3RyaW5nLCBlbnRyeTogeyBib2R5OiBzdHJpbmcgfSk6IHZvaWRcbiAgLyoqIFN0b3JlcyBhIGNvbmZpcm1lZC1hYnNlbnQgKG5lZ2F0aXZlKSBlbnRyeSwgcmVwbGFjaW5nIGFueSB2YWx1ZSBlbnRyeS4gKi9cbiAgc2V0QWJzZW50KGtleTogc3RyaW5nKTogdm9pZFxuICBkZWxldGUoa2V5OiBzdHJpbmcpOiB2b2lkXG4gIC8qKiBTdGFydHMgcmVjb3JkaW5nIG11dGF0ZWQga2V5cywgc28gYSByZWFkIGlzc3VlZCBlYXJsaWVyIGNhbiB0ZWxsIGl0cyBzbmFwc2hvdCB3ZW50IHN0YWxlLiAqL1xuICB3YXRjaCgpOiBDYWNoZVdhdGNoZXJcbn1cblxuLyoqXG4gKiBLZXlzIG11dGF0ZWQgc2luY2UgdGhlIHdhdGNoIHN0YXJ0ZWQuIEFsd2F5cyBzdG9wKCkgaXQsIG9yIGl0IGtlZXBzIGNvbGxlY3RpbmcuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYWNoZVdhdGNoZXIge1xuICBtdXRhdGVkKGtleTogc3RyaW5nKTogYm9vbGVhblxuICBzdG9wKCk6IHZvaWRcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBib3VuZGVkIHZhbHVlIGNhY2hlIHNoYXJlZCBieSBhIHN0b3JhZ2Ugc2NvcGUuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVZhbHVlQ2FjaGUoY29uZmlnOiBTdG9yYWdlQ29uZmlnU3RhdGUpOiBWYWx1ZUNhY2hlIHtcbiAgY29uc3QgZW50cmllcyA9IG5ldyBNYXA8c3RyaW5nLCBDYWNoZUVudHJ5ICYgeyBzdG9yZWRBdDogbnVtYmVyIH0+KClcbiAgY29uc3Qgd2F0Y2hlcnMgPSBuZXcgU2V0PFNldDxzdHJpbmc+PigpXG5cbiAgZnVuY3Rpb24gbm90ZU11dGF0aW9uKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBzZWVuIG9mIHdhdGNoZXJzKSBzZWVuLmFkZChrZXkpXG4gIH1cblxuICBmdW5jdGlvbiBpbnNlcnQoa2V5OiBzdHJpbmcsIGVudHJ5OiBDYWNoZUVudHJ5KTogdm9pZCB7XG4gICAgbm90ZU11dGF0aW9uKGtleSlcbiAgICAvLyBEZWxldGUgKyByZS1pbnNlcnQgbW92ZXMgcmVmcmVzaGVkIGtleXMgdG8gdGhlIGVuZCBvZiB0aGUgTWFwJ3NcbiAgICAvLyBpbnNlcnRpb24gb3JkZXIsIHNvIGV2aWN0aW9uIGJlbG93IGRyb3BzIHRoZSBsZWFzdC1yZWNlbnRseS13cml0dGVuLlxuICAgIGVudHJpZXMuZGVsZXRlKGtleSlcbiAgICBlbnRyaWVzLnNldChrZXksIHsgLi4uZW50cnksIHN0b3JlZEF0OiBEYXRlLm5vdygpIH0pXG5cbiAgICAvLyBHdWFyZCBhZ2FpbnN0IG1pc2NvbmZpZ3VyYXRpb246IGEgbmVnYXRpdmUgYm91bmQgd291bGQgbG9vcCBmb3JldmVyIG9uXG4gICAgLy8gYW4gZW1wdHkgbWFwLCBhbmQgYSBOYU4gYm91bmQgd291bGQgc2lsZW50bHkgZGlzYWJsZSBldmljdGlvbi5cbiAgICBjb25zdCBtYXhFbnRyaWVzID0gIU51bWJlci5pc05hTihjb25maWcuY2FjaGVNYXhFbnRyaWVzKVxuICAgICAgPyBNYXRoLm1heCgwLCBjb25maWcuY2FjaGVNYXhFbnRyaWVzKVxuICAgICAgOiBERUZBVUxUX1NUT1JBR0VfQ09ORklHLmNhY2hlTWF4RW50cmllc1xuXG4gICAgd2hpbGUgKGVudHJpZXMuc2l6ZSA+IG1heEVudHJpZXMpIHtcbiAgICAgIGVudHJpZXMuZGVsZXRlKGVudHJpZXMua2V5cygpLm5leHQoKS52YWx1ZSEpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBnZXQoa2V5OiBzdHJpbmcpOiBDYWNoZUVudHJ5IHwgdW5kZWZpbmVkIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gZW50cmllcy5nZXQoa2V5KVxuICAgICAgaWYgKCFlbnRyeSkgcmV0dXJuIHVuZGVmaW5lZFxuXG4gICAgICAvLyBHdWFyZCBhZ2FpbnN0IG1pc2NvbmZpZ3VyYXRpb24sIG1pcnJvcmluZyBjYWNoZU1heEVudHJpZXM6IGEgTmFOXG4gICAgICAvLyBib3VuZCB3b3VsZCBzaWxlbnRseSBkaXNhYmxlIGV4cGlyeSAoTmFOIGNvbXBhcmlzb25zIGFyZSBmYWxzZSkuXG4gICAgICAvLyBOZWdhdGl2ZSB2YWx1ZXMgbmVlZCBubyBndWFyZCDigJQgdGhleSBqdXN0IGV4cGlyZSBldmVyeXRoaW5nLlxuICAgICAgY29uc3QgbWF4QWdlTXMgPSAhTnVtYmVyLmlzTmFOKGNvbmZpZy5jYWNoZU1heEFnZU1zKSA/IGNvbmZpZy5jYWNoZU1heEFnZU1zIDogREVGQVVMVF9TVE9SQUdFX0NPTkZJRy5jYWNoZU1heEFnZU1zXG5cbiAgICAgIC8vIExhenkgbWF4LWFnZSBleHBpcnk6IHN0b3JlZEF0IGlzIG5ldmVyIHJlZnJlc2hlZCBvbiBoaXRzLCBzbyB0aGUgYWdlXG4gICAgICAvLyBib3VuZHMgdGhlIHRpbWUgc2luY2UgdGhlIGxhc3QgYWN0dWFsIG5ldHdvcmsgY29uZmlybWF0aW9uLlxuICAgICAgaWYgKERhdGUubm93KCkgLSBlbnRyeS5zdG9yZWRBdCA+IG1heEFnZU1zKSB7XG4gICAgICAgIGVudHJpZXMuZGVsZXRlKGtleSlcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZW50cnlcbiAgICB9LFxuXG4gICAgc2V0KGtleTogc3RyaW5nLCBlbnRyeTogeyBib2R5OiBzdHJpbmcgfSk6IHZvaWQge1xuICAgICAgaW5zZXJ0KGtleSwgZW50cnkpXG4gICAgfSxcblxuICAgIHNldEFic2VudChrZXk6IHN0cmluZyk6IHZvaWQge1xuICAgICAgaW5zZXJ0KGtleSwgeyBhYnNlbnQ6IHRydWUgfSlcbiAgICB9LFxuXG4gICAgZGVsZXRlKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgICBub3RlTXV0YXRpb24oa2V5KVxuICAgICAgZW50cmllcy5kZWxldGUoa2V5KVxuICAgIH0sXG5cbiAgICB3YXRjaCgpOiBDYWNoZVdhdGNoZXIge1xuICAgICAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpXG4gICAgICB3YXRjaGVycy5hZGQoc2VlbilcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG11dGF0ZWQ6IChrZXk6IHN0cmluZykgPT4gc2Vlbi5oYXMoa2V5KSxcbiAgICAgICAgc3RvcDogKCkgPT4ge1xuICAgICAgICAgIHdhdGNoZXJzLmRlbGV0ZShzZWVuKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rejection of a superseded delete when the write that replaced it did not apply.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export class SupersedingWriteFailed extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('a write that replaced it did not apply');
|
|
8
|
+
this.name = 'SupersedingWriteFailed';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates the per-key write serializer shared by a storage scope.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export function createWriteQueue() {
|
|
16
|
+
const keys = new Map();
|
|
17
|
+
function makeOp(body, execute) {
|
|
18
|
+
let resolve;
|
|
19
|
+
let reject;
|
|
20
|
+
const promise = new Promise((res, rej) => {
|
|
21
|
+
resolve = res;
|
|
22
|
+
reject = rej;
|
|
23
|
+
});
|
|
24
|
+
return { body, execute, promise, resolve, reject };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A replaced op resolves true when its replacement lands. On failure a set
|
|
28
|
+
* resolves false and a delete rejects, in its own terms.
|
|
29
|
+
*/
|
|
30
|
+
function settleSuperseded(superseded, by) {
|
|
31
|
+
by.promise.then((result) => {
|
|
32
|
+
const applied = by.body === null || result;
|
|
33
|
+
if (superseded.body !== null)
|
|
34
|
+
superseded.resolve(applied);
|
|
35
|
+
else if (applied)
|
|
36
|
+
superseded.resolve(true);
|
|
37
|
+
else
|
|
38
|
+
superseded.reject(new SupersedingWriteFailed());
|
|
39
|
+
}, (error) => {
|
|
40
|
+
if (superseded.body === null)
|
|
41
|
+
superseded.reject(error);
|
|
42
|
+
else
|
|
43
|
+
superseded.resolve(false);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function drain(key, state) {
|
|
47
|
+
for (;;) {
|
|
48
|
+
const op = state.active;
|
|
49
|
+
try {
|
|
50
|
+
op.resolve(await op.execute(op.body));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
op.reject(error);
|
|
54
|
+
}
|
|
55
|
+
if (state.queued) {
|
|
56
|
+
state.active = state.queued;
|
|
57
|
+
state.queued = undefined;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
keys.delete(key);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
pending(key) {
|
|
67
|
+
const state = keys.get(key);
|
|
68
|
+
if (!state)
|
|
69
|
+
return undefined;
|
|
70
|
+
return (state.queued ?? state.active).body;
|
|
71
|
+
},
|
|
72
|
+
isPending(key) {
|
|
73
|
+
return keys.has(key);
|
|
74
|
+
},
|
|
75
|
+
async settled(key) {
|
|
76
|
+
const state = keys.get(key);
|
|
77
|
+
if (!state)
|
|
78
|
+
return;
|
|
79
|
+
const hadQueued = state.queued !== undefined;
|
|
80
|
+
await state.active.promise.catch(() => undefined);
|
|
81
|
+
// drain() promotes the queued op (or its replacement) in place before this resumes.
|
|
82
|
+
if (hadQueued)
|
|
83
|
+
await state.active.promise.catch(() => undefined);
|
|
84
|
+
},
|
|
85
|
+
enqueue(key, body, execute, joinActive) {
|
|
86
|
+
const state = keys.get(key);
|
|
87
|
+
if (!state) {
|
|
88
|
+
const op = makeOp(body, execute);
|
|
89
|
+
const newState = { active: op };
|
|
90
|
+
keys.set(key, newState);
|
|
91
|
+
void drain(key, newState);
|
|
92
|
+
return op.promise;
|
|
93
|
+
}
|
|
94
|
+
if (state.queued) {
|
|
95
|
+
// A queued op has not started, so it is issued "after" this caller
|
|
96
|
+
// either way: join it when identical, supersede it otherwise.
|
|
97
|
+
if (state.queued.body === body)
|
|
98
|
+
return state.queued.promise;
|
|
99
|
+
const op = makeOp(body, execute);
|
|
100
|
+
settleSuperseded(state.queued, op);
|
|
101
|
+
state.queued = op;
|
|
102
|
+
return op.promise;
|
|
103
|
+
}
|
|
104
|
+
if (joinActive && state.active.body === body) {
|
|
105
|
+
return state.active.promise;
|
|
106
|
+
}
|
|
107
|
+
const op = makeOp(body, execute);
|
|
108
|
+
state.queued = op;
|
|
109
|
+
return op.promise;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdGUtcXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2Uvd3JpdGUtcXVldWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLHNCQUF1QixTQUFRLEtBQUs7SUFDL0M7UUFDRSxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQTtRQUMvQyxJQUFJLENBQUMsSUFBSSxHQUFHLHdCQUF3QixDQUFBO0lBQ3RDLENBQUM7Q0FDRjtBQTJERDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCO0lBQzlCLE1BQU0sSUFBSSxHQUFHLElBQUksR0FBRyxFQUFvQixDQUFBO0lBRXhDLFNBQVMsTUFBTSxDQUFDLElBQW1CLEVBQUUsT0FBNkI7UUFDaEUsSUFBSSxPQUFtQyxDQUFBO1FBQ3ZDLElBQUksTUFBaUMsQ0FBQTtRQUNyQyxNQUFNLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBVSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRTtZQUNoRCxPQUFPLEdBQUcsR0FBRyxDQUFBO1lBQ2IsTUFBTSxHQUFHLEdBQUcsQ0FBQTtRQUNkLENBQUMsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQTtJQUNwRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxVQUFxQixFQUFFLEVBQWE7UUFDNUQsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQ2IsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUNULE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxJQUFJLEtBQUssSUFBSSxJQUFJLE1BQU0sQ0FBQTtZQUMxQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssSUFBSTtnQkFBRSxVQUFVLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFBO2lCQUNwRCxJQUFJLE9BQU87Z0JBQUUsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTs7Z0JBQ3JDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxzQkFBc0IsRUFBRSxDQUFDLENBQUE7UUFDdEQsQ0FBQyxFQUNELENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDUixJQUFJLFVBQVUsQ0FBQyxJQUFJLEtBQUssSUFBSTtnQkFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBOztnQkFDakQsVUFBVSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNoQyxDQUFDLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFFRCxLQUFLLFVBQVUsS0FBSyxDQUFDLEdBQVcsRUFBRSxLQUFlO1FBQy9DLFNBQVM7WUFDUCxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFBO1lBQ3ZCLElBQUk7Z0JBQ0YsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7YUFDdEM7WUFBQyxPQUFPLEtBQUssRUFBRTtnQkFDZCxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO2FBQ2pCO1lBRUQsSUFBSSxLQUFLLENBQUMsTUFBTSxFQUFFO2dCQUNoQixLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUE7Z0JBQzNCLEtBQUssQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFBO2FBQ3pCO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLE9BQU07YUFDUDtTQUNGO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxPQUFPLENBQUMsR0FBVztZQUNqQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQzNCLElBQUksQ0FBQyxLQUFLO2dCQUFFLE9BQU8sU0FBUyxDQUFBO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDNUMsQ0FBQztRQUVELFNBQVMsQ0FBQyxHQUFXO1lBQ25CLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUN0QixDQUFDO1FBRUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFXO1lBQ3ZCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDM0IsSUFBSSxDQUFDLEtBQUs7Z0JBQUUsT0FBTTtZQUNsQixNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQTtZQUM1QyxNQUFNLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQTtZQUNqRCxvRkFBb0Y7WUFDcEYsSUFBSSxTQUFTO2dCQUFFLE1BQU0sS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ2xFLENBQUM7UUFFRCxPQUFPLENBQUMsR0FBVyxFQUFFLElBQW1CLEVBQUUsT0FBNkIsRUFBRSxVQUFtQjtZQUMxRixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRTNCLElBQUksQ0FBQyxLQUFLLEVBQUU7Z0JBQ1YsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQTtnQkFDaEMsTUFBTSxRQUFRLEdBQWEsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUE7Z0JBQ3pDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFBO2dCQUN2QixLQUFLLEtBQUssQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUE7Z0JBQ3pCLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQTthQUNsQjtZQUVELElBQUksS0FBSyxDQUFDLE1BQU0sRUFBRTtnQkFDaEIsbUVBQW1FO2dCQUNuRSw4REFBOEQ7Z0JBQzlELElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSTtvQkFBRSxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFBO2dCQUMzRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFBO2dCQUNoQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFBO2dCQUNsQyxLQUFLLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQTtnQkFDakIsT0FBTyxFQUFFLENBQUMsT0FBTyxDQUFBO2FBQ2xCO1lBRUQsSUFBSSxVQUFVLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUM1QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFBO2FBQzVCO1lBRUQsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQTtZQUNoQyxLQUFLLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQTtZQUNqQixPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUE7UUFDbkIsQ0FBQztLQUNGLENBQUE7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBSZWplY3Rpb24gb2YgYSBzdXBlcnNlZGVkIGRlbGV0ZSB3aGVuIHRoZSB3cml0ZSB0aGF0IHJlcGxhY2VkIGl0IGRpZCBub3QgYXBwbHkuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGNsYXNzIFN1cGVyc2VkaW5nV3JpdGVGYWlsZWQgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCdhIHdyaXRlIHRoYXQgcmVwbGFjZWQgaXQgZGlkIG5vdCBhcHBseScpXG4gICAgdGhpcy5uYW1lID0gJ1N1cGVyc2VkaW5nV3JpdGVGYWlsZWQnXG4gIH1cbn1cblxuLyoqXG4gKiBBIHBlbmRpbmcgd3JpdGUgb3BlcmF0aW9uLiBgYm9keWAgaXMgdGhlIHNlcmlhbGl6ZWQgUFVUIHBheWxvYWQsIG9yIG51bGxcbiAqIGZvciBhIERFTEVURS4gQ2FsbGVycyB0aGF0IGpvaW4gdGhlIG9wIHNoYXJlIGl0cyBwcm9taXNlLlxuICovXG5pbnRlcmZhY2UgUGVuZGluZ09wIHtcbiAgYm9keTogc3RyaW5nIHwgbnVsbFxuICBleGVjdXRlOiAoYm9keTogc3RyaW5nIHwgbnVsbCkgPT4gUHJvbWlzZTxib29sZWFuPlxuICBwcm9taXNlOiBQcm9taXNlPGJvb2xlYW4+XG4gIHJlc29sdmU6IChyZXN1bHQ6IGJvb2xlYW4pID0+IHZvaWRcbiAgcmVqZWN0OiAoZXJyb3I6IHVua25vd24pID0+IHZvaWRcbn1cblxuaW50ZXJmYWNlIEtleVN0YXRlIHtcbiAgLyoqIFRoZSBvcCBjdXJyZW50bHkgb24gdGhlIG5ldHdvcmsuICovXG4gIGFjdGl2ZTogUGVuZGluZ09wXG4gIC8qKiBBdCBtb3N0IG9uZSBxdWV1ZWQgb3A7IGEgbGF0ZXIgd3JpdGUgcmVwbGFjZXMgaXQgKGxhdGVzdCB3aW5zKS4gKi9cbiAgcXVldWVkPzogUGVuZGluZ09wXG59XG5cbi8qKlxuICogU2VyaWFsaXplcyB3cml0ZXMgcGVyIGtleSBzbyB0aGUgc2VydmljZSBjb21taXRzIHRoZW0gaW4gaXNzdWUgb3JkZXIuXG4gKiBPdmVybGFwcGluZyBQVVRzIGZyb20gdGhlIHNpbmdsZSBzY2VuZSBzZXJ2ZXIgd291bGQgb3RoZXJ3aXNlIHJhY2U6IHRoZVxuICogc2VydmVyIGtlZXBzIHdoaWNoZXZlciByZXF1ZXN0IGl0IHByb2Nlc3NlcyBsYXN0LCB3aGlsZSB0aGUgbG9jYWwgY2FjaGVcbiAqIGtlZXBzIHdoaWNoZXZlciByZXNwb25zZSBhcnJpdmVzIGxhc3Qg4oCUIGVpdGhlciBjYW4gZGlzYWdyZWUgd2l0aCB0aGUgbGFzdFxuICogc2V0KCkgaXNzdWVkLiBXaXRoIGF0IG1vc3Qgb25lIGluLWZsaWdodCBvcCBwZXIga2V5IGFuZCBhIHNpbmdsZSBxdWV1ZWRcbiAqIFwibGF0ZXN0IHZhbHVlXCIgc2xvdCwgdGhlIHNlcnZlcidzIGZpbmFsIHN0YXRlIGFsd2F5cyBtYXRjaGVzIHRoZSBsYXN0XG4gKiB3cml0ZSBpc3N1ZWQsIGFuZCBOIHJhcGlkIHdyaXRlcyBjb2xsYXBzZSBpbnRvIGF0IG1vc3QgMiBuZXR3b3JrIGNhbGxzLlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV3JpdGVRdWV1ZSB7XG4gIC8qKlxuICAgKiBCb2R5IG9mIHRoZSBsYXRlc3QgaXNzdWVkIHdyaXRlIGZvciB0aGUga2V5ICh0aGUgcXVldWVkIG9wIGlmIHByZXNlbnQsXG4gICAqIGVsc2UgdGhlIGluLWZsaWdodCBvbmUpOiBhIHN0cmluZyBmb3IgYSBQVVQsIG51bGwgZm9yIGEgREVMRVRFLFxuICAgKiB1bmRlZmluZWQgd2hlbiBubyB3cml0ZSBpcyBwZW5kaW5nLlxuICAgKi9cbiAgcGVuZGluZyhrZXk6IHN0cmluZyk6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWRcbiAgLyoqIFRydWUgd2hpbGUgYW55IHdyaXRlIGZvciB0aGUga2V5IGlzIGluIGZsaWdodCBvciBxdWV1ZWQuICovXG4gIGlzUGVuZGluZyhrZXk6IHN0cmluZyk6IGJvb2xlYW5cbiAgLyoqXG4gICAqIFJlc29sdmVzIG9uY2UgdGhlIGluLWZsaWdodCBvcCBzZXR0bGVzIGFuZCwgaWYgb25lIHdhcyBxdWV1ZWQgYXQgY2FsbCB0aW1lLFxuICAgKiB0aGUgb3AgdGhhdCBydW5zIG5leHQuIEF0IG1vc3QgdHdvLCBzbyB3cml0ZXMgY2Fubm90IHN0YXJ2ZSBhIHdhaXRlci4gTmV2ZXIgcmVqZWN0cy5cbiAgICovXG4gIHNldHRsZWQoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+XG4gIC8qKlxuICAgKiBJc3N1ZXMgYSB3cml0ZSwgcXVldWVkIGJlaGluZCBhbnkgaW4tZmxpZ2h0IG9uZSBhbmQgcmVwbGFjaW5nIGFueSBxdWV1ZWQgb25lXG4gICAqIChzZWUgc2V0dGxlU3VwZXJzZWRlZCkuIEFuIGlkZW50aWNhbCBxdWV1ZWQgb3AgaXMgam9pbmVkOyBgam9pbkFjdGl2ZWAgYWxzb1xuICAgKiBqb2lucyBhbiBpZGVudGljYWwgaW4tZmxpZ2h0IG9wLCB3aGljaCBvbmx5IGRlZHVwLXRvbGVyYW50IGNhbGxlcnMgbWF5IGRvLlxuICAgKiBSZWplY3RzIHdpdGggdGhlIGV4ZWN1dG9yJ3MgZXJyb3I7IHNlZSBzZXR0bGVTdXBlcnNlZGVkIGZvciByZXBsYWNlZCBvcHMuXG4gICAqL1xuICBlbnF1ZXVlKFxuICAgIGtleTogc3RyaW5nLFxuICAgIGJvZHk6IHN0cmluZyB8IG51bGwsXG4gICAgZXhlY3V0ZTogKGJvZHk6IHN0cmluZyB8IG51bGwpID0+IFByb21pc2U8Ym9vbGVhbj4sXG4gICAgam9pbkFjdGl2ZTogYm9vbGVhblxuICApOiBQcm9taXNlPGJvb2xlYW4+XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgcGVyLWtleSB3cml0ZSBzZXJpYWxpemVyIHNoYXJlZCBieSBhIHN0b3JhZ2Ugc2NvcGUuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVdyaXRlUXVldWUoKTogV3JpdGVRdWV1ZSB7XG4gIGNvbnN0IGtleXMgPSBuZXcgTWFwPHN0cmluZywgS2V5U3RhdGU+KClcblxuICBmdW5jdGlvbiBtYWtlT3AoYm9keTogc3RyaW5nIHwgbnVsbCwgZXhlY3V0ZTogUGVuZGluZ09wWydleGVjdXRlJ10pOiBQZW5kaW5nT3Age1xuICAgIGxldCByZXNvbHZlITogKHJlc3VsdDogYm9vbGVhbikgPT4gdm9pZFxuICAgIGxldCByZWplY3QhOiAoZXJyb3I6IHVua25vd24pID0+IHZvaWRcbiAgICBjb25zdCBwcm9taXNlID0gbmV3IFByb21pc2U8Ym9vbGVhbj4oKHJlcywgcmVqKSA9PiB7XG4gICAgICByZXNvbHZlID0gcmVzXG4gICAgICByZWplY3QgPSByZWpcbiAgICB9KVxuICAgIHJldHVybiB7IGJvZHksIGV4ZWN1dGUsIHByb21pc2UsIHJlc29sdmUsIHJlamVjdCB9XG4gIH1cblxuICAvKipcbiAgICogQSByZXBsYWNlZCBvcCByZXNvbHZlcyB0cnVlIHdoZW4gaXRzIHJlcGxhY2VtZW50IGxhbmRzLiBPbiBmYWlsdXJlIGEgc2V0XG4gICAqIHJlc29sdmVzIGZhbHNlIGFuZCBhIGRlbGV0ZSByZWplY3RzLCBpbiBpdHMgb3duIHRlcm1zLlxuICAgKi9cbiAgZnVuY3Rpb24gc2V0dGxlU3VwZXJzZWRlZChzdXBlcnNlZGVkOiBQZW5kaW5nT3AsIGJ5OiBQZW5kaW5nT3ApOiB2b2lkIHtcbiAgICBieS5wcm9taXNlLnRoZW4oXG4gICAgICAocmVzdWx0KSA9PiB7XG4gICAgICAgIGNvbnN0IGFwcGxpZWQgPSBieS5ib2R5ID09PSBudWxsIHx8IHJlc3VsdFxuICAgICAgICBpZiAoc3VwZXJzZWRlZC5ib2R5ICE9PSBudWxsKSBzdXBlcnNlZGVkLnJlc29sdmUoYXBwbGllZClcbiAgICAgICAgZWxzZSBpZiAoYXBwbGllZCkgc3VwZXJzZWRlZC5yZXNvbHZlKHRydWUpXG4gICAgICAgIGVsc2Ugc3VwZXJzZWRlZC5yZWplY3QobmV3IFN1cGVyc2VkaW5nV3JpdGVGYWlsZWQoKSlcbiAgICAgIH0sXG4gICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgaWYgKHN1cGVyc2VkZWQuYm9keSA9PT0gbnVsbCkgc3VwZXJzZWRlZC5yZWplY3QoZXJyb3IpXG4gICAgICAgIGVsc2Ugc3VwZXJzZWRlZC5yZXNvbHZlKGZhbHNlKVxuICAgICAgfVxuICAgIClcbiAgfVxuXG4gIGFzeW5jIGZ1bmN0aW9uIGRyYWluKGtleTogc3RyaW5nLCBzdGF0ZTogS2V5U3RhdGUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKDs7KSB7XG4gICAgICBjb25zdCBvcCA9IHN0YXRlLmFjdGl2ZVxuICAgICAgdHJ5IHtcbiAgICAgICAgb3AucmVzb2x2ZShhd2FpdCBvcC5leGVjdXRlKG9wLmJvZHkpKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgb3AucmVqZWN0KGVycm9yKVxuICAgICAgfVxuXG4gICAgICBpZiAoc3RhdGUucXVldWVkKSB7XG4gICAgICAgIHN0YXRlLmFjdGl2ZSA9IHN0YXRlLnF1ZXVlZFxuICAgICAgICBzdGF0ZS5xdWV1ZWQgPSB1bmRlZmluZWRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGtleXMuZGVsZXRlKGtleSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBwZW5kaW5nKGtleTogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgICBjb25zdCBzdGF0ZSA9IGtleXMuZ2V0KGtleSlcbiAgICAgIGlmICghc3RhdGUpIHJldHVybiB1bmRlZmluZWRcbiAgICAgIHJldHVybiAoc3RhdGUucXVldWVkID8/IHN0YXRlLmFjdGl2ZSkuYm9keVxuICAgIH0sXG5cbiAgICBpc1BlbmRpbmcoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgIHJldHVybiBrZXlzLmhhcyhrZXkpXG4gICAgfSxcblxuICAgIGFzeW5jIHNldHRsZWQoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGNvbnN0IHN0YXRlID0ga2V5cy5nZXQoa2V5KVxuICAgICAgaWYgKCFzdGF0ZSkgcmV0dXJuXG4gICAgICBjb25zdCBoYWRRdWV1ZWQgPSBzdGF0ZS5xdWV1ZWQgIT09IHVuZGVmaW5lZFxuICAgICAgYXdhaXQgc3RhdGUuYWN0aXZlLnByb21pc2UuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKVxuICAgICAgLy8gZHJhaW4oKSBwcm9tb3RlcyB0aGUgcXVldWVkIG9wIChvciBpdHMgcmVwbGFjZW1lbnQpIGluIHBsYWNlIGJlZm9yZSB0aGlzIHJlc3VtZXMuXG4gICAgICBpZiAoaGFkUXVldWVkKSBhd2FpdCBzdGF0ZS5hY3RpdmUucHJvbWlzZS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpXG4gICAgfSxcblxuICAgIGVucXVldWUoa2V5OiBzdHJpbmcsIGJvZHk6IHN0cmluZyB8IG51bGwsIGV4ZWN1dGU6IFBlbmRpbmdPcFsnZXhlY3V0ZSddLCBqb2luQWN0aXZlOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICBjb25zdCBzdGF0ZSA9IGtleXMuZ2V0KGtleSlcblxuICAgICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICBjb25zdCBvcCA9IG1ha2VPcChib2R5LCBleGVjdXRlKVxuICAgICAgICBjb25zdCBuZXdTdGF0ZTogS2V5U3RhdGUgPSB7IGFjdGl2ZTogb3AgfVxuICAgICAgICBrZXlzLnNldChrZXksIG5ld1N0YXRlKVxuICAgICAgICB2b2lkIGRyYWluKGtleSwgbmV3U3RhdGUpXG4gICAgICAgIHJldHVybiBvcC5wcm9taXNlXG4gICAgICB9XG5cbiAgICAgIGlmIChzdGF0ZS5xdWV1ZWQpIHtcbiAgICAgICAgLy8gQSBxdWV1ZWQgb3AgaGFzIG5vdCBzdGFydGVkLCBzbyBpdCBpcyBpc3N1ZWQgXCJhZnRlclwiIHRoaXMgY2FsbGVyXG4gICAgICAgIC8vIGVpdGhlciB3YXk6IGpvaW4gaXQgd2hlbiBpZGVudGljYWwsIHN1cGVyc2VkZSBpdCBvdGhlcndpc2UuXG4gICAgICAgIGlmIChzdGF0ZS5xdWV1ZWQuYm9keSA9PT0gYm9keSkgcmV0dXJuIHN0YXRlLnF1ZXVlZC5wcm9taXNlXG4gICAgICAgIGNvbnN0IG9wID0gbWFrZU9wKGJvZHksIGV4ZWN1dGUpXG4gICAgICAgIHNldHRsZVN1cGVyc2VkZWQoc3RhdGUucXVldWVkLCBvcClcbiAgICAgICAgc3RhdGUucXVldWVkID0gb3BcbiAgICAgICAgcmV0dXJuIG9wLnByb21pc2VcbiAgICAgIH1cblxuICAgICAgaWYgKGpvaW5BY3RpdmUgJiYgc3RhdGUuYWN0aXZlLmJvZHkgPT09IGJvZHkpIHtcbiAgICAgICAgcmV0dXJuIHN0YXRlLmFjdGl2ZS5wcm9taXNlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wID0gbWFrZU9wKGJvZHksIGV4ZWN1dGUpXG4gICAgICBzdGF0ZS5xdWV1ZWQgPSBvcFxuICAgICAgcmV0dXJuIG9wLnByb21pc2VcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines the correct storage server URL based on the current realm.
|
|
3
|
+
*
|
|
4
|
+
* - If `isPreview` is true, uses the realm's baseUrl (localhost)
|
|
5
|
+
* - If the realm's baseUrl contains `.zone`, uses storage.decentraland.zone
|
|
6
|
+
* - Otherwise, uses storage.decentraland.org (production)
|
|
7
|
+
*
|
|
8
|
+
* The realm never changes mid-session, so the result is memoized; a failed
|
|
9
|
+
* resolution is not memoized so transient getRealm errors can be retried.
|
|
10
|
+
*
|
|
11
|
+
* @returns The storage server base URL
|
|
12
|
+
*/
|
|
13
|
+
export declare function getStorageServerUrl(): Promise<string>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { getRealm } from '~system/Runtime';
|
|
2
|
+
const STORAGE_SERVER_ORG = 'https://storage.decentraland.org';
|
|
3
|
+
const STORAGE_SERVER_ZONE = 'https://storage.decentraland.zone';
|
|
4
|
+
async function resolveStorageServerUrl() {
|
|
5
|
+
const { realmInfo } = await getRealm({});
|
|
6
|
+
if (!realmInfo) {
|
|
7
|
+
throw new Error('Unable to retrieve realm information');
|
|
8
|
+
}
|
|
9
|
+
// Local development / preview mode
|
|
10
|
+
if (realmInfo.isPreview) {
|
|
11
|
+
return realmInfo.baseUrl;
|
|
12
|
+
}
|
|
13
|
+
// Staging / testing environment
|
|
14
|
+
if (realmInfo.baseUrl.includes('.zone')) {
|
|
15
|
+
return STORAGE_SERVER_ZONE;
|
|
16
|
+
}
|
|
17
|
+
// Production environment
|
|
18
|
+
return STORAGE_SERVER_ORG;
|
|
19
|
+
}
|
|
20
|
+
let memoizedUrl = null;
|
|
21
|
+
/**
|
|
22
|
+
* Determines the correct storage server URL based on the current realm.
|
|
23
|
+
*
|
|
24
|
+
* - If `isPreview` is true, uses the realm's baseUrl (localhost)
|
|
25
|
+
* - If the realm's baseUrl contains `.zone`, uses storage.decentraland.zone
|
|
26
|
+
* - Otherwise, uses storage.decentraland.org (production)
|
|
27
|
+
*
|
|
28
|
+
* The realm never changes mid-session, so the result is memoized; a failed
|
|
29
|
+
* resolution is not memoized so transient getRealm errors can be retried.
|
|
30
|
+
*
|
|
31
|
+
* @returns The storage server base URL
|
|
32
|
+
*/
|
|
33
|
+
export function getStorageServerUrl() {
|
|
34
|
+
if (!memoizedUrl) {
|
|
35
|
+
memoizedUrl = resolveStorageServerUrl();
|
|
36
|
+
memoizedUrl.catch(() => {
|
|
37
|
+
memoizedUrl = null;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return memoizedUrl;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS11cmwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2VydmVyL3N0b3JhZ2UtdXJsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUUxQyxNQUFNLGtCQUFrQixHQUFHLGtDQUFrQyxDQUFBO0FBQzdELE1BQU0sbUJBQW1CLEdBQUcsbUNBQW1DLENBQUE7QUFFL0QsS0FBSyxVQUFVLHVCQUF1QjtJQUNwQyxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUE7SUFFeEMsSUFBSSxDQUFDLFNBQVMsRUFBRTtRQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQTtLQUN4RDtJQUVELG1DQUFtQztJQUNuQyxJQUFJLFNBQVMsQ0FBQyxTQUFTLEVBQUU7UUFDdkIsT0FBTyxTQUFTLENBQUMsT0FBTyxDQUFBO0tBQ3pCO0lBRUQsZ0NBQWdDO0lBQ2hDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDdkMsT0FBTyxtQkFBbUIsQ0FBQTtLQUMzQjtJQUVELHlCQUF5QjtJQUN6QixPQUFPLGtCQUFrQixDQUFBO0FBQzNCLENBQUM7QUFFRCxJQUFJLFdBQVcsR0FBMkIsSUFBSSxDQUFBO0FBRTlDOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQjtJQUNqQyxJQUFJLENBQUMsV0FBVyxFQUFFO1FBQ2hCLFdBQVcsR0FBRyx1QkFBdUIsRUFBRSxDQUFBO1FBQ3ZDLFdBQVcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFO1lBQ3JCLFdBQVcsR0FBRyxJQUFJLENBQUE7UUFDcEIsQ0FBQyxDQUFDLENBQUE7S0FDSDtJQUNELE9BQU8sV0FBVyxDQUFBO0FBQ3BCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBnZXRSZWFsbSB9IGZyb20gJ35zeXN0ZW0vUnVudGltZSdcblxuY29uc3QgU1RPUkFHRV9TRVJWRVJfT1JHID0gJ2h0dHBzOi8vc3RvcmFnZS5kZWNlbnRyYWxhbmQub3JnJ1xuY29uc3QgU1RPUkFHRV9TRVJWRVJfWk9ORSA9ICdodHRwczovL3N0b3JhZ2UuZGVjZW50cmFsYW5kLnpvbmUnXG5cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTdG9yYWdlU2VydmVyVXJsKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHsgcmVhbG1JbmZvIH0gPSBhd2FpdCBnZXRSZWFsbSh7fSlcblxuICBpZiAoIXJlYWxtSW5mbykge1xuICAgIHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIHJldHJpZXZlIHJlYWxtIGluZm9ybWF0aW9uJylcbiAgfVxuXG4gIC8vIExvY2FsIGRldmVsb3BtZW50IC8gcHJldmlldyBtb2RlXG4gIGlmIChyZWFsbUluZm8uaXNQcmV2aWV3KSB7XG4gICAgcmV0dXJuIHJlYWxtSW5mby5iYXNlVXJsXG4gIH1cblxuICAvLyBTdGFnaW5nIC8gdGVzdGluZyBlbnZpcm9ubWVudFxuICBpZiAocmVhbG1JbmZvLmJhc2VVcmwuaW5jbHVkZXMoJy56b25lJykpIHtcbiAgICByZXR1cm4gU1RPUkFHRV9TRVJWRVJfWk9ORVxuICB9XG5cbiAgLy8gUHJvZHVjdGlvbiBlbnZpcm9ubWVudFxuICByZXR1cm4gU1RPUkFHRV9TRVJWRVJfT1JHXG59XG5cbmxldCBtZW1vaXplZFVybDogUHJvbWlzZTxzdHJpbmc+IHwgbnVsbCA9IG51bGxcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBjb3JyZWN0IHN0b3JhZ2Ugc2VydmVyIFVSTCBiYXNlZCBvbiB0aGUgY3VycmVudCByZWFsbS5cbiAqXG4gKiAtIElmIGBpc1ByZXZpZXdgIGlzIHRydWUsIHVzZXMgdGhlIHJlYWxtJ3MgYmFzZVVybCAobG9jYWxob3N0KVxuICogLSBJZiB0aGUgcmVhbG0ncyBiYXNlVXJsIGNvbnRhaW5zIGAuem9uZWAsIHVzZXMgc3RvcmFnZS5kZWNlbnRyYWxhbmQuem9uZVxuICogLSBPdGhlcndpc2UsIHVzZXMgc3RvcmFnZS5kZWNlbnRyYWxhbmQub3JnIChwcm9kdWN0aW9uKVxuICpcbiAqIFRoZSByZWFsbSBuZXZlciBjaGFuZ2VzIG1pZC1zZXNzaW9uLCBzbyB0aGUgcmVzdWx0IGlzIG1lbW9pemVkOyBhIGZhaWxlZFxuICogcmVzb2x1dGlvbiBpcyBub3QgbWVtb2l6ZWQgc28gdHJhbnNpZW50IGdldFJlYWxtIGVycm9ycyBjYW4gYmUgcmV0cmllZC5cbiAqXG4gKiBAcmV0dXJucyBUaGUgc3RvcmFnZSBzZXJ2ZXIgYmFzZSBVUkxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFN0b3JhZ2VTZXJ2ZXJVcmwoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgaWYgKCFtZW1vaXplZFVybCkge1xuICAgIG1lbW9pemVkVXJsID0gcmVzb2x2ZVN0b3JhZ2VTZXJ2ZXJVcmwoKVxuICAgIG1lbW9pemVkVXJsLmNhdGNoKCgpID0+IHtcbiAgICAgIG1lbW9pemVkVXJsID0gbnVsbFxuICAgIH0pXG4gIH1cbiAgcmV0dXJuIG1lbW9pemVkVXJsXG59XG4iXX0=
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/// <reference types="@dcl/js-runtime" />
|
|
2
|
+
import { SignedFetchRequest } from '~system/SignedFetch';
|
|
3
|
+
/**
|
|
4
|
+
* Validates that the code is running on a server-side scene.
|
|
5
|
+
* Throws an error if called from a client-side context.
|
|
6
|
+
*
|
|
7
|
+
* @param moduleName - The name of the module for the error message
|
|
8
|
+
* @throws Error if not running on a server-side scene
|
|
9
|
+
*/
|
|
10
|
+
export declare function assertIsServer(moduleName: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Result type for operations that can fail.
|
|
13
|
+
* Returns a tuple of [error, null] on failure or [null, data] on success.
|
|
14
|
+
*/
|
|
15
|
+
export type Result<T, E = string> = [E, null] | [null, T];
|
|
16
|
+
/**
|
|
17
|
+
* Extended result type that includes HTTP status code information.
|
|
18
|
+
*/
|
|
19
|
+
export type FetchResult<T> = [string, null, number?] | [null, T, number];
|
|
20
|
+
/**
|
|
21
|
+
* Wraps a promise to catch errors and return a Result tuple.
|
|
22
|
+
* This allows for cleaner error handling without try-catch blocks.
|
|
23
|
+
*
|
|
24
|
+
* @param promise - The promise to wrap
|
|
25
|
+
* @returns A tuple of [error, null] on failure or [null, data] on success
|
|
26
|
+
*/
|
|
27
|
+
export declare function tryCatch<T, E = Error>(promise: Promise<T>): Promise<Result<T, E>>;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps signedFetch with automatic error handling and JSON parsing. Never rejects.
|
|
30
|
+
* Returns a FetchResult tuple with parsed JSON data or error message and status code.
|
|
31
|
+
*
|
|
32
|
+
* @param signedFetchBody - The signedFetch request configuration
|
|
33
|
+
* @returns A tuple of [error, null, statusCode?] on failure or [null, data, statusCode] on success
|
|
34
|
+
*/
|
|
35
|
+
export declare function wrapSignedFetch<T = unknown>(signedFetchBody: SignedFetchRequest): Promise<FetchResult<T>>;
|
package/server/utils.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { signedFetch } from '~system/SignedFetch';
|
|
2
|
+
import { isServer } from '../network';
|
|
3
|
+
import { errorMessage } from './storage/error-message';
|
|
4
|
+
/**
|
|
5
|
+
* Validates that the code is running on a server-side scene.
|
|
6
|
+
* Throws an error if called from a client-side context.
|
|
7
|
+
*
|
|
8
|
+
* @param moduleName - The name of the module for the error message
|
|
9
|
+
* @throws Error if not running on a server-side scene
|
|
10
|
+
*/
|
|
11
|
+
export function assertIsServer(moduleName) {
|
|
12
|
+
if (!isServer()) {
|
|
13
|
+
throw new Error(`${moduleName} is only available on server-side scenes`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Wraps a promise to catch errors and return a Result tuple.
|
|
18
|
+
* This allows for cleaner error handling without try-catch blocks.
|
|
19
|
+
*
|
|
20
|
+
* @param promise - The promise to wrap
|
|
21
|
+
* @returns A tuple of [error, null] on failure or [null, data] on success
|
|
22
|
+
*/
|
|
23
|
+
export async function tryCatch(promise) {
|
|
24
|
+
try {
|
|
25
|
+
const data = await promise;
|
|
26
|
+
return [null, data];
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return [error, null];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wraps signedFetch with automatic error handling and JSON parsing. Never rejects.
|
|
34
|
+
* Returns a FetchResult tuple with parsed JSON data or error message and status code.
|
|
35
|
+
*
|
|
36
|
+
* @param signedFetchBody - The signedFetch request configuration
|
|
37
|
+
* @returns A tuple of [error, null, statusCode?] on failure or [null, data, statusCode] on success
|
|
38
|
+
*/
|
|
39
|
+
export async function wrapSignedFetch(signedFetchBody) {
|
|
40
|
+
let response;
|
|
41
|
+
try {
|
|
42
|
+
response = await signedFetch(signedFetchBody);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error(`Error in ${signedFetchBody.url} endpoint`, { error });
|
|
46
|
+
return [errorMessage(error, 'signedFetch failed'), null, undefined];
|
|
47
|
+
}
|
|
48
|
+
if (!response) {
|
|
49
|
+
console.error(`Error in ${signedFetchBody.url} endpoint: no response`);
|
|
50
|
+
return ['signedFetch returned no response', null, undefined];
|
|
51
|
+
}
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const errorMessage = `${response.status} ${response.statusText}`;
|
|
54
|
+
console.error(`Error in ${signedFetchBody.url} endpoint`, { response });
|
|
55
|
+
return [errorMessage, null, response.status];
|
|
56
|
+
}
|
|
57
|
+
let body;
|
|
58
|
+
try {
|
|
59
|
+
// JSON.parse throws synchronously, so it can't be wrapped with tryCatch (the
|
|
60
|
+
// throw would happen while evaluating the argument, rejecting this promise).
|
|
61
|
+
body = JSON.parse(response.body || '{}');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
console.error(`Failed to parse response from ${signedFetchBody.url}`);
|
|
65
|
+
return ['Failed to parse response', null, response.status];
|
|
66
|
+
}
|
|
67
|
+
return [null, (body ?? {}), response.status];
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2VydmVyL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQXNCLE1BQU0scUJBQXFCLENBQUE7QUFDckUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUFFdEQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxVQUFrQjtJQUMvQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUU7UUFDZixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsVUFBVSwwQ0FBMEMsQ0FBQyxDQUFBO0tBQ3pFO0FBQ0gsQ0FBQztBQWFEOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsUUFBUSxDQUFlLE9BQW1CO0lBQzlELElBQUk7UUFDRixNQUFNLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQTtRQUMxQixPQUFPLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFBO0tBQ3BCO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDZCxPQUFPLENBQUMsS0FBVSxFQUFFLElBQUksQ0FBQyxDQUFBO0tBQzFCO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsZUFBZSxDQUFjLGVBQW1DO0lBQ3BGLElBQUksUUFBNkQsQ0FBQTtJQUNqRSxJQUFJO1FBQ0YsUUFBUSxHQUFHLE1BQU0sV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0tBQzlDO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDZCxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksZUFBZSxDQUFDLEdBQUcsV0FBVyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtRQUNwRSxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxFQUFFLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQTtLQUNwRTtJQUVELElBQUksQ0FBQyxRQUFRLEVBQUU7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksZUFBZSxDQUFDLEdBQUcsd0JBQXdCLENBQUMsQ0FBQTtRQUN0RSxPQUFPLENBQUMsa0NBQWtDLEVBQUUsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFBO0tBQzdEO0lBRUQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUU7UUFDaEIsTUFBTSxZQUFZLEdBQUcsR0FBRyxRQUFRLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQTtRQUNoRSxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksZUFBZSxDQUFDLEdBQUcsV0FBVyxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUN2RSxPQUFPLENBQUMsWUFBWSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7S0FDN0M7SUFFRCxJQUFJLElBQU8sQ0FBQTtJQUNYLElBQUk7UUFDRiw2RUFBNkU7UUFDN0UsNkVBQTZFO1FBQzdFLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLENBQUE7S0FDekM7SUFBQyxNQUFNO1FBQ04sT0FBTyxDQUFDLEtBQUssQ0FBQyxpQ0FBaUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUE7UUFDckUsT0FBTyxDQUFDLDBCQUEwQixFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7S0FDM0Q7SUFFRCxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQTtBQUNuRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgc2lnbmVkRmV0Y2gsIFNpZ25lZEZldGNoUmVxdWVzdCB9IGZyb20gJ35zeXN0ZW0vU2lnbmVkRmV0Y2gnXG5pbXBvcnQgeyBpc1NlcnZlciB9IGZyb20gJy4uL25ldHdvcmsnXG5pbXBvcnQgeyBlcnJvck1lc3NhZ2UgfSBmcm9tICcuL3N0b3JhZ2UvZXJyb3ItbWVzc2FnZSdcblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhhdCB0aGUgY29kZSBpcyBydW5uaW5nIG9uIGEgc2VydmVyLXNpZGUgc2NlbmUuXG4gKiBUaHJvd3MgYW4gZXJyb3IgaWYgY2FsbGVkIGZyb20gYSBjbGllbnQtc2lkZSBjb250ZXh0LlxuICpcbiAqIEBwYXJhbSBtb2R1bGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIG1vZHVsZSBmb3IgdGhlIGVycm9yIG1lc3NhZ2VcbiAqIEB0aHJvd3MgRXJyb3IgaWYgbm90IHJ1bm5pbmcgb24gYSBzZXJ2ZXItc2lkZSBzY2VuZVxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0SXNTZXJ2ZXIobW9kdWxlTmFtZTogc3RyaW5nKTogdm9pZCB7XG4gIGlmICghaXNTZXJ2ZXIoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHttb2R1bGVOYW1lfSBpcyBvbmx5IGF2YWlsYWJsZSBvbiBzZXJ2ZXItc2lkZSBzY2VuZXNgKVxuICB9XG59XG5cbi8qKlxuICogUmVzdWx0IHR5cGUgZm9yIG9wZXJhdGlvbnMgdGhhdCBjYW4gZmFpbC5cbiAqIFJldHVybnMgYSB0dXBsZSBvZiBbZXJyb3IsIG51bGxdIG9uIGZhaWx1cmUgb3IgW251bGwsIGRhdGFdIG9uIHN1Y2Nlc3MuXG4gKi9cbmV4cG9ydCB0eXBlIFJlc3VsdDxULCBFID0gc3RyaW5nPiA9IFtFLCBudWxsXSB8IFtudWxsLCBUXVxuXG4vKipcbiAqIEV4dGVuZGVkIHJlc3VsdCB0eXBlIHRoYXQgaW5jbHVkZXMgSFRUUCBzdGF0dXMgY29kZSBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IHR5cGUgRmV0Y2hSZXN1bHQ8VD4gPSBbc3RyaW5nLCBudWxsLCBudW1iZXI/XSB8IFtudWxsLCBULCBudW1iZXJdXG5cbi8qKlxuICogV3JhcHMgYSBwcm9taXNlIHRvIGNhdGNoIGVycm9ycyBhbmQgcmV0dXJuIGEgUmVzdWx0IHR1cGxlLlxuICogVGhpcyBhbGxvd3MgZm9yIGNsZWFuZXIgZXJyb3IgaGFuZGxpbmcgd2l0aG91dCB0cnktY2F0Y2ggYmxvY2tzLlxuICpcbiAqIEBwYXJhbSBwcm9taXNlIC0gVGhlIHByb21pc2UgdG8gd3JhcFxuICogQHJldHVybnMgQSB0dXBsZSBvZiBbZXJyb3IsIG51bGxdIG9uIGZhaWx1cmUgb3IgW251bGwsIGRhdGFdIG9uIHN1Y2Nlc3NcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyeUNhdGNoPFQsIEUgPSBFcnJvcj4ocHJvbWlzZTogUHJvbWlzZTxUPik6IFByb21pc2U8UmVzdWx0PFQsIEU+PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHByb21pc2VcbiAgICByZXR1cm4gW251bGwsIGRhdGFdXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIFtlcnJvciBhcyBFLCBudWxsXVxuICB9XG59XG5cbi8qKlxuICogV3JhcHMgc2lnbmVkRmV0Y2ggd2l0aCBhdXRvbWF0aWMgZXJyb3IgaGFuZGxpbmcgYW5kIEpTT04gcGFyc2luZy4gTmV2ZXIgcmVqZWN0cy5cbiAqIFJldHVybnMgYSBGZXRjaFJlc3VsdCB0dXBsZSB3aXRoIHBhcnNlZCBKU09OIGRhdGEgb3IgZXJyb3IgbWVzc2FnZSBhbmQgc3RhdHVzIGNvZGUuXG4gKlxuICogQHBhcmFtIHNpZ25lZEZldGNoQm9keSAtIFRoZSBzaWduZWRGZXRjaCByZXF1ZXN0IGNvbmZpZ3VyYXRpb25cbiAqIEByZXR1cm5zIEEgdHVwbGUgb2YgW2Vycm9yLCBudWxsLCBzdGF0dXNDb2RlP10gb24gZmFpbHVyZSBvciBbbnVsbCwgZGF0YSwgc3RhdHVzQ29kZV0gb24gc3VjY2Vzc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JhcFNpZ25lZEZldGNoPFQgPSB1bmtub3duPihzaWduZWRGZXRjaEJvZHk6IFNpZ25lZEZldGNoUmVxdWVzdCk6IFByb21pc2U8RmV0Y2hSZXN1bHQ8VD4+IHtcbiAgbGV0IHJlc3BvbnNlOiBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIHNpZ25lZEZldGNoPj4gfCB1bmRlZmluZWRcbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IGF3YWl0IHNpZ25lZEZldGNoKHNpZ25lZEZldGNoQm9keSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKGBFcnJvciBpbiAke3NpZ25lZEZldGNoQm9keS51cmx9IGVuZHBvaW50YCwgeyBlcnJvciB9KVxuICAgIHJldHVybiBbZXJyb3JNZXNzYWdlKGVycm9yLCAnc2lnbmVkRmV0Y2ggZmFpbGVkJyksIG51bGwsIHVuZGVmaW5lZF1cbiAgfVxuXG4gIGlmICghcmVzcG9uc2UpIHtcbiAgICBjb25zb2xlLmVycm9yKGBFcnJvciBpbiAke3NpZ25lZEZldGNoQm9keS51cmx9IGVuZHBvaW50OiBubyByZXNwb25zZWApXG4gICAgcmV0dXJuIFsnc2lnbmVkRmV0Y2ggcmV0dXJuZWQgbm8gcmVzcG9uc2UnLCBudWxsLCB1bmRlZmluZWRdXG4gIH1cblxuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgY29uc3QgZXJyb3JNZXNzYWdlID0gYCR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YFxuICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIGluICR7c2lnbmVkRmV0Y2hCb2R5LnVybH0gZW5kcG9pbnRgLCB7IHJlc3BvbnNlIH0pXG4gICAgcmV0dXJuIFtlcnJvck1lc3NhZ2UsIG51bGwsIHJlc3BvbnNlLnN0YXR1c11cbiAgfVxuXG4gIGxldCBib2R5OiBUXG4gIHRyeSB7XG4gICAgLy8gSlNPTi5wYXJzZSB0aHJvd3Mgc3luY2hyb25vdXNseSwgc28gaXQgY2FuJ3QgYmUgd3JhcHBlZCB3aXRoIHRyeUNhdGNoICh0aGVcbiAgICAvLyB0aHJvdyB3b3VsZCBoYXBwZW4gd2hpbGUgZXZhbHVhdGluZyB0aGUgYXJndW1lbnQsIHJlamVjdGluZyB0aGlzIHByb21pc2UpLlxuICAgIGJvZHkgPSBKU09OLnBhcnNlKHJlc3BvbnNlLmJvZHkgfHwgJ3t9JylcbiAgfSBjYXRjaCB7XG4gICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlIGZyb20gJHtzaWduZWRGZXRjaEJvZHkudXJsfWApXG4gICAgcmV0dXJuIFsnRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlJywgbnVsbCwgcmVzcG9uc2Uuc3RhdHVzXVxuICB9XG5cbiAgcmV0dXJuIFtudWxsLCAoYm9keSA/PyB7fSkgYXMgVCwgcmVzcG9uc2Uuc3RhdHVzXVxufVxuIl19
|