@dcl/sdk 7.26.1-32844959441.commit-a2ccd0b → 7.26.1-32860802198.commit-dae48fb

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