@dcl/sdk 7.25.0 → 7.25.1-30310486734.commit-5ffe873
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/composite-provider.js +9 -4
- package/future.d.ts +8 -0
- package/future.js +26 -0
- 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 +14 -1
- package/network/message-bus-sync.js +161 -103
- package/network/server/index.d.ts +14 -0
- package/network/server/index.js +219 -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 +7 -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 +79 -0
- package/server/storage/constants.js +19 -0
- package/server/storage/index.d.ts +45 -0
- package/server/storage/index.js +51 -0
- package/server/storage/player.d.ts +45 -0
- package/server/storage/player.js +198 -0
- package/server/storage/scene.d.ts +40 -0
- package/server/storage/scene.js +188 -0
- package/server/storage/value-cache.d.ts +1 -0
- package/server/storage/value-cache.js +52 -0
- package/server/storage/write-queue.d.ts +1 -0
- package/server/storage/write-queue.js +71 -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 +61 -0
- package/src/atom.ts +98 -0
- package/src/composite-provider.ts +10 -3
- package/src/ethereum-provider/text-encoding.d.ts +4 -0
- package/src/future.ts +38 -0
- 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 +174 -110
- package/src/network/server/index.ts +301 -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 +111 -0
- package/src/server/storage/index.ts +74 -0
- package/src/server/storage/player.ts +289 -0
- package/src/server/storage/scene.ts +270 -0
- package/src/server/storage/value-cache.ts +92 -0
- package/src/server/storage/write-queue.ts +131 -0
- package/src/server/storage-url.ts +49 -0
- package/src/server/utils.ts +76 -0
- package/src/text-codec.ts +12 -59
- package/text-codec.d.ts +8 -23
- package/text-codec.js +13 -55
- package/internal/utf8.d.ts +0 -15
- package/internal/utf8.js +0 -172
- package/src/internal/utf8.ts +0 -167
|
@@ -0,0 +1,188 @@
|
|
|
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 scene-scoped storage that provides methods to interact with
|
|
8
|
+
* scene-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 createSceneStorage = (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
|
+
// Writes to the same key are serialized (and rapid ones coalesced to the
|
|
19
|
+
// latest value) so the service commits them in issue order — overlapping
|
|
20
|
+
// PUTs would otherwise leave both the kept value and the cached value to
|
|
21
|
+
// response-order chance.
|
|
22
|
+
const writes = createWriteQueue();
|
|
23
|
+
async function executeSet(key, body) {
|
|
24
|
+
const baseUrl = await getStorageServerUrl();
|
|
25
|
+
const url = `${baseUrl}/values/${encodeURIComponent(key)}`;
|
|
26
|
+
const [error] = await wrapSignedFetch({
|
|
27
|
+
url,
|
|
28
|
+
init: {
|
|
29
|
+
method: 'PUT',
|
|
30
|
+
headers: {
|
|
31
|
+
'content-type': 'application/json'
|
|
32
|
+
},
|
|
33
|
+
body
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
// Either way the entry changed server-side (or may have): detach any
|
|
37
|
+
// overlapping in-flight GET so its stale response is not cached.
|
|
38
|
+
inflightGets.delete(key);
|
|
39
|
+
if (error) {
|
|
40
|
+
// The PUT may have reached the server, so the cached body is no
|
|
41
|
+
// longer reliable.
|
|
42
|
+
cache.delete(key);
|
|
43
|
+
console.error(`Failed to set storage value '${key}': ${error}`);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
cache.set(key, { body });
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
async function executeDelete(key) {
|
|
50
|
+
const baseUrl = await getStorageServerUrl();
|
|
51
|
+
const url = `${baseUrl}/values/${encodeURIComponent(key)}`;
|
|
52
|
+
const [error, , status] = await wrapSignedFetch({
|
|
53
|
+
url,
|
|
54
|
+
init: {
|
|
55
|
+
method: 'DELETE',
|
|
56
|
+
headers: {}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// Detach again: a GET may have started while the DELETE was in flight.
|
|
60
|
+
inflightGets.delete(key);
|
|
61
|
+
if (error) {
|
|
62
|
+
// A 404 still confirms the key is absent server-side.
|
|
63
|
+
if (status === 404)
|
|
64
|
+
cache.setAbsent(key);
|
|
65
|
+
console.error(`Failed to delete storage value '${key}': ${error}`);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
cache.setAbsent(key);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
async get(key, options) {
|
|
73
|
+
assertIsServer(MODULE_NAME);
|
|
74
|
+
if (config.cacheReads && !options?.fresh) {
|
|
75
|
+
const entry = cache.get(key);
|
|
76
|
+
if (entry?.absent)
|
|
77
|
+
return null;
|
|
78
|
+
// Parse per hit so each caller gets a fresh object (no shared mutation).
|
|
79
|
+
if (entry?.body !== undefined)
|
|
80
|
+
return JSON.parse(entry.body).value;
|
|
81
|
+
}
|
|
82
|
+
// Coalesce concurrent gets (even fresh ones: an in-flight response is
|
|
83
|
+
// milliseconds old, not TTL-stale) into a single network request.
|
|
84
|
+
const joined = inflightGets.get(key);
|
|
85
|
+
if (joined)
|
|
86
|
+
return joined.promise;
|
|
87
|
+
const inflight = {};
|
|
88
|
+
inflight.promise = (async () => {
|
|
89
|
+
try {
|
|
90
|
+
const baseUrl = await getStorageServerUrl();
|
|
91
|
+
const url = `${baseUrl}/values/${encodeURIComponent(key)}`;
|
|
92
|
+
const [error, data, status] = await wrapSignedFetch({ url });
|
|
93
|
+
const isOwner = inflightGets.get(key) === inflight;
|
|
94
|
+
if (error) {
|
|
95
|
+
// A confirmed 404 is a first-class "absent" outcome, not a failure.
|
|
96
|
+
if (status === 404) {
|
|
97
|
+
if (isOwner)
|
|
98
|
+
cache.setAbsent(key);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
console.error(`Failed to get storage value '${key}': ${error}`);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
if (data && data.value !== undefined) {
|
|
105
|
+
// Same serialization shape as set()'s PUT body, so a read followed by
|
|
106
|
+
// an unchanged write can be skipped.
|
|
107
|
+
const body = JSON.stringify({ value: data.value });
|
|
108
|
+
if (isOwner)
|
|
109
|
+
cache.set(key, { body });
|
|
110
|
+
return data.value;
|
|
111
|
+
}
|
|
112
|
+
// 200 with a missing value is ambiguous: neither a confirmed value
|
|
113
|
+
// nor a confirmed absence, so cache nothing.
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
if (inflightGets.get(key) === inflight)
|
|
118
|
+
inflightGets.delete(key);
|
|
119
|
+
}
|
|
120
|
+
})();
|
|
121
|
+
inflightGets.set(key, inflight);
|
|
122
|
+
return inflight.promise;
|
|
123
|
+
},
|
|
124
|
+
async set(key, value, options) {
|
|
125
|
+
assertIsServer(MODULE_NAME);
|
|
126
|
+
const body = JSON.stringify({ value });
|
|
127
|
+
const skipIfUnchanged = options?.skipIfUnchanged ?? config.skipIfUnchanged;
|
|
128
|
+
// Dedup against confirmed state only while no write is pending — a
|
|
129
|
+
// pending write makes the cache momentarily stale; enqueue() coalesces
|
|
130
|
+
// against pending writes instead.
|
|
131
|
+
if (skipIfUnchanged && writes.pending(key) === undefined && cache.get(key)?.body === body) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return writes.enqueue(key, body, (b) => executeSet(key, b), skipIfUnchanged);
|
|
135
|
+
},
|
|
136
|
+
async delete(key) {
|
|
137
|
+
assertIsServer(MODULE_NAME);
|
|
138
|
+
// Invalidate immediately — even while the DELETE waits behind other
|
|
139
|
+
// writes, reads must not serve the doomed value, and a stale
|
|
140
|
+
// "unchanged" skip would lose a future write.
|
|
141
|
+
cache.delete(key);
|
|
142
|
+
inflightGets.delete(key);
|
|
143
|
+
return writes.enqueue(key, null, () => executeDelete(key), true);
|
|
144
|
+
},
|
|
145
|
+
async getValues(options) {
|
|
146
|
+
assertIsServer(MODULE_NAME);
|
|
147
|
+
const { prefix, limit, offset } = options ?? {};
|
|
148
|
+
const baseUrl = await getStorageServerUrl();
|
|
149
|
+
const parts = [];
|
|
150
|
+
if (!!prefix) {
|
|
151
|
+
parts.push(`prefix=${encodeURIComponent(prefix)}`);
|
|
152
|
+
}
|
|
153
|
+
if (!!limit) {
|
|
154
|
+
parts.push(`limit=${limit}`);
|
|
155
|
+
}
|
|
156
|
+
if (!!offset) {
|
|
157
|
+
parts.push(`offset=${offset}`);
|
|
158
|
+
}
|
|
159
|
+
const query = parts.join('&');
|
|
160
|
+
const url = query ? `${baseUrl}/values?${query}` : `${baseUrl}/values`;
|
|
161
|
+
const [error, response] = await wrapSignedFetch({ url });
|
|
162
|
+
if (error) {
|
|
163
|
+
console.error(`Failed to get storage values: ${error}`);
|
|
164
|
+
return { data: [], pagination: { offset: 0, total: 0 } };
|
|
165
|
+
}
|
|
166
|
+
const data = response?.data ?? [];
|
|
167
|
+
// Seed the per-key cache so subsequent get()/set() on returned keys can
|
|
168
|
+
// skip the network. Only keys with no live entry and no pending write
|
|
169
|
+
// are seeded: existing per-key state comes from a confirmed operation
|
|
170
|
+
// that this page snapshot — whose request started earlier — must not
|
|
171
|
+
// clobber with stale data. Absence is never seeded (prefix/pagination
|
|
172
|
+
// make it non-authoritative). A page larger than cacheMaxEntries churns
|
|
173
|
+
// the cache; entries repopulate lazily.
|
|
174
|
+
for (const entry of data) {
|
|
175
|
+
if (entry.value !== undefined && !writes.isPending(entry.key) && cache.get(entry.key) === undefined) {
|
|
176
|
+
cache.set(entry.key, { body: JSON.stringify({ value: entry.value }) });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const requestedOffset = offset ?? 0;
|
|
180
|
+
const pagination = {
|
|
181
|
+
offset: response?.pagination?.offset ?? requestedOffset,
|
|
182
|
+
total: response?.pagination?.total ?? data.length
|
|
183
|
+
};
|
|
184
|
+
return { data, pagination };
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NlbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2Uvc2NlbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDcEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFDMUQsT0FBTyxFQUNMLG1CQUFtQixFQUluQixXQUFXLEVBR1osTUFBTSxhQUFhLENBQUE7QUFDcEIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ2hELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQTZDaEQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLFNBQTZCLG1CQUFtQixFQUFFLEVBQWlCLEVBQUU7SUFDdEcsTUFBTSxLQUFLLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDdEMseUVBQXlFO0lBQ3pFLDJFQUEyRTtJQUMzRSw2REFBNkQ7SUFDN0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXlDLENBQUE7SUFDckUseUVBQXlFO0lBQ3pFLHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUseUJBQXlCO0lBQ3pCLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixFQUFFLENBQUE7SUFFakMsS0FBSyxVQUFVLFVBQVUsQ0FBQyxHQUFXLEVBQUUsSUFBWTtRQUNqRCxNQUFNLE9BQU8sR0FBRyxNQUFNLG1CQUFtQixFQUFFLENBQUE7UUFDM0MsTUFBTSxHQUFHLEdBQUcsR0FBRyxPQUFPLFdBQVcsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQTtRQUUxRCxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxlQUFlLENBQUM7WUFDcEMsR0FBRztZQUNILElBQUksRUFBRTtnQkFDSixNQUFNLEVBQUUsS0FBSztn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QXNFO1lBQ3RFLHFFQUFxRTtZQUNyRSxzRUFBc0U7WUFDdEUsd0VBQXdFO1lBQ3hFLHdDQUF3QztZQUN4QyxLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksRUFBRTtnQkFDeEIsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLFNBQVMsRUFBRTtvQkFDbkcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO2lCQUN2RTthQUNGO1lBRUQsTUFBTSxlQUFlLEdBQUcsTUFBTSxJQUFJLENBQUMsQ0FBQTtZQUNuQyxNQUFNLFVBQVUsR0FBRztnQkFDakIsTUFBTSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxJQUFJLGVBQWU7Z0JBQ3ZELEtBQUssRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTTthQUNsRCxDQUFBO1lBRUQsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQTtRQUM3QixDQUFDO0tBQ0YsQ0FBQTtBQUNILENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldFN0b3JhZ2VTZXJ2ZXJVcmwgfSBmcm9tICcuLi9zdG9yYWdlLXVybCdcbmltcG9ydCB7IGFzc2VydElzU2VydmVyLCB3cmFwU2lnbmVkRmV0Y2ggfSBmcm9tICcuLi91dGlscydcbmltcG9ydCB7XG4gIGNyZWF0ZVN0b3JhZ2VDb25maWcsXG4gIEdldE9wdGlvbnMsXG4gIEdldFZhbHVlc09wdGlvbnMsXG4gIEdldFZhbHVlc1Jlc3VsdCxcbiAgTU9EVUxFX05BTUUsXG4gIFNldE9wdGlvbnMsXG4gIFN0b3JhZ2VDb25maWdTdGF0ZVxufSBmcm9tICcuL2NvbnN0YW50cydcbmltcG9ydCB7IGNyZWF0ZVZhbHVlQ2FjaGUgfSBmcm9tICcuL3ZhbHVlLWNhY2hlJ1xuaW1wb3J0IHsgY3JlYXRlV3JpdGVRdWV1ZSB9IGZyb20gJy4vd3JpdGUtcXVldWUnXG5cbi8qKlxuICogU2NlbmUtc2NvcGVkIHN0b3JhZ2UgaW50ZXJmYWNlIGZvciBrZXktdmFsdWUgcGFpcnMgZnJvbSB0aGUgU2VydmVyIFNpZGUgU3RvcmFnZSBzZXJ2aWNlLlxuICogVGhpcyBpcyBOT1QgZmlsZXN5c3RlbSBzdG9yYWdlIC0gZGF0YSBpcyBzdG9yZWQgaW4gdGhlIHJlbW90ZSBzdG9yYWdlIHNlcnZpY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVNjZW5lU3RvcmFnZSB7XG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHNjZW5lIHN0b3JhZ2UgYnkga2V5IGZyb20gdGhlIFNlcnZlciBTaWRlIFN0b3JhZ2Ugc2VydmljZS5cbiAgICpcbiAgICogQnkgZGVmYXVsdCAoY2FjaGVSZWFkcyksIHZhbHVlcyByZWFkIG9yIHdyaXR0ZW4gZHVyaW5nIHRoZSBsYXN0IGNhY2hlTWF4QWdlTXNcbiAgICogYXJlIHNlcnZlZCBmcm9tIGEgbG9jYWwgY2FjaGUgd2l0aG91dCBhIG5ldHdvcmsgcmVxdWVzdCwgaW5jbHVkaW5nIGNvbmZpcm1lZFxuICAgKiBcIm5vdCBmb3VuZFwiIHJlc3VsdHMuIENvbmN1cnJlbnQgZ2V0cyBmb3IgdGhlIHNhbWUga2V5IHNoYXJlIG9uZSByZXF1ZXN0LlxuICAgKiBPdXQtb2YtYmFuZCB3cml0ZXJzIChlLmcuIENMSSBzdG9yYWdlIGNvbW1hbmRzKSBtYXkgbm90IGJlIHZpc2libGUgZm9yIHVwIHRvXG4gICAqIGNhY2hlTWF4QWdlTXMg4oCUIHBhc3MgeyBmcmVzaDogdHJ1ZSB9IHRvIGZvcmNlIGEgbmV0d29yayByZWFkLlxuICAgKiBAcGFyYW0ga2V5IC0gVGhlIGtleSB0byByZXRyaWV2ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIHsgZnJlc2ggfSB0byBieXBhc3MgdGhlIHJlYWQgY2FjaGVcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHBhcnNlZCBKU09OIHZhbHVlLCBvciBudWxsIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgZ2V0PFQgPSB1bmtub3duPihrZXk6IHN0cmluZywgb3B0aW9ucz86IEdldE9wdGlvbnMpOiBQcm9taXNlPFQgfCBudWxsPlxuXG4gIC8qKlxuICAgKiBTdG9yZXMgYSB2YWx1ZSBpbiBzY2VuZSBzdG9yYWdlIGluIHRoZSBTZXJ2ZXIgU2lkZSBTdG9yYWdlIHNlcnZpY2UuXG4gICAqIEBwYXJhbSBrZXkgLSBUaGUga2V5IHRvIHN0b3JlIHRoZSB2YWx1ZSB1bmRlclxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gc3RvcmUgKHdpbGwgYmUgSlNPTiBzZXJpYWxpemVkKVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIHsgc2tpcElmVW5jaGFuZ2VkIH0gdG8gc2tpcCB0aGUgbmV0d29yayB3cml0ZSB3aGVuIHRoZSB2YWx1ZSBpcyBhbHJlYWR5IHN0b3JlZFxuICAgKi9cbiAgc2V0PFQgPSB1bmtub3duPihrZXk6IHN0cmluZywgdmFsdWU6IFQsIG9wdGlvbnM/OiBTZXRPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPlxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGEgdmFsdWUgZnJvbSBzY2VuZSBzdG9yYWdlIGluIHRoZSBTZXJ2ZXIgU2lkZSBTdG9yYWdlIHNlcnZpY2UuXG4gICAqIEBwYXJhbSBrZXkgLSBUaGUga2V5IHRvIGRlbGV0ZVxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIGlmIGRlbGV0ZWQsIGZhbHNlIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgZGVsZXRlKGtleTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPlxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGtleS12YWx1ZSBlbnRyaWVzIGZyb20gc2NlbmUgc3RvcmFnZSwgb3B0aW9uYWxseSBmaWx0ZXJlZCBieSBwcmVmaXguXG4gICAqIFN1cHBvcnRzIHBhZ2luYXRpb24gdmlhIGxpbWl0IGFuZCBvZmZzZXQuXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgeyBwcmVmaXgsIGxpbWl0LCBvZmZzZXQgfSBmb3IgZmlsdGVyaW5nIGFuZCBwYWdpbmF0aW9uLlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB7IGRhdGEsIHBhZ2luYXRpb246IHsgb2Zmc2V0LCB0b3RhbCB9IH0gZm9yIHBhZ2luYXRpb24gVUlcbiAgICovXG4gIGdldFZhbHVlcyhvcHRpb25zPzogR2V0VmFsdWVzT3B0aW9ucyk6IFByb21pc2U8R2V0VmFsdWVzUmVzdWx0PlxufVxuXG4vKipcbiAqIENyZWF0ZXMgc2NlbmUtc2NvcGVkIHN0b3JhZ2UgdGhhdCBwcm92aWRlcyBtZXRob2RzIHRvIGludGVyYWN0IHdpdGhcbiAqIHNjZW5lLXNwZWNpZmljIGtleS12YWx1ZSBwYWlycyBmcm9tIHRoZSBTZXJ2ZXIgU2lkZSBTdG9yYWdlIHNlcnZpY2UuXG4gKiBUaGlzIG1vZHVsZSBvbmx5IHdvcmtzIHdoZW4gcnVubmluZyBvbiBzZXJ2ZXItc2lkZSBzY2VuZXMuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGNvbnN0IGNyZWF0ZVNjZW5lU3RvcmFnZSA9IChjb25maWc6IFN0b3JhZ2VDb25maWdTdGF0ZSA9IGNyZWF0ZVN0b3JhZ2VDb25maWcoKSk6IElTY2VuZVN0b3JhZ2UgPT4ge1xuICBjb25zdCBjYWNoZSA9IGNyZWF0ZVZhbHVlQ2FjaGUoY29uZmlnKVxuICAvLyBFYWNoIGluLWZsaWdodCBHRVQgaXMgdHJhY2tlZCBieSBhIHdyYXBwZXIgb2JqZWN0IHdob3NlIGlkZW50aXR5IG1hcmtzXG4gIC8vIG93bmVyc2hpcDogc2V0KCkvZGVsZXRlKCkgZHJvcCB0aGUgd3JhcHBlciwgZGV0YWNoaW5nIHRoZSBwZW5kaW5nIEdFVCBzb1xuICAvLyBpdHMgc3RhbGUgcmVzcG9uc2UgY2Fubm90IG92ZXJ3cml0ZSB0aGUgbmV3ZXIgY2FjaGUgZW50cnkuXG4gIGNvbnN0IGluZmxpZ2h0R2V0cyA9IG5ldyBNYXA8c3RyaW5nLCB7IHByb21pc2U6IFByb21pc2U8dW5rbm93bj4gfT4oKVxuICAvLyBXcml0ZXMgdG8gdGhlIHNhbWUga2V5IGFyZSBzZXJpYWxpemVkIChhbmQgcmFwaWQgb25lcyBjb2FsZXNjZWQgdG8gdGhlXG4gIC8vIGxhdGVzdCB2YWx1ZSkgc28gdGhlIHNlcnZpY2UgY29tbWl0cyB0aGVtIGluIGlzc3VlIG9yZGVyIOKAlCBvdmVybGFwcGluZ1xuICAvLyBQVVRzIHdvdWxkIG90aGVyd2lzZSBsZWF2ZSBib3RoIHRoZSBrZXB0IHZhbHVlIGFuZCB0aGUgY2FjaGVkIHZhbHVlIHRvXG4gIC8vIHJlc3BvbnNlLW9yZGVyIGNoYW5jZS5cbiAgY29uc3Qgd3JpdGVzID0gY3JlYXRlV3JpdGVRdWV1ZSgpXG5cbiAgYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZVNldChrZXk6IHN0cmluZywgYm9keTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYmFzZVVybCA9IGF3YWl0IGdldFN0b3JhZ2VTZXJ2ZXJVcmwoKVxuICAgIGNvbnN0IHVybCA9IGAke2Jhc2VVcmx9L3ZhbHVlcy8ke2VuY29kZVVSSUNvbXBvbmVudChrZXkpfWBcblxuICAgIGNvbnN0IFtlcnJvcl0gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2goe1xuICAgICAgdXJsLFxuICAgICAgaW5pdDoge1xuICAgICAgICBtZXRob2Q6ICdQVVQnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ2NvbnRlbnQtdHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgICB9LFxuICAgICAgICBib2R5XG4gICAgICB9XG4gICAgfSlcblxuICAgIC8vIEVpdGhlciB3YXkgdGhlIGVudHJ5IGNoYW5nZWQgc2VydmVyLXNpZGUgKG9yIG1heSBoYXZlKTogZGV0YWNoIGFueVxuICAgIC8vIG92ZXJsYXBwaW5nIGluLWZsaWdodCBHRVQgc28gaXRzIHN0YWxlIHJlc3BvbnNlIGlzIG5vdCBjYWNoZWQuXG4gICAgaW5mbGlnaHRHZXRzLmRlbGV0ZShrZXkpXG5cbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIC8vIFRoZSBQVVQgbWF5IGhhdmUgcmVhY2hlZCB0aGUgc2VydmVyLCBzbyB0aGUgY2FjaGVkIGJvZHkgaXMgbm9cbiAgICAgIC8vIGxvbmdlciByZWxpYWJsZS5cbiAgICAgIGNhY2hlLmRlbGV0ZShrZXkpXG4gICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gc2V0IHN0b3JhZ2UgdmFsdWUgJyR7a2V5fSc6ICR7ZXJyb3J9YClcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIGNhY2hlLnNldChrZXksIHsgYm9keSB9KVxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBleGVjdXRlRGVsZXRlKGtleTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYmFzZVVybCA9IGF3YWl0IGdldFN0b3JhZ2VTZXJ2ZXJVcmwoKVxuICAgIGNvbnN0IHVybCA9IGAke2Jhc2VVcmx9L3ZhbHVlcy8ke2VuY29kZVVSSUNvbXBvbmVudChrZXkpfWBcblxuICAgIGNvbnN0IFtlcnJvciwgLCBzdGF0dXNdID0gYXdhaXQgd3JhcFNpZ25lZEZldGNoKHtcbiAgICAgIHVybCxcbiAgICAgIGluaXQ6IHtcbiAgICAgICAgbWV0aG9kOiAnREVMRVRFJyxcbiAgICAgICAgaGVhZGVyczoge31cbiAgICAgIH1cbiAgICB9KVxuXG4gICAgLy8gRGV0YWNoIGFnYWluOiBhIEdFVCBtYXkgaGF2ZSBzdGFydGVkIHdoaWxlIHRoZSBERUxFVEUgd2FzIGluIGZsaWdodC5cbiAgICBpbmZsaWdodEdldHMuZGVsZXRlKGtleSlcblxuICAgIGlmIChlcnJvcikge1xuICAgICAgLy8gQSA0MDQgc3RpbGwgY29uZmlybXMgdGhlIGtleSBpcyBhYnNlbnQgc2VydmVyLXNpZGUuXG4gICAgICBpZiAoc3RhdHVzID09PSA0MDQpIGNhY2hlLnNldEFic2VudChrZXkpXG4gICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlIHN0b3JhZ2UgdmFsdWUgJyR7a2V5fSc6ICR7ZXJyb3J9YClcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIGNhY2hlLnNldEFic2VudChrZXkpXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYXN5bmMgZ2V0PFQgPSB1bmtub3duPihrZXk6IHN0cmluZywgb3B0aW9ucz86IEdldE9wdGlvbnMpOiBQcm9taXNlPFQgfCBudWxsPiB7XG4gICAgICBhc3NlcnRJc1NlcnZlcihNT0RVTEVfTkFNRSlcblxuICAgICAgaWYgKGNvbmZpZy5jYWNoZVJlYWRzICYmICFvcHRpb25zPy5mcmVzaCkge1xuICAgICAgICBjb25zdCBlbnRyeSA9IGNhY2hlLmdldChrZXkpXG4gICAgICAgIGlmIChlbnRyeT8uYWJzZW50KSByZXR1cm4gbnVsbFxuICAgICAgICAvLyBQYXJzZSBwZXIgaGl0IHNvIGVhY2ggY2FsbGVyIGdldHMgYSBmcmVzaCBvYmplY3QgKG5vIHNoYXJlZCBtdXRhdGlvbikuXG4gICAgICAgIGlmIChlbnRyeT8uYm9keSAhPT0gdW5kZWZpbmVkKSByZXR1cm4gSlNPTi5wYXJzZShlbnRyeS5ib2R5KS52YWx1ZSBhcyBUXG4gICAgICB9XG5cbiAgICAgIC8vIENvYWxlc2NlIGNvbmN1cnJlbnQgZ2V0cyAoZXZlbiBmcmVzaCBvbmVzOiBhbiBpbi1mbGlnaHQgcmVzcG9uc2UgaXNcbiAgICAgIC8vIG1pbGxpc2Vjb25kcyBvbGQsIG5vdCBUVEwtc3RhbGUpIGludG8gYSBzaW5nbGUgbmV0d29yayByZXF1ZXN0LlxuICAgICAgY29uc3Qgam9pbmVkID0gaW5mbGlnaHRHZXRzLmdldChrZXkpXG4gICAgICBpZiAoam9pbmVkKSByZXR1cm4gam9pbmVkLnByb21pc2UgYXMgUHJvbWlzZTxUIHwgbnVsbD5cblxuICAgICAgY29uc3QgaW5mbGlnaHQgPSB7fSBhcyB7IHByb21pc2U6IFByb21pc2U8VCB8IG51bGw+IH1cbiAgICAgIGluZmxpZ2h0LnByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGJhc2VVcmwgPSBhd2FpdCBnZXRTdG9yYWdlU2VydmVyVXJsKClcbiAgICAgICAgICBjb25zdCB1cmwgPSBgJHtiYXNlVXJsfS92YWx1ZXMvJHtlbmNvZGVVUklDb21wb25lbnQoa2V5KX1gXG5cbiAgICAgICAgICBjb25zdCBbZXJyb3IsIGRhdGEsIHN0YXR1c10gPSBhd2FpdCB3cmFwU2lnbmVkRmV0Y2g8eyB2YWx1ZTogVCB9Pih7IHVybCB9KVxuXG4gICAgICAgICAgY29uc3QgaXNPd25lciA9IGluZmxpZ2h0R2V0cy5nZXQoa2V5KSA9PT0gaW5mbGlnaHRcblxuICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgLy8gQSBjb25maXJtZWQgNDA0IGlzIGEgZmlyc3QtY2xhc3MgXCJhYnNlbnRcIiBvdXRjb21lLCBub3QgYSBmYWlsdXJlLlxuICAgICAgICAgICAgaWYgKHN0YXR1cyA9PT0gNDA0KSB7XG4gICAgICAgICAgICAgIGlmIChpc093bmVyKSBjYWNoZS5zZXRBYnNlbnQoa2V5KVxuICAgICAgICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGdldCBzdG9yYWdlIHZhbHVlICcke2tleX0nOiAke2Vycm9yfWApXG4gICAgICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChkYXRhICYmIGRhdGEudmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gU2FtZSBzZXJpYWxpemF0aW9uIHNoYXBlIGFzIHNldCgpJ3MgUFVUIGJvZHksIHNvIGEgcmVhZCBmb2xsb3dlZCBieVxuICAgICAgICAgICAgLy8gYW4gdW5jaGFuZ2VkIHdyaXRlIGNhbiBiZSBza2lwcGVkLlxuICAgICAgICAgICAgY29uc3QgYm9keSA9IEpTT04uc3RyaW5naWZ5KHsgdmFsdWU6IGRhdGEudmFsdWUgfSlcbiAgICAgICAgICAgIGlmIChpc093bmVyKSBjYWNoZS5zZXQoa2V5LCB7IGJvZHkgfSlcbiAgICAgICAgICAgIHJldHVybiBkYXRhLnZhbHVlXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gMjAwIHdpdGggYSBtaXNzaW5nIHZhbHVlIGlzIGFtYmlndW91czogbmVpdGhlciBhIGNvbmZpcm1lZCB2YWx1ZVxuICAgICAgICAgIC8vIG5vciBhIGNvbmZpcm1lZCBhYnNlbmNlLCBzbyBjYWNoZSBub3RoaW5nLlxuICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgaWYgKGluZmxpZ2h0R2V0cy5nZXQoa2V5KSA9PT0gaW5mbGlnaHQpIGluZmxpZ2h0R2V0cy5kZWxldGUoa2V5KVxuICAgICAgICB9XG4gICAgICB9KSgpXG5cbiAgICAgIGluZmxpZ2h0R2V0cy5zZXQoa2V5LCBpbmZsaWdodClcbiAgICAgIHJldHVybiBpbmZsaWdodC5wcm9taXNlXG4gICAgfSxcblxuICAgIGFzeW5jIHNldDxUID0gdW5rbm93bj4oa2V5OiBzdHJpbmcsIHZhbHVlOiBULCBvcHRpb25zPzogU2V0T3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgYXNzZXJ0SXNTZXJ2ZXIoTU9EVUxFX05BTUUpXG5cbiAgICAgIGNvbnN0IGJvZHkgPSBKU09OLnN0cmluZ2lmeSh7IHZhbHVlIH0pXG4gICAgICBjb25zdCBza2lwSWZVbmNoYW5nZWQgPSBvcHRpb25zPy5za2lwSWZVbmNoYW5nZWQgPz8gY29uZmlnLnNraXBJZlVuY2hhbmdlZFxuXG4gICAgICAvLyBEZWR1cCBhZ2FpbnN0IGNvbmZpcm1lZCBzdGF0ZSBvbmx5IHdoaWxlIG5vIHdyaXRlIGlzIHBlbmRpbmcg4oCUIGFcbiAgICAgIC8vIHBlbmRpbmcgd3JpdGUgbWFrZXMgdGhlIGNhY2hlIG1vbWVudGFyaWx5IHN0YWxlOyBlbnF1ZXVlKCkgY29hbGVzY2VzXG4gICAgICAvLyBhZ2FpbnN0IHBlbmRpbmcgd3JpdGVzIGluc3RlYWQuXG4gICAgICBpZiAoc2tpcElmVW5jaGFuZ2VkICYmIHdyaXRlcy5wZW5kaW5nKGtleSkgPT09IHVuZGVmaW5lZCAmJiBjYWNoZS5nZXQoa2V5KT8uYm9keSA9PT0gYm9keSkge1xuICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gd3JpdGVzLmVucXVldWUoa2V5LCBib2R5LCAoYikgPT4gZXhlY3V0ZVNldChrZXksIGIgYXMgc3RyaW5nKSwgc2tpcElmVW5jaGFuZ2VkKVxuICAgIH0sXG5cbiAgICBhc3luYyBkZWxldGUoa2V5OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgIGFzc2VydElzU2VydmVyKE1PRFVMRV9OQU1FKVxuXG4gICAgICAvLyBJbnZhbGlkYXRlIGltbWVkaWF0ZWx5IOKAlCBldmVuIHdoaWxlIHRoZSBERUxFVEUgd2FpdHMgYmVoaW5kIG90aGVyXG4gICAgICAvLyB3cml0ZXMsIHJlYWRzIG11c3Qgbm90IHNlcnZlIHRoZSBkb29tZWQgdmFsdWUsIGFuZCBhIHN0YWxlXG4gICAgICAvLyBcInVuY2hhbmdlZFwiIHNraXAgd291bGQgbG9zZSBhIGZ1dHVyZSB3cml0ZS5cbiAgICAgIGNhY2hlLmRlbGV0ZShrZXkpXG4gICAgICBpbmZsaWdodEdldHMuZGVsZXRlKGtleSlcblxuICAgICAgcmV0dXJuIHdyaXRlcy5lbnF1ZXVlKGtleSwgbnVsbCwgKCkgPT4gZXhlY3V0ZURlbGV0ZShrZXkpLCB0cnVlKVxuICAgIH0sXG5cbiAgICBhc3luYyBnZXRWYWx1ZXMob3B0aW9ucz86IEdldFZhbHVlc09wdGlvbnMpOiBQcm9taXNlPEdldFZhbHVlc1Jlc3VsdD4ge1xuICAgICAgYXNzZXJ0SXNTZXJ2ZXIoTU9EVUxFX05BTUUpXG5cbiAgICAgIGNvbnN0IHsgcHJlZml4LCBsaW1pdCwgb2Zmc2V0IH0gPSBvcHRpb25zID8/IHt9XG4gICAgICBjb25zdCBiYXNlVXJsID0gYXdhaXQgZ2V0U3RvcmFnZVNlcnZlclVybCgpXG4gICAgICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXVxuXG4gICAgICBpZiAoISFwcmVmaXgpIHtcbiAgICAgICAgcGFydHMucHVzaChgcHJlZml4PSR7ZW5jb2RlVVJJQ29tcG9uZW50KHByZWZpeCl9YClcbiAgICAgIH1cblxuICAgICAgaWYgKCEhbGltaXQpIHtcbiAgICAgICAgcGFydHMucHVzaChgbGltaXQ9JHtsaW1pdH1gKVxuICAgICAgfVxuXG4gICAgICBpZiAoISFvZmZzZXQpIHtcbiAgICAgICAgcGFydHMucHVzaChgb2Zmc2V0PSR7b2Zmc2V0fWApXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHF1ZXJ5ID0gcGFydHMuam9pbignJicpXG4gICAgICBjb25zdCB1cmwgPSBxdWVyeSA/IGAke2Jhc2VVcmx9L3ZhbHVlcz8ke3F1ZXJ5fWAgOiBgJHtiYXNlVXJsfS92YWx1ZXNgXG5cbiAgICAgIGNvbnN0IFtlcnJvciwgcmVzcG9uc2VdID0gYXdhaXQgd3JhcFNpZ25lZEZldGNoPEdldFZhbHVlc1Jlc3VsdD4oeyB1cmwgfSlcblxuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBnZXQgc3RvcmFnZSB2YWx1ZXM6ICR7ZXJyb3J9YClcbiAgICAgICAgcmV0dXJuIHsgZGF0YTogW10sIHBhZ2luYXRpb246IHsgb2Zmc2V0OiAwLCB0b3RhbDogMCB9IH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YSA9IHJlc3BvbnNlPy5kYXRhID8/IFtdXG5cbiAgICAgIC8vIFNlZWQgdGhlIHBlci1rZXkgY2FjaGUgc28gc3Vic2VxdWVudCBnZXQoKS9zZXQoKSBvbiByZXR1cm5lZCBrZXlzIGNhblxuICAgICAgLy8gc2tpcCB0aGUgbmV0d29yay4gT25seSBrZXlzIHdpdGggbm8gbGl2ZSBlbnRyeSBhbmQgbm8gcGVuZGluZyB3cml0ZVxuICAgICAgLy8gYXJlIHNlZWRlZDogZXhpc3RpbmcgcGVyLWtleSBzdGF0ZSBjb21lcyBmcm9tIGEgY29uZmlybWVkIG9wZXJhdGlvblxuICAgICAgLy8gdGhhdCB0aGlzIHBhZ2Ugc25hcHNob3Qg4oCUIHdob3NlIHJlcXVlc3Qgc3RhcnRlZCBlYXJsaWVyIOKAlCBtdXN0IG5vdFxuICAgICAgLy8gY2xvYmJlciB3aXRoIHN0YWxlIGRhdGEuIEFic2VuY2UgaXMgbmV2ZXIgc2VlZGVkIChwcmVmaXgvcGFnaW5hdGlvblxuICAgICAgLy8gbWFrZSBpdCBub24tYXV0aG9yaXRhdGl2ZSkuIEEgcGFnZSBsYXJnZXIgdGhhbiBjYWNoZU1heEVudHJpZXMgY2h1cm5zXG4gICAgICAvLyB0aGUgY2FjaGU7IGVudHJpZXMgcmVwb3B1bGF0ZSBsYXppbHkuXG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGRhdGEpIHtcbiAgICAgICAgaWYgKGVudHJ5LnZhbHVlICE9PSB1bmRlZmluZWQgJiYgIXdyaXRlcy5pc1BlbmRpbmcoZW50cnkua2V5KSAmJiBjYWNoZS5nZXQoZW50cnkua2V5KSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY2FjaGUuc2V0KGVudHJ5LmtleSwgeyBib2R5OiBKU09OLnN0cmluZ2lmeSh7IHZhbHVlOiBlbnRyeS52YWx1ZSB9KSB9KVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlcXVlc3RlZE9mZnNldCA9IG9mZnNldCA/PyAwXG4gICAgICBjb25zdCBwYWdpbmF0aW9uID0ge1xuICAgICAgICBvZmZzZXQ6IHJlc3BvbnNlPy5wYWdpbmF0aW9uPy5vZmZzZXQgPz8gcmVxdWVzdGVkT2Zmc2V0LFxuICAgICAgICB0b3RhbDogcmVzcG9uc2U/LnBhZ2luYXRpb24/LnRvdGFsID8/IGRhdGEubGVuZ3RoXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7IGRhdGEsIHBhZ2luYXRpb24gfVxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
function insert(key, entry) {
|
|
9
|
+
// Delete + re-insert moves refreshed keys to the end of the Map's
|
|
10
|
+
// insertion order, so eviction below drops the least-recently-written.
|
|
11
|
+
entries.delete(key);
|
|
12
|
+
entries.set(key, { ...entry, storedAt: Date.now() });
|
|
13
|
+
// Guard against misconfiguration: a negative bound would loop forever on
|
|
14
|
+
// an empty map, and a NaN bound would silently disable eviction.
|
|
15
|
+
const maxEntries = Number.isFinite(config.cacheMaxEntries)
|
|
16
|
+
? Math.max(0, config.cacheMaxEntries)
|
|
17
|
+
: DEFAULT_STORAGE_CONFIG.cacheMaxEntries;
|
|
18
|
+
while (entries.size > maxEntries) {
|
|
19
|
+
entries.delete(entries.keys().next().value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
get(key) {
|
|
24
|
+
const entry = entries.get(key);
|
|
25
|
+
if (!entry)
|
|
26
|
+
return undefined;
|
|
27
|
+
// Guard against misconfiguration, mirroring cacheMaxEntries: a NaN
|
|
28
|
+
// bound would silently disable expiry (NaN comparisons are false).
|
|
29
|
+
// Negative values need no guard — they just expire everything.
|
|
30
|
+
const maxAgeMs = Number.isFinite(config.cacheMaxAgeMs)
|
|
31
|
+
? config.cacheMaxAgeMs
|
|
32
|
+
: DEFAULT_STORAGE_CONFIG.cacheMaxAgeMs;
|
|
33
|
+
// Lazy max-age expiry: storedAt is never refreshed on hits, so the age
|
|
34
|
+
// bounds the time since the last actual network confirmation.
|
|
35
|
+
if (Date.now() - entry.storedAt > maxAgeMs) {
|
|
36
|
+
entries.delete(key);
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return entry;
|
|
40
|
+
},
|
|
41
|
+
set(key, entry) {
|
|
42
|
+
insert(key, entry);
|
|
43
|
+
},
|
|
44
|
+
setAbsent(key) {
|
|
45
|
+
insert(key, { absent: true });
|
|
46
|
+
},
|
|
47
|
+
delete(key) {
|
|
48
|
+
entries.delete(key);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsdWUtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2UvdmFsdWUtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLHNCQUFzQixFQUFzQixNQUFNLGFBQWEsQ0FBQTtBQWlDeEU7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLE1BQTBCO0lBQ3pELE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUE2QyxDQUFBO0lBRXBFLFNBQVMsTUFBTSxDQUFDLEdBQVcsRUFBRSxLQUFpQjtRQUM1QyxrRUFBa0U7UUFDbEUsdUVBQXVFO1FBQ3ZFLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLEtBQUssRUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUVwRCx5RUFBeUU7UUFDekUsaUVBQWlFO1FBQ2pFLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQztZQUN4RCxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLGVBQWUsQ0FBQztZQUNyQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsZUFBZSxDQUFBO1FBRTFDLE9BQU8sT0FBTyxDQUFDLElBQUksR0FBRyxVQUFVLEVBQUU7WUFDaEMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBTSxDQUFDLENBQUE7U0FDN0M7SUFDSCxDQUFDO0lBRUQsT0FBTztRQUNMLEdBQUcsQ0FBQyxHQUFXO1lBQ2IsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUM5QixJQUFJLENBQUMsS0FBSztnQkFBRSxPQUFPLFNBQVMsQ0FBQTtZQUU1QixtRUFBbUU7WUFDbkUsbUVBQW1FO1lBQ25FLCtEQUErRDtZQUMvRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUM7Z0JBQ3BELENBQUMsQ0FBQyxNQUFNLENBQUMsYUFBYTtnQkFDdEIsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLGFBQWEsQ0FBQTtZQUV4Qyx1RUFBdUU7WUFDdkUsOERBQThEO1lBQzlELElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxRQUFRLEdBQUcsUUFBUSxFQUFFO2dCQUMxQyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO2dCQUNuQixPQUFPLFNBQVMsQ0FBQTthQUNqQjtZQUVELE9BQU8sS0FBSyxDQUFBO1FBQ2QsQ0FBQztRQUVELEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBdUI7WUFDdEMsTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUNwQixDQUFDO1FBRUQsU0FBUyxDQUFDLEdBQVc7WUFDbkIsTUFBTSxDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQy9CLENBQUM7UUFFRCxNQUFNLENBQUMsR0FBVztZQUNoQixPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ3JCLENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERFRkFVTFRfU1RPUkFHRV9DT05GSUcsIFN0b3JhZ2VDb25maWdTdGF0ZSB9IGZyb20gJy4vY29uc3RhbnRzJ1xuXG4vKipcbiAqIEEgY2FjaGVkIGZhY3QgYWJvdXQgYSBrZXkncyBzZXJ2ZXItc2lkZSBzdGF0ZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlRW50cnkge1xuICAvKipcbiAgICogU2VyaWFsaXplZCBgeyB2YWx1ZSB9YCBib2R5OyBhYnNlbnQgZm9yIG5lZ2F0aXZlIGVudHJpZXMuIFBhcnNlZCBwZXIgcmVhZFxuICAgKiBoaXQgc28gY2FsbGVycyBuZXZlciBzaGFyZSBvYmplY3QgcmVmZXJlbmNlcywgYW5kIGNvbXBhcmVkIHZlcmJhdGltIGZvclxuICAgKiB3cml0ZSBkZWR1cCAoZXhhY3QgZXF1YWxpdHkg4oCUIG5vIGhhc2gtY29sbGlzaW9uIHJpc2spLlxuICAgKi9cbiAgYm9keT86IHN0cmluZ1xuICAvKiogVHJ1ZSB3aGVuIHRoZSBzZXJ2ZXIgY29uZmlybWVkIHRoZSBrZXkgZG9lcyBub3QgZXhpc3QgKEdFVCA0MDQgb3Igc3VjY2Vzc2Z1bCBERUxFVEUpLiAqL1xuICBhYnNlbnQ/OiBib29sZWFuXG59XG5cbi8qKlxuICogQm91bmRlZCwgbGF6aWx5LWV4cGlyaW5nIGNhY2hlIG9mIGtleSBzdGF0ZXMsIGJhY2tpbmcgYm90aCB3cml0ZSBkZWR1cFxuICogKHNraXAgc3RvcmFnZSB3cml0ZXMgd2hvc2UgdmFsdWUgaXMgYWxyZWFkeSBrbm93biB0byBiZSBzdG9yZWQpIGFuZCByZWFkXG4gKiBjYWNoaW5nIChzZXJ2ZSBnZXQoKSB3aXRob3V0IGEgbmV0d29yayByZXF1ZXN0IHdpdGhpbiB0aGUgVFRMKS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFZhbHVlQ2FjaGUge1xuICAvKiogUmV0dXJucyB0aGUgZW50cnkgaWYgcHJlc2VudCBhbmQgZnJlc2g7IGxhemlseSBldmljdHMgZXhwaXJlZCBlbnRyaWVzLiAqL1xuICBnZXQoa2V5OiBzdHJpbmcpOiBDYWNoZUVudHJ5IHwgdW5kZWZpbmVkXG4gIC8qKiBTdG9yZXMgb3IgcmVmcmVzaGVzIGEga25vd24gdmFsdWUgKHNlcmlhbGl6ZWQgYm9keSk7IG92ZXJ3cml0ZXMgbmVnYXRpdmUgZW50cmllcy4gKi9cbiAgc2V0KGtleTogc3RyaW5nLCBlbnRyeTogeyBib2R5OiBzdHJpbmcgfSk6IHZvaWRcbiAgLyoqIFN0b3JlcyBhIGNvbmZpcm1lZC1hYnNlbnQgKG5lZ2F0aXZlKSBlbnRyeSwgcmVwbGFjaW5nIGFueSB2YWx1ZSBlbnRyeS4gKi9cbiAgc2V0QWJzZW50KGtleTogc3RyaW5nKTogdm9pZFxuICBkZWxldGUoa2V5OiBzdHJpbmcpOiB2b2lkXG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgYm91bmRlZCB2YWx1ZSBjYWNoZSBzaGFyZWQgYnkgYSBzdG9yYWdlIHNjb3BlLlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVWYWx1ZUNhY2hlKGNvbmZpZzogU3RvcmFnZUNvbmZpZ1N0YXRlKTogVmFsdWVDYWNoZSB7XG4gIGNvbnN0IGVudHJpZXMgPSBuZXcgTWFwPHN0cmluZywgQ2FjaGVFbnRyeSAmIHsgc3RvcmVkQXQ6IG51bWJlciB9PigpXG5cbiAgZnVuY3Rpb24gaW5zZXJ0KGtleTogc3RyaW5nLCBlbnRyeTogQ2FjaGVFbnRyeSk6IHZvaWQge1xuICAgIC8vIERlbGV0ZSArIHJlLWluc2VydCBtb3ZlcyByZWZyZXNoZWQga2V5cyB0byB0aGUgZW5kIG9mIHRoZSBNYXAnc1xuICAgIC8vIGluc2VydGlvbiBvcmRlciwgc28gZXZpY3Rpb24gYmVsb3cgZHJvcHMgdGhlIGxlYXN0LXJlY2VudGx5LXdyaXR0ZW4uXG4gICAgZW50cmllcy5kZWxldGUoa2V5KVxuICAgIGVudHJpZXMuc2V0KGtleSwgeyAuLi5lbnRyeSwgc3RvcmVkQXQ6IERhdGUubm93KCkgfSlcblxuICAgIC8vIEd1YXJkIGFnYWluc3QgbWlzY29uZmlndXJhdGlvbjogYSBuZWdhdGl2ZSBib3VuZCB3b3VsZCBsb29wIGZvcmV2ZXIgb25cbiAgICAvLyBhbiBlbXB0eSBtYXAsIGFuZCBhIE5hTiBib3VuZCB3b3VsZCBzaWxlbnRseSBkaXNhYmxlIGV2aWN0aW9uLlxuICAgIGNvbnN0IG1heEVudHJpZXMgPSBOdW1iZXIuaXNGaW5pdGUoY29uZmlnLmNhY2hlTWF4RW50cmllcylcbiAgICAgID8gTWF0aC5tYXgoMCwgY29uZmlnLmNhY2hlTWF4RW50cmllcylcbiAgICAgIDogREVGQVVMVF9TVE9SQUdFX0NPTkZJRy5jYWNoZU1heEVudHJpZXNcblxuICAgIHdoaWxlIChlbnRyaWVzLnNpemUgPiBtYXhFbnRyaWVzKSB7XG4gICAgICBlbnRyaWVzLmRlbGV0ZShlbnRyaWVzLmtleXMoKS5uZXh0KCkudmFsdWUhKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZ2V0KGtleTogc3RyaW5nKTogQ2FjaGVFbnRyeSB8IHVuZGVmaW5lZCB7XG4gICAgICBjb25zdCBlbnRyeSA9IGVudHJpZXMuZ2V0KGtleSlcbiAgICAgIGlmICghZW50cnkpIHJldHVybiB1bmRlZmluZWRcblxuICAgICAgLy8gR3VhcmQgYWdhaW5zdCBtaXNjb25maWd1cmF0aW9uLCBtaXJyb3JpbmcgY2FjaGVNYXhFbnRyaWVzOiBhIE5hTlxuICAgICAgLy8gYm91bmQgd291bGQgc2lsZW50bHkgZGlzYWJsZSBleHBpcnkgKE5hTiBjb21wYXJpc29ucyBhcmUgZmFsc2UpLlxuICAgICAgLy8gTmVnYXRpdmUgdmFsdWVzIG5lZWQgbm8gZ3VhcmQg4oCUIHRoZXkganVzdCBleHBpcmUgZXZlcnl0aGluZy5cbiAgICAgIGNvbnN0IG1heEFnZU1zID0gTnVtYmVyLmlzRmluaXRlKGNvbmZpZy5jYWNoZU1heEFnZU1zKVxuICAgICAgICA/IGNvbmZpZy5jYWNoZU1heEFnZU1zXG4gICAgICAgIDogREVGQVVMVF9TVE9SQUdFX0NPTkZJRy5jYWNoZU1heEFnZU1zXG5cbiAgICAgIC8vIExhenkgbWF4LWFnZSBleHBpcnk6IHN0b3JlZEF0IGlzIG5ldmVyIHJlZnJlc2hlZCBvbiBoaXRzLCBzbyB0aGUgYWdlXG4gICAgICAvLyBib3VuZHMgdGhlIHRpbWUgc2luY2UgdGhlIGxhc3QgYWN0dWFsIG5ldHdvcmsgY29uZmlybWF0aW9uLlxuICAgICAgaWYgKERhdGUubm93KCkgLSBlbnRyeS5zdG9yZWRBdCA+IG1heEFnZU1zKSB7XG4gICAgICAgIGVudHJpZXMuZGVsZXRlKGtleSlcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZW50cnlcbiAgICB9LFxuXG4gICAgc2V0KGtleTogc3RyaW5nLCBlbnRyeTogeyBib2R5OiBzdHJpbmcgfSk6IHZvaWQge1xuICAgICAgaW5zZXJ0KGtleSwgZW50cnkpXG4gICAgfSxcblxuICAgIHNldEFic2VudChrZXk6IHN0cmluZyk6IHZvaWQge1xuICAgICAgaW5zZXJ0KGtleSwgeyBhYnNlbnQ6IHRydWUgfSlcbiAgICB9LFxuXG4gICAgZGVsZXRlKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgICBlbnRyaWVzLmRlbGV0ZShrZXkpXG4gICAgfVxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates the per-key write serializer shared by a storage scope.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export function createWriteQueue() {
|
|
6
|
+
const keys = new Map();
|
|
7
|
+
function makeOp(body, execute) {
|
|
8
|
+
let resolve;
|
|
9
|
+
const promise = new Promise((r) => (resolve = r));
|
|
10
|
+
return { body, execute, promise, resolve };
|
|
11
|
+
}
|
|
12
|
+
async function drain(key, state) {
|
|
13
|
+
for (;;) {
|
|
14
|
+
const op = state.active;
|
|
15
|
+
let result = false;
|
|
16
|
+
try {
|
|
17
|
+
result = await op.execute(op.body);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Executors report failures via their boolean result; a throw is
|
|
21
|
+
// unexpected but must not wedge the queue.
|
|
22
|
+
}
|
|
23
|
+
op.resolve(result);
|
|
24
|
+
if (state.queued) {
|
|
25
|
+
state.active = state.queued;
|
|
26
|
+
state.queued = undefined;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
keys.delete(key);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
pending(key) {
|
|
36
|
+
const state = keys.get(key);
|
|
37
|
+
if (!state)
|
|
38
|
+
return undefined;
|
|
39
|
+
return (state.queued ?? state.active).body;
|
|
40
|
+
},
|
|
41
|
+
isPending(key) {
|
|
42
|
+
return keys.has(key);
|
|
43
|
+
},
|
|
44
|
+
enqueue(key, body, execute, joinActive) {
|
|
45
|
+
const state = keys.get(key);
|
|
46
|
+
if (!state) {
|
|
47
|
+
const op = makeOp(body, execute);
|
|
48
|
+
const newState = { active: op };
|
|
49
|
+
keys.set(key, newState);
|
|
50
|
+
void drain(key, newState);
|
|
51
|
+
return op.promise;
|
|
52
|
+
}
|
|
53
|
+
if (state.queued) {
|
|
54
|
+
// A queued op has not started, so it is issued "after" this caller
|
|
55
|
+
// either way: join it when identical, supersede it otherwise.
|
|
56
|
+
if (state.queued.body !== body) {
|
|
57
|
+
state.queued.body = body;
|
|
58
|
+
state.queued.execute = execute;
|
|
59
|
+
}
|
|
60
|
+
return state.queued.promise;
|
|
61
|
+
}
|
|
62
|
+
if (joinActive && state.active.body === body) {
|
|
63
|
+
return state.active.promise;
|
|
64
|
+
}
|
|
65
|
+
const op = makeOp(body, execute);
|
|
66
|
+
state.queued = op;
|
|
67
|
+
return op.promise;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdGUtcXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL3N0b3JhZ2Uvd3JpdGUtcXVldWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBc0RBOzs7R0FHRztBQUNILE1BQU0sVUFBVSxnQkFBZ0I7SUFDOUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUE7SUFFeEMsU0FBUyxNQUFNLENBQUMsSUFBbUIsRUFBRSxPQUE2QjtRQUNoRSxJQUFJLE9BQW1DLENBQUE7UUFDdkMsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLENBQVUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDMUQsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFBO0lBQzVDLENBQUM7SUFFRCxLQUFLLFVBQVUsS0FBSyxDQUFDLEdBQVcsRUFBRSxLQUFlO1FBQy9DLFNBQVM7WUFDUCxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFBO1lBQ3ZCLElBQUksTUFBTSxHQUFHLEtBQUssQ0FBQTtZQUNsQixJQUFJO2dCQUNGLE1BQU0sR0FBRyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFBO2FBQ25DO1lBQUMsTUFBTTtnQkFDTixpRUFBaUU7Z0JBQ2pFLDJDQUEyQzthQUM1QztZQUNELEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUE7WUFFbEIsSUFBSSxLQUFLLENBQUMsTUFBTSxFQUFFO2dCQUNoQixLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUE7Z0JBQzNCLEtBQUssQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFBO2FBQ3pCO2lCQUFNO2dCQUNMLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2hCLE9BQU07YUFDUDtTQUNGO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxPQUFPLENBQUMsR0FBVztZQUNqQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQzNCLElBQUksQ0FBQyxLQUFLO2dCQUFFLE9BQU8sU0FBUyxDQUFBO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDNUMsQ0FBQztRQUVELFNBQVMsQ0FBQyxHQUFXO1lBQ25CLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUN0QixDQUFDO1FBRUQsT0FBTyxDQUFDLEdBQVcsRUFBRSxJQUFtQixFQUFFLE9BQTZCLEVBQUUsVUFBbUI7WUFDMUYsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUUzQixJQUFJLENBQUMsS0FBSyxFQUFFO2dCQUNWLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUE7Z0JBQ2hDLE1BQU0sUUFBUSxHQUFhLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxDQUFBO2dCQUN6QyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQTtnQkFDdkIsS0FBSyxLQUFLLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFBO2dCQUN6QixPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUE7YUFDbEI7WUFFRCxJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUU7Z0JBQ2hCLG1FQUFtRTtnQkFDbkUsOERBQThEO2dCQUM5RCxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLElBQUksRUFBRTtvQkFDOUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO29CQUN4QixLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7aUJBQy9CO2dCQUNELE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUE7YUFDNUI7WUFFRCxJQUFJLFVBQVUsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxJQUFJLEVBQUU7Z0JBQzVDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUE7YUFDNUI7WUFFRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQ2hDLEtBQUssQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFBO1lBQ2pCLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQTtRQUNuQixDQUFDO0tBQ0YsQ0FBQTtBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEEgcGVuZGluZyB3cml0ZSBvcGVyYXRpb24uIGBib2R5YCBpcyB0aGUgc2VyaWFsaXplZCBQVVQgcGF5bG9hZCwgb3IgbnVsbFxuICogZm9yIGEgREVMRVRFLiBDYWxsZXJzIGNvYWxlc2NlZCBpbnRvIHRoZSBvcCBzaGFyZSBpdHMgcHJvbWlzZS5cbiAqIEBpbnRlcm5hbFxuICovXG5pbnRlcmZhY2UgUGVuZGluZ09wIHtcbiAgYm9keTogc3RyaW5nIHwgbnVsbFxuICBleGVjdXRlOiAoYm9keTogc3RyaW5nIHwgbnVsbCkgPT4gUHJvbWlzZTxib29sZWFuPlxuICBwcm9taXNlOiBQcm9taXNlPGJvb2xlYW4+XG4gIHJlc29sdmU6IChyZXN1bHQ6IGJvb2xlYW4pID0+IHZvaWRcbn1cblxuaW50ZXJmYWNlIEtleVN0YXRlIHtcbiAgLyoqIFRoZSBvcCBjdXJyZW50bHkgb24gdGhlIG5ldHdvcmsuICovXG4gIGFjdGl2ZTogUGVuZGluZ09wXG4gIC8qKiBBdCBtb3N0IG9uZSBxdWV1ZWQgb3A7IGxhdGVyIHdyaXRlcyByZXBsYWNlIGl0cyBwYXlsb2FkIChsYXRlc3Qgd2lucykuICovXG4gIHF1ZXVlZD86IFBlbmRpbmdPcFxufVxuXG4vKipcbiAqIFNlcmlhbGl6ZXMgd3JpdGVzIHBlciBrZXkgc28gdGhlIHNlcnZpY2UgY29tbWl0cyB0aGVtIGluIGlzc3VlIG9yZGVyLlxuICogT3ZlcmxhcHBpbmcgUFVUcyBmcm9tIHRoZSBzaW5nbGUgc2NlbmUgc2VydmVyIHdvdWxkIG90aGVyd2lzZSByYWNlOiB0aGVcbiAqIHNlcnZlciBrZWVwcyB3aGljaGV2ZXIgcmVxdWVzdCBpdCBwcm9jZXNzZXMgbGFzdCwgd2hpbGUgdGhlIGxvY2FsIGNhY2hlXG4gKiBrZWVwcyB3aGljaGV2ZXIgcmVzcG9uc2UgYXJyaXZlcyBsYXN0IOKAlCBlaXRoZXIgY2FuIGRpc2FncmVlIHdpdGggdGhlIGxhc3RcbiAqIHNldCgpIGlzc3VlZC4gV2l0aCBhdCBtb3N0IG9uZSBpbi1mbGlnaHQgb3AgcGVyIGtleSBhbmQgYSBzaW5nbGUgcXVldWVkXG4gKiBcImxhdGVzdCB2YWx1ZVwiIHNsb3QsIHRoZSBzZXJ2ZXIncyBmaW5hbCBzdGF0ZSBhbHdheXMgbWF0Y2hlcyB0aGUgbGFzdFxuICogd3JpdGUgaXNzdWVkLCBhbmQgTiByYXBpZCB3cml0ZXMgY29sbGFwc2UgaW50byBhdCBtb3N0IDIgbmV0d29yayBjYWxscy5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdyaXRlUXVldWUge1xuICAvKipcbiAgICogQm9keSBvZiB0aGUgbGF0ZXN0IGlzc3VlZCB3cml0ZSBmb3IgdGhlIGtleSAodGhlIHF1ZXVlZCBvcCBpZiBwcmVzZW50LFxuICAgKiBlbHNlIHRoZSBpbi1mbGlnaHQgb25lKTogYSBzdHJpbmcgZm9yIGEgUFVULCBudWxsIGZvciBhIERFTEVURSxcbiAgICogdW5kZWZpbmVkIHdoZW4gbm8gd3JpdGUgaXMgcGVuZGluZy5cbiAgICovXG4gIHBlbmRpbmcoa2V5OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkXG4gIC8qKiBUcnVlIHdoaWxlIGFueSB3cml0ZSBmb3IgdGhlIGtleSBpcyBpbiBmbGlnaHQgb3IgcXVldWVkLiAqL1xuICBpc1BlbmRpbmcoa2V5OiBzdHJpbmcpOiBib29sZWFuXG4gIC8qKlxuICAgKiBJc3N1ZXMgYSB3cml0ZS4gSWYgb25lIGlzIGluIGZsaWdodCwgdGhlIG5ldyBvcCBpcyBxdWV1ZWQg4oCUIHJlcGxhY2luZyBhbnlcbiAgICogYWxyZWFkeS1xdWV1ZWQgb3AsIHdob3NlIGNhbGxlcnMgdGhlbiBmb2xsb3cgdGhpcyBvcCdzIG91dGNvbWUgKHRoZWlyXG4gICAqIHZhbHVlIHdhcyBzdXBlcnNlZGVkIGJlZm9yZSBpdCBjb3VsZCBldmVyIGJlIG9ic2VydmVkKS4gQW4gb3AgaWRlbnRpY2FsXG4gICAqIHRvIHRoZSBxdWV1ZWQgb25lIGpvaW5zIGl0OyBgam9pbkFjdGl2ZWAgYWRkaXRpb25hbGx5IGFsbG93cyBqb2luaW5nIGFuXG4gICAqIGlkZW50aWNhbCBpbi1mbGlnaHQgb3AgKG9ubHkgdmFsaWQgZm9yIGRlZHVwLXRvbGVyYW50IGNhbGxlcnMsIHNpbmNlIHRoYXRcbiAgICogb3Agd2FzIGlzc3VlZCBiZWZvcmUgdGhpcyBjYWxsKS5cbiAgICovXG4gIGVucXVldWUoXG4gICAga2V5OiBzdHJpbmcsXG4gICAgYm9keTogc3RyaW5nIHwgbnVsbCxcbiAgICBleGVjdXRlOiAoYm9keTogc3RyaW5nIHwgbnVsbCkgPT4gUHJvbWlzZTxib29sZWFuPixcbiAgICBqb2luQWN0aXZlOiBib29sZWFuXG4gICk6IFByb21pc2U8Ym9vbGVhbj5cbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBwZXIta2V5IHdyaXRlIHNlcmlhbGl6ZXIgc2hhcmVkIGJ5IGEgc3RvcmFnZSBzY29wZS5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlV3JpdGVRdWV1ZSgpOiBXcml0ZVF1ZXVlIHtcbiAgY29uc3Qga2V5cyA9IG5ldyBNYXA8c3RyaW5nLCBLZXlTdGF0ZT4oKVxuXG4gIGZ1bmN0aW9uIG1ha2VPcChib2R5OiBzdHJpbmcgfCBudWxsLCBleGVjdXRlOiBQZW5kaW5nT3BbJ2V4ZWN1dGUnXSk6IFBlbmRpbmdPcCB7XG4gICAgbGV0IHJlc29sdmUhOiAocmVzdWx0OiBib29sZWFuKSA9PiB2b2lkXG4gICAgY29uc3QgcHJvbWlzZSA9IG5ldyBQcm9taXNlPGJvb2xlYW4+KChyKSA9PiAocmVzb2x2ZSA9IHIpKVxuICAgIHJldHVybiB7IGJvZHksIGV4ZWN1dGUsIHByb21pc2UsIHJlc29sdmUgfVxuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gZHJhaW4oa2V5OiBzdHJpbmcsIHN0YXRlOiBLZXlTdGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoOzspIHtcbiAgICAgIGNvbnN0IG9wID0gc3RhdGUuYWN0aXZlXG4gICAgICBsZXQgcmVzdWx0ID0gZmFsc2VcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IG9wLmV4ZWN1dGUob3AuYm9keSlcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBFeGVjdXRvcnMgcmVwb3J0IGZhaWx1cmVzIHZpYSB0aGVpciBib29sZWFuIHJlc3VsdDsgYSB0aHJvdyBpc1xuICAgICAgICAvLyB1bmV4cGVjdGVkIGJ1dCBtdXN0IG5vdCB3ZWRnZSB0aGUgcXVldWUuXG4gICAgICB9XG4gICAgICBvcC5yZXNvbHZlKHJlc3VsdClcblxuICAgICAgaWYgKHN0YXRlLnF1ZXVlZCkge1xuICAgICAgICBzdGF0ZS5hY3RpdmUgPSBzdGF0ZS5xdWV1ZWRcbiAgICAgICAgc3RhdGUucXVldWVkID0gdW5kZWZpbmVkXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBrZXlzLmRlbGV0ZShrZXkpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgcGVuZGluZyhrZXk6IHN0cmluZyk6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQge1xuICAgICAgY29uc3Qgc3RhdGUgPSBrZXlzLmdldChrZXkpXG4gICAgICBpZiAoIXN0YXRlKSByZXR1cm4gdW5kZWZpbmVkXG4gICAgICByZXR1cm4gKHN0YXRlLnF1ZXVlZCA/PyBzdGF0ZS5hY3RpdmUpLmJvZHlcbiAgICB9LFxuXG4gICAgaXNQZW5kaW5nKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICByZXR1cm4ga2V5cy5oYXMoa2V5KVxuICAgIH0sXG5cbiAgICBlbnF1ZXVlKGtleTogc3RyaW5nLCBib2R5OiBzdHJpbmcgfCBudWxsLCBleGVjdXRlOiBQZW5kaW5nT3BbJ2V4ZWN1dGUnXSwgam9pbkFjdGl2ZTogYm9vbGVhbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgY29uc3Qgc3RhdGUgPSBrZXlzLmdldChrZXkpXG5cbiAgICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgY29uc3Qgb3AgPSBtYWtlT3AoYm9keSwgZXhlY3V0ZSlcbiAgICAgICAgY29uc3QgbmV3U3RhdGU6IEtleVN0YXRlID0geyBhY3RpdmU6IG9wIH1cbiAgICAgICAga2V5cy5zZXQoa2V5LCBuZXdTdGF0ZSlcbiAgICAgICAgdm9pZCBkcmFpbihrZXksIG5ld1N0YXRlKVxuICAgICAgICByZXR1cm4gb3AucHJvbWlzZVxuICAgICAgfVxuXG4gICAgICBpZiAoc3RhdGUucXVldWVkKSB7XG4gICAgICAgIC8vIEEgcXVldWVkIG9wIGhhcyBub3Qgc3RhcnRlZCwgc28gaXQgaXMgaXNzdWVkIFwiYWZ0ZXJcIiB0aGlzIGNhbGxlclxuICAgICAgICAvLyBlaXRoZXIgd2F5OiBqb2luIGl0IHdoZW4gaWRlbnRpY2FsLCBzdXBlcnNlZGUgaXQgb3RoZXJ3aXNlLlxuICAgICAgICBpZiAoc3RhdGUucXVldWVkLmJvZHkgIT09IGJvZHkpIHtcbiAgICAgICAgICBzdGF0ZS5xdWV1ZWQuYm9keSA9IGJvZHlcbiAgICAgICAgICBzdGF0ZS5xdWV1ZWQuZXhlY3V0ZSA9IGV4ZWN1dGVcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RhdGUucXVldWVkLnByb21pc2VcbiAgICAgIH1cblxuICAgICAgaWYgKGpvaW5BY3RpdmUgJiYgc3RhdGUuYWN0aXZlLmJvZHkgPT09IGJvZHkpIHtcbiAgICAgICAgcmV0dXJuIHN0YXRlLmFjdGl2ZS5wcm9taXNlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wID0gbWFrZU9wKGJvZHksIGV4ZWN1dGUpXG4gICAgICBzdGF0ZS5xdWV1ZWQgPSBvcFxuICAgICAgcmV0dXJuIG9wLnByb21pc2VcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -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.
|
|
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,61 @@
|
|
|
1
|
+
import { signedFetch } from '~system/SignedFetch';
|
|
2
|
+
import { isServer } from '../network';
|
|
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 function assertIsServer(moduleName) {
|
|
11
|
+
if (!isServer()) {
|
|
12
|
+
throw new Error(`${moduleName} is only available on server-side scenes`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wraps a promise to catch errors and return a Result tuple.
|
|
17
|
+
* This allows for cleaner error handling without try-catch blocks.
|
|
18
|
+
*
|
|
19
|
+
* @param promise - The promise to wrap
|
|
20
|
+
* @returns A tuple of [error, null] on failure or [null, data] on success
|
|
21
|
+
*/
|
|
22
|
+
export async function tryCatch(promise) {
|
|
23
|
+
try {
|
|
24
|
+
const data = await promise;
|
|
25
|
+
return [null, data];
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return [error, null];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Wraps signedFetch with automatic error handling and JSON parsing.
|
|
33
|
+
* Returns a FetchResult tuple with parsed JSON data or error message and status code.
|
|
34
|
+
*
|
|
35
|
+
* @param signedFetchBody - The signedFetch request configuration
|
|
36
|
+
* @returns A tuple of [error, null, statusCode?] on failure or [null, data, statusCode] on success
|
|
37
|
+
*/
|
|
38
|
+
export async function wrapSignedFetch(signedFetchBody) {
|
|
39
|
+
const [error, response] = await tryCatch(signedFetch(signedFetchBody));
|
|
40
|
+
if (error) {
|
|
41
|
+
console.error(`Error in ${signedFetchBody.url} endpoint`, { error });
|
|
42
|
+
return [error.message, null, undefined];
|
|
43
|
+
}
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorMessage = `${response.status} ${response.statusText}`;
|
|
46
|
+
console.error(`Error in ${signedFetchBody.url} endpoint`, { response });
|
|
47
|
+
return [errorMessage, null, response.status];
|
|
48
|
+
}
|
|
49
|
+
let body;
|
|
50
|
+
try {
|
|
51
|
+
// JSON.parse throws synchronously, so it can't be wrapped with tryCatch (the
|
|
52
|
+
// throw would happen while evaluating the argument, rejecting this promise).
|
|
53
|
+
body = JSON.parse(response.body || '{}');
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
console.error(`Failed to parse response from ${signedFetchBody.url}`);
|
|
57
|
+
return ['Failed to parse response', null, response.status];
|
|
58
|
+
}
|
|
59
|
+
return [null, (body ?? {}), response.status];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2VydmVyL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQXNCLE1BQU0scUJBQXFCLENBQUE7QUFDckUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUVyQzs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLFVBQWtCO0lBQy9DLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRTtRQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxVQUFVLDBDQUEwQyxDQUFDLENBQUE7S0FDekU7QUFDSCxDQUFDO0FBYUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxRQUFRLENBQWUsT0FBbUI7SUFDOUQsSUFBSTtRQUNGLE1BQU0sSUFBSSxHQUFHLE1BQU0sT0FBTyxDQUFBO1FBQzFCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUE7S0FDcEI7SUFBQyxPQUFPLEtBQUssRUFBRTtRQUNkLE9BQU8sQ0FBQyxLQUFVLEVBQUUsSUFBSSxDQUFDLENBQUE7S0FDMUI7QUFDSCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlLENBQWMsZUFBbUM7SUFDcEYsTUFBTSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsR0FBRyxNQUFNLFFBQVEsQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQTtJQUV0RSxJQUFJLEtBQUssRUFBRTtRQUNULE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxlQUFlLENBQUMsR0FBRyxXQUFXLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFBO1FBQ3BFLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQTtLQUN4QztJQUVELElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFO1FBQ2hCLE1BQU0sWUFBWSxHQUFHLEdBQUcsUUFBUSxDQUFDLE1BQU0sSUFBSSxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUE7UUFDaEUsT0FBTyxDQUFDLEtBQUssQ0FBQyxZQUFZLGVBQWUsQ0FBQyxHQUFHLFdBQVcsRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUE7UUFDdkUsT0FBTyxDQUFDLFlBQVksRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0tBQzdDO0lBRUQsSUFBSSxJQUFPLENBQUE7SUFDWCxJQUFJO1FBQ0YsNkVBQTZFO1FBQzdFLDZFQUE2RTtRQUM3RSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxDQUFBO0tBQ3pDO0lBQUMsTUFBTTtRQUNOLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLGVBQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO1FBQ3JFLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0tBQzNEO0lBRUQsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksSUFBSSxFQUFFLENBQU0sRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDbkQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHNpZ25lZEZldGNoLCBTaWduZWRGZXRjaFJlcXVlc3QgfSBmcm9tICd+c3lzdGVtL1NpZ25lZEZldGNoJ1xuaW1wb3J0IHsgaXNTZXJ2ZXIgfSBmcm9tICcuLi9uZXR3b3JrJ1xuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGF0IHRoZSBjb2RlIGlzIHJ1bm5pbmcgb24gYSBzZXJ2ZXItc2lkZSBzY2VuZS5cbiAqIFRocm93cyBhbiBlcnJvciBpZiBjYWxsZWQgZnJvbSBhIGNsaWVudC1zaWRlIGNvbnRleHQuXG4gKlxuICogQHBhcmFtIG1vZHVsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgbW9kdWxlIGZvciB0aGUgZXJyb3IgbWVzc2FnZVxuICogQHRocm93cyBFcnJvciBpZiBub3QgcnVubmluZyBvbiBhIHNlcnZlci1zaWRlIHNjZW5lXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRJc1NlcnZlcihtb2R1bGVOYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKCFpc1NlcnZlcigpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke21vZHVsZU5hbWV9IGlzIG9ubHkgYXZhaWxhYmxlIG9uIHNlcnZlci1zaWRlIHNjZW5lc2ApXG4gIH1cbn1cblxuLyoqXG4gKiBSZXN1bHQgdHlwZSBmb3Igb3BlcmF0aW9ucyB0aGF0IGNhbiBmYWlsLlxuICogUmV0dXJucyBhIHR1cGxlIG9mIFtlcnJvciwgbnVsbF0gb24gZmFpbHVyZSBvciBbbnVsbCwgZGF0YV0gb24gc3VjY2Vzcy5cbiAqL1xuZXhwb3J0IHR5cGUgUmVzdWx0PFQsIEUgPSBzdHJpbmc+ID0gW0UsIG51bGxdIHwgW251bGwsIFRdXG5cbi8qKlxuICogRXh0ZW5kZWQgcmVzdWx0IHR5cGUgdGhhdCBpbmNsdWRlcyBIVFRQIHN0YXR1cyBjb2RlIGluZm9ybWF0aW9uLlxuICovXG5leHBvcnQgdHlwZSBGZXRjaFJlc3VsdDxUPiA9IFtzdHJpbmcsIG51bGwsIG51bWJlcj9dIHwgW251bGwsIFQsIG51bWJlcl1cblxuLyoqXG4gKiBXcmFwcyBhIHByb21pc2UgdG8gY2F0Y2ggZXJyb3JzIGFuZCByZXR1cm4gYSBSZXN1bHQgdHVwbGUuXG4gKiBUaGlzIGFsbG93cyBmb3IgY2xlYW5lciBlcnJvciBoYW5kbGluZyB3aXRob3V0IHRyeS1jYXRjaCBibG9ja3MuXG4gKlxuICogQHBhcmFtIHByb21pc2UgLSBUaGUgcHJvbWlzZSB0byB3cmFwXG4gKiBAcmV0dXJucyBBIHR1cGxlIG9mIFtlcnJvciwgbnVsbF0gb24gZmFpbHVyZSBvciBbbnVsbCwgZGF0YV0gb24gc3VjY2Vzc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJ5Q2F0Y2g8VCwgRSA9IEVycm9yPihwcm9taXNlOiBQcm9taXNlPFQ+KTogUHJvbWlzZTxSZXN1bHQ8VCwgRT4+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBkYXRhID0gYXdhaXQgcHJvbWlzZVxuICAgIHJldHVybiBbbnVsbCwgZGF0YV1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gW2Vycm9yIGFzIEUsIG51bGxdXG4gIH1cbn1cblxuLyoqXG4gKiBXcmFwcyBzaWduZWRGZXRjaCB3aXRoIGF1dG9tYXRpYyBlcnJvciBoYW5kbGluZyBhbmQgSlNPTiBwYXJzaW5nLlxuICogUmV0dXJucyBhIEZldGNoUmVzdWx0IHR1cGxlIHdpdGggcGFyc2VkIEpTT04gZGF0YSBvciBlcnJvciBtZXNzYWdlIGFuZCBzdGF0dXMgY29kZS5cbiAqXG4gKiBAcGFyYW0gc2lnbmVkRmV0Y2hCb2R5IC0gVGhlIHNpZ25lZEZldGNoIHJlcXVlc3QgY29uZmlndXJhdGlvblxuICogQHJldHVybnMgQSB0dXBsZSBvZiBbZXJyb3IsIG51bGwsIHN0YXR1c0NvZGU/XSBvbiBmYWlsdXJlIG9yIFtudWxsLCBkYXRhLCBzdGF0dXNDb2RlXSBvbiBzdWNjZXNzXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cmFwU2lnbmVkRmV0Y2g8VCA9IHVua25vd24+KHNpZ25lZEZldGNoQm9keTogU2lnbmVkRmV0Y2hSZXF1ZXN0KTogUHJvbWlzZTxGZXRjaFJlc3VsdDxUPj4ge1xuICBjb25zdCBbZXJyb3IsIHJlc3BvbnNlXSA9IGF3YWl0IHRyeUNhdGNoKHNpZ25lZEZldGNoKHNpZ25lZEZldGNoQm9keSkpXG5cbiAgaWYgKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gJHtzaWduZWRGZXRjaEJvZHkudXJsfSBlbmRwb2ludGAsIHsgZXJyb3IgfSlcbiAgICByZXR1cm4gW2Vycm9yLm1lc3NhZ2UsIG51bGwsIHVuZGVmaW5lZF1cbiAgfVxuXG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBgJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gXG4gICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gJHtzaWduZWRGZXRjaEJvZHkudXJsfSBlbmRwb2ludGAsIHsgcmVzcG9uc2UgfSlcbiAgICByZXR1cm4gW2Vycm9yTWVzc2FnZSwgbnVsbCwgcmVzcG9uc2Uuc3RhdHVzXVxuICB9XG5cbiAgbGV0IGJvZHk6IFRcbiAgdHJ5IHtcbiAgICAvLyBKU09OLnBhcnNlIHRocm93cyBzeW5jaHJvbm91c2x5LCBzbyBpdCBjYW4ndCBiZSB3cmFwcGVkIHdpdGggdHJ5Q2F0Y2ggKHRoZVxuICAgIC8vIHRocm93IHdvdWxkIGhhcHBlbiB3aGlsZSBldmFsdWF0aW5nIHRoZSBhcmd1bWVudCwgcmVqZWN0aW5nIHRoaXMgcHJvbWlzZSkuXG4gICAgYm9keSA9IEpTT04ucGFyc2UocmVzcG9uc2UuYm9keSB8fCAne30nKVxuICB9IGNhdGNoIHtcbiAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gcGFyc2UgcmVzcG9uc2UgZnJvbSAke3NpZ25lZEZldGNoQm9keS51cmx9YClcbiAgICByZXR1cm4gWydGYWlsZWQgdG8gcGFyc2UgcmVzcG9uc2UnLCBudWxsLCByZXNwb25zZS5zdGF0dXNdXG4gIH1cblxuICByZXR1cm4gW251bGwsIChib2R5ID8/IHt9KSBhcyBULCByZXNwb25zZS5zdGF0dXNdXG59XG4iXX0=
|