sliftutils 1.7.10 → 1.7.12

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 (84) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/examplestorage/exampleserver.ts +0 -2
  3. package/index.d.ts +301 -54
  4. package/misc/dist/environment.ts.cache +3 -3
  5. package/misc/dist/getSecret.ts.cache +139 -0
  6. package/misc/dist/strings.ts.cache +13 -0
  7. package/misc/dist/zip.ts.cache +9 -0
  8. package/misc/getSecret.ts +38 -16
  9. package/misc/https/cloudflareHelpers.d.ts +19 -0
  10. package/misc/https/cloudflareHelpers.ts +69 -0
  11. package/misc/https/dist/certs.ts.cache +115 -179
  12. package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
  13. package/misc/https/dist/dns.ts.cache +112 -100
  14. package/misc/https/dist/hostServer.ts.cache +130 -0
  15. package/misc/https/dist/httpsCerts.ts.cache +24 -5
  16. package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
  17. package/misc/https/dns.d.ts +41 -12
  18. package/misc/https/dns.ts +104 -101
  19. package/misc/https/hostServer.d.ts +0 -6
  20. package/misc/https/hostServer.ts +9 -5
  21. package/package.json +2 -2
  22. package/render-utils/dist/observer.tsx.cache +3 -2
  23. package/spec.txt +0 -90
  24. package/storage/ArchivesDisk.d.ts +2 -0
  25. package/storage/ArchivesDisk.ts +7 -3
  26. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
  27. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
  28. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
  29. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
  30. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
  31. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
  32. package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
  33. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
  34. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
  35. package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
  36. package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
  37. package/storage/IArchives.d.ts +47 -15
  38. package/storage/IArchives.ts +86 -31
  39. package/storage/backblaze.d.ts +15 -0
  40. package/storage/backblaze.ts +199 -79
  41. package/storage/dist/ArchivesDisk.ts.cache +373 -0
  42. package/storage/dist/FileFolderAPI.tsx.cache +508 -65
  43. package/storage/dist/IArchives.ts.cache +44 -0
  44. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
  45. package/storage/dist/JSONStorage.ts.cache +6 -2
  46. package/storage/dist/PendingManager.tsx.cache +1 -1
  47. package/storage/dist/TransactionStorage.ts.cache +231 -92
  48. package/storage/dist/backblaze.ts.cache +797 -0
  49. package/storage/dist/fileSystemPointer.ts.cache +36 -3
  50. package/storage/dist/remoteFileStorage.ts.cache +495 -0
  51. package/storage/remoteStorage/ArchivesRemote.d.ts +5 -1
  52. package/storage/remoteStorage/ArchivesRemote.ts +28 -8
  53. package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
  54. package/storage/remoteStorage/ArchivesUrl.ts +16 -4
  55. package/storage/remoteStorage/blobStore.d.ts +63 -3
  56. package/storage/remoteStorage/blobStore.ts +419 -101
  57. package/storage/remoteStorage/createArchives.d.ts +31 -10
  58. package/storage/remoteStorage/createArchives.ts +470 -253
  59. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
  60. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
  61. package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
  62. package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
  63. package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
  64. package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
  65. package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
  66. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
  67. package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
  68. package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
  69. package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
  70. package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
  71. package/storage/remoteStorage/remoteConfig.d.ts +8 -0
  72. package/storage/remoteStorage/remoteConfig.ts +105 -5
  73. package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
  74. package/storage/remoteStorage/sourceWrapper.ts +223 -0
  75. package/storage/remoteStorage/spec.md +31 -0
  76. package/storage/remoteStorage/storageController.d.ts +11 -0
  77. package/storage/remoteStorage/storageController.ts +109 -40
  78. package/storage/remoteStorage/storageServer.d.ts +0 -5
  79. package/storage/remoteStorage/storageServer.ts +17 -10
  80. package/storage/remoteStorage/storageServerCli.ts +0 -3
  81. package/storage/remoteStorage/storageServerState.d.ts +7 -1
  82. package/storage/remoteStorage/storageServerState.ts +230 -48
  83. package/testsite/server.ts +0 -2
  84. package/yarn.lock +11 -6
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.streamReaderFromEntries = exports.parseStream = exports.frameDeletes = exports.frameRows = exports.STREAM_EXTENSION = void 0;
7
+ const cbor_x_1 = __importDefault(require("cbor-x"));
8
+ const BulkDatabaseFormat_1 = require("./BulkDatabaseFormat");
9
+ // Tier-0 streaming format: an append log of whole-row writes and deletes (row-format, not columnar),
10
+ // so small mutations are a single cheap append instead of rewriting a columnar file. Each block is:
11
+ //
12
+ // [u32 len][CBOR({ t, v }) or CBOR({ t, d })][u32 len]
13
+ //
14
+ // `t` is a per-write unique timestamp (getTimeUnique); `v` is a set row; `d` is a deleted key. Because
15
+ // every thread streams to its own file, the only way to recover the global mutation order — needed
16
+ // for newest-wins — is a per-write timestamp, with ties broken by file name. The trailing length must
17
+ // match the leading one; a torn/incomplete append leaves a mismatched or missing suffix, so we stop
18
+ // there and report trailing bad bytes instead of throwing. structuredClone preserves typed arrays.
19
+ exports.STREAM_EXTENSION = ".stream";
20
+ const cborEncoder = new cbor_x_1.default.Encoder({ structuredClone: true });
21
+ function frame(payload) {
22
+ let len = Buffer.alloc(4);
23
+ len.writeUInt32LE(payload.length, 0);
24
+ return Buffer.concat([len, payload, len]);
25
+ }
26
+ // Framing only — no batching here. BulkDatabase2 coalesces and flushes these framed bytes on a ramping
27
+ // per-collection schedule (see streamAppend in BulkDatabaseBase), because the browser File System Access
28
+ // API rewrites the whole file on every append, so one-append-per-write is quadratic. The first write
29
+ // after a lull still flushes immediately, so a single action then a tab close is saved at once.
30
+ // Times are assigned by the caller (BulkDatabase2) so the exact same timestamp lands on disk, in the
31
+ // in-memory overlay, and in the cross-tab broadcast — keeping the global write order consistent.
32
+ function frameRows(entries) {
33
+ return Buffer.concat(entries.map(e => frame(Buffer.from(cborEncoder.encode({ t: e.time, v: e.row })))));
34
+ }
35
+ exports.frameRows = frameRows;
36
+ function frameDeletes(entries) {
37
+ return Buffer.concat(entries.map(e => frame(Buffer.from(cborEncoder.encode({ t: e.time, d: e.key })))));
38
+ }
39
+ exports.frameDeletes = frameDeletes;
40
+ function parseStream(buffer) {
41
+ let entries = [];
42
+ let pos = 0;
43
+ while (pos + 4 <= buffer.length) {
44
+ let len = buffer.readUInt32LE(pos);
45
+ let payloadStart = pos + 4;
46
+ let suffixStart = payloadStart + len;
47
+ if (suffixStart + 4 > buffer.length)
48
+ break;
49
+ if (buffer.readUInt32LE(suffixStart) !== len)
50
+ break;
51
+ let decoded;
52
+ try {
53
+ decoded = cborEncoder.decode(buffer.subarray(payloadStart, suffixStart));
54
+ }
55
+ catch (_a) {
56
+ break;
57
+ }
58
+ if (decoded && decoded.d !== undefined)
59
+ entries.push({ time: decoded.t, deletedKey: decoded.d });
60
+ else if (decoded && decoded.v)
61
+ entries.push({ time: decoded.t, row: decoded.v });
62
+ pos = suffixStart + 4;
63
+ }
64
+ return { entries, badBytes: buffer.length - pos };
65
+ }
66
+ exports.parseStream = parseStream;
67
+ // Wraps streamed entries (already ordered oldest-first) as a BaseBulkDatabaseReader. Each set MERGES
68
+ // its fields onto the key's current row (so a partial write/update only changes the columns it
69
+ // includes); a delete tombstones the key (exposed via deletedKeys so the join suppresses it in older
70
+ // bulk readers) and resets the merge. A column the merged row never set reads as ABSENT, so the join
71
+ // falls through to older readers for it. Also returns the latest timestamp seen per key (live or
72
+ // deleted), used for cross-tab conflict resolution.
73
+ function streamReaderFromEntries(entries, totalBytes) {
74
+ let byKey = new Map();
75
+ let deletedKeys = new Set();
76
+ let times = new Map();
77
+ for (let entry of entries) {
78
+ if (entry.deletedKey !== undefined) {
79
+ byKey.delete(entry.deletedKey);
80
+ deletedKeys.add(entry.deletedKey);
81
+ times.set(entry.deletedKey, entry.time);
82
+ }
83
+ else if (entry.row) {
84
+ let key = entry.row.key;
85
+ byKey.set(key, { ...byKey.get(key), ...entry.row });
86
+ deletedKeys.delete(key);
87
+ times.set(key, entry.time);
88
+ }
89
+ }
90
+ let keys = [...byKey.keys()];
91
+ let columnNames = [];
92
+ let seen = new Set();
93
+ for (let row of byKey.values()) {
94
+ for (let field of Object.keys(row)) {
95
+ if (seen.has(field))
96
+ continue;
97
+ seen.add(field);
98
+ columnNames.push(field);
99
+ }
100
+ }
101
+ let columns = columnNames.map(column => ({ column, byteSize: 0 }));
102
+ // Per-key tombstone times for the join's delete resolution.
103
+ let deleteTimes = new Map();
104
+ for (let key of deletedKeys)
105
+ deleteTimes.set(key, times.get(key) || 0);
106
+ // Iterate to find min/max — NOT Math.min(...times)/Math.max(...times): spreading a large array as call
107
+ // arguments overflows the stack ("Maximum call stack size exceeded") once a stream has many keys.
108
+ let minTime = Infinity, maxTime = -Infinity;
109
+ for (let t of times.values()) {
110
+ if (t < minTime)
111
+ minTime = t;
112
+ if (t > maxTime)
113
+ maxTime = t;
114
+ }
115
+ const keyIndexMap = buildKeyIndex(keys);
116
+ let reader = {
117
+ name: "(streams)",
118
+ totalBytes,
119
+ rowCount: keys.length,
120
+ minTime: times.size ? minTime : 0,
121
+ maxTime: times.size ? maxTime : 0,
122
+ keys,
123
+ keyTimes: new Map(keys.map(key => [key, times.get(key) || 0])),
124
+ columns,
125
+ deleteTimes,
126
+ // A key's time is its latest write across all columns (per-key, not per-column). For a column
127
+ // it never set we return ABSENT so the join falls through to an older reader.
128
+ async getColumn(column) {
129
+ return keys.map(key => {
130
+ let row = byKey.get(key);
131
+ return { key, value: row && column in row ? row[column] : BulkDatabaseFormat_1.ABSENT, time: times.get(key) || 0 };
132
+ });
133
+ },
134
+ async getSingleField(key, column) {
135
+ let row = byKey.get(key);
136
+ if (!row || !(column in row))
137
+ return BulkDatabaseFormat_1.ABSENT;
138
+ return { value: row[column], time: times.get(key) || 0 };
139
+ },
140
+ // Stream values are decoded objects (CBOR), so unlike a bulk file we have to encode them to raw
141
+ // cells here. Stream data is small (tier-0, size-capped), so this is cheap. A column the row never
142
+ // set is omitted (ABSENT → fall through); a stored undefined is kept (a real clear).
143
+ async getRawColumn(column) {
144
+ let map = new Map();
145
+ for (let key of keys) {
146
+ let row = byKey.get(key);
147
+ if (!row || !(column in row))
148
+ continue;
149
+ map.set(key, (0, BulkDatabaseFormat_1.encodeValue)(row[column]));
150
+ }
151
+ return map;
152
+ },
153
+ // Per-column index in the same shape a bulk file exposes, materialized in memory once (stream data
154
+ // is tier-0, size-capped, so the encode is cheap). Lets the planned merge treat stream + bulk
155
+ // sources uniformly: it loads each (source, column) index, uses offsets/types to plan the output's
156
+ // byte layout, and reads contiguous runs from this index's in-memory data buffer during execute.
157
+ async getColumnIndex(column) {
158
+ return getStreamColumnIndex(keys, byKey, column);
159
+ },
160
+ rowOfKey(key) {
161
+ return keyIndexMap.get(key);
162
+ },
163
+ };
164
+ return { reader, times };
165
+ }
166
+ exports.streamReaderFromEntries = streamReaderFromEntries;
167
+ // keys[] is the column-side row order for this stream reader; rowOfKey is used by the planner to look up
168
+ // a winning cell's source row without going through a column read. Stays consistent with getColumnIndex,
169
+ // which builds its offsets/types over the same `keys` array in the same order.
170
+ function buildKeyIndex(keys) {
171
+ const m = new Map();
172
+ for (let i = 0; i < keys.length; i++)
173
+ m.set(keys[i], i);
174
+ return m;
175
+ }
176
+ // Build a stream-side ColumnIndex (offsets + types + a contiguous-row byte slicer) over the in-memory
177
+ // merged rows. Encodes each row's value for this column once into a single backing buffer; readValueBytes
178
+ // then slices it. Cached per (reader, column) so a merge planning + execution pass doesn't re-encode.
179
+ function getStreamColumnIndex(keys, byKey, column) {
180
+ var _a;
181
+ let cached = (_a = columnIndexCache.get(byKey)) === null || _a === void 0 ? void 0 : _a.get(column);
182
+ if (cached)
183
+ return cached;
184
+ const offsets = new Uint32Array(keys.length + 1);
185
+ const types = new Uint8Array(keys.length);
186
+ const parts = [];
187
+ let pos = 0;
188
+ for (let i = 0; i < keys.length; i++) {
189
+ const row = byKey.get(keys[i]);
190
+ offsets[i] = pos;
191
+ if (!row || !(column in row)) {
192
+ types[i] = BulkDatabaseFormat_1.TYPE_ABSENT_TAG;
193
+ continue;
194
+ }
195
+ const { type, bytes } = (0, BulkDatabaseFormat_1.encodeValue)(row[column]);
196
+ types[i] = type;
197
+ parts.push(bytes);
198
+ pos += bytes.length;
199
+ }
200
+ offsets[keys.length] = pos;
201
+ const data = parts.length ? Buffer.concat(parts) : BulkDatabaseFormat_1.EMPTY_BUFFER;
202
+ const idx = {
203
+ offsets,
204
+ types,
205
+ async readValueBytes(startRow, endRow) {
206
+ if (endRow <= startRow)
207
+ return BulkDatabaseFormat_1.EMPTY_BUFFER;
208
+ const start = offsets[startRow];
209
+ const end = offsets[endRow];
210
+ if (end <= start)
211
+ return BulkDatabaseFormat_1.EMPTY_BUFFER;
212
+ return data.subarray(start, end);
213
+ },
214
+ };
215
+ let perReader = columnIndexCache.get(byKey);
216
+ if (!perReader) {
217
+ perReader = new Map();
218
+ columnIndexCache.set(byKey, perReader);
219
+ }
220
+ perReader.set(column, idx);
221
+ return idx;
222
+ }
223
+ // Per stream-reader cache of its column indexes. Keyed by the reader's byKey map (a fresh
224
+ // streamReaderFromEntries call produces a fresh map, so this is effectively per-reader).
225
+ const columnIndexCache = new WeakMap();
226
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyZWFtTG9nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3RyZWFtTG9nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLG9EQUEyQjtBQUMzQiw2REFBd0k7QUFFeEkscUdBQXFHO0FBQ3JHLG9HQUFvRztBQUNwRyxFQUFFO0FBQ0YsMkRBQTJEO0FBQzNELEVBQUU7QUFDRix1R0FBdUc7QUFDdkcsbUdBQW1HO0FBQ25HLHNHQUFzRztBQUN0RyxvR0FBb0c7QUFDcEcsbUdBQW1HO0FBRXRGLFFBQUEsZ0JBQWdCLEdBQUcsU0FBUyxDQUFDO0FBRTFDLE1BQU0sV0FBVyxHQUFHLElBQUksZ0JBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztBQUlqRSxTQUFTLEtBQUssQ0FBQyxPQUFlO0lBQzFCLElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUIsR0FBRyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUM5QyxDQUFDO0FBRUQsdUdBQXVHO0FBQ3ZHLHlHQUF5RztBQUN6RyxxR0FBcUc7QUFDckcsZ0dBQWdHO0FBRWhHLHFHQUFxRztBQUNyRyxpR0FBaUc7QUFDakcsU0FBZ0IsU0FBUyxDQUFDLE9BQXlEO0lBQy9FLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FB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RyxHQUFnQjtRQUNyQixPQUFPO1FBQ1AsS0FBSztRQUNMLEtBQUssQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLE1BQU07WUFDakMsSUFBSSxNQUFNLElBQUksUUFBUTtnQkFBRSxPQUFPLGlDQUFZLENBQUM7WUFDNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2hDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM1QixJQUFJLEdBQUcsSUFBSSxLQUFLO2dCQUFFLE9BQU8saUNBQVksQ0FBQztZQUN0QyxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLENBQUM7S0FDSixDQUFDO0lBQ0YsSUFBSSxTQUFTLEdBQUcsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUFDLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztJQUFDLENBQUM7SUFDbEYsU0FBUyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDM0IsT0FBTyxHQUFHLENBQUM7QUFDZixDQUFDO0FBRUQsMEZBQTBGO0FBQzFGLHlGQUF5RjtBQUN6RixNQUFNLGdCQUFnQixHQUFHLElBQUksT0FBTyxFQUFrRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNib3J4IGZyb20gXCJjYm9yLXhcIjtcbmltcG9ydCB7IEFCU0VOVCwgQmFzZUJ1bGtEYXRhYmFzZVJlYWRlciwgQ29sdW1uSW5kZXgsIEVNUFRZX0JVRkZFUiwgZW5jb2RlVmFsdWUsIFJhd0NlbGwsIFRZUEVfQUJTRU5UX1RBRyB9IGZyb20gXCIuL0J1bGtEYXRhYmFzZUZvcm1hdFwiO1xuXG4vLyBUaWVyLTAgc3RyZWFtaW5nIGZvcm1hdDogYW4gYXBwZW5kIGxvZyBvZiB3aG9sZS1yb3cgd3JpdGVzIGFuZCBkZWxldGVzIChyb3ctZm9ybWF0LCBub3QgY29sdW1uYXIpLFxuLy8gc28gc21hbGwgbXV0YXRpb25zIGFyZSBhIHNpbmdsZSBjaGVhcCBhcHBlbmQgaW5zdGVhZCBvZiByZXdyaXRpbmcgYSBjb2x1bW5hciBmaWxlLiBFYWNoIGJsb2NrIGlzOlxuLy9cbi8vICAgW3UzMiBsZW5dW0NCT1IoeyB0LCB2IH0pICBvciAgQ0JPUih7IHQsIGQgfSldW3UzMiBsZW5dXG4vL1xuLy8gYHRgIGlzIGEgcGVyLXdyaXRlIHVuaXF1ZSB0aW1lc3RhbXAgKGdldFRpbWVVbmlxdWUpOyBgdmAgaXMgYSBzZXQgcm93OyBgZGAgaXMgYSBkZWxldGVkIGtleS4gQmVjYXVzZVxuLy8gZXZlcnkgdGhyZWFkIHN0cmVhbXMgdG8gaXRzIG93biBmaWxlLCB0aGUgb25seSB3YXkgdG8gcmVjb3ZlciB0aGUgZ2xvYmFsIG11dGF0aW9uIG9yZGVyIOKAlCBuZWVkZWRcbi8vIGZvciBuZXdlc3Qtd2lucyDigJQgaXMgYSBwZXItd3JpdGUgdGltZXN0YW1wLCB3aXRoIHRpZXMgYnJva2VuIGJ5IGZpbGUgbmFtZS4gVGhlIHRyYWlsaW5nIGxlbmd0aCBtdXN0XG4vLyBtYXRjaCB0aGUgbGVhZGluZyBvbmU7IGEgdG9ybi9pbmNvbXBsZXRlIGFwcGVuZCBsZWF2ZXMgYSBtaXNtYXRjaGVkIG9yIG1pc3Npbmcgc3VmZml4LCBzbyB3ZSBzdG9wXG4vLyB0aGVyZSBhbmQgcmVwb3J0IHRyYWlsaW5nIGJhZCBieXRlcyBpbnN0ZWFkIG9mIHRocm93aW5nLiBzdHJ1Y3R1cmVkQ2xvbmUgcHJlc2VydmVzIHR5cGVkIGFycmF5cy5cblxuZXhwb3J0IGNvbnN0IFNUUkVBTV9FWFRFTlNJT04gPSBcIi5zdHJlYW1cIjtcblxuY29uc3QgY2JvckVuY29kZXIgPSBuZXcgY2JvcnguRW5jb2Rlcih7IHN0cnVjdHVyZWRDbG9uZTogdHJ1ZSB9KTtcblxuZXhwb3J0IHR5cGUgU3RyZWFtRW50cnkgPSB7IHRpbWU6IG51bWJlcjsgcm93PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47IGRlbGV0ZWRLZXk/OiBzdHJpbmcgfTtcblxuZnVuY3Rpb24gZnJhbWUocGF5bG9hZDogQnVmZmVyKTogQnVmZmVyIHtcbiAgICBsZXQgbGVuID0gQnVmZmVyLmFsbG9jKDQpO1xuICAgIGxlbi53cml0ZVVJbnQzMkxFKHBheWxvYWQubGVuZ3RoLCAwKTtcbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChbbGVuLCBwYXlsb2FkLCBsZW5dKTtcbn1cblxuLy8gRnJhbWluZyBvbmx5IOKAlCBubyBiYXRjaGluZyBoZXJlLiBCdWxrRGF0YWJhc2UyIGNvYWxlc2NlcyBhbmQgZmx1c2hlcyB0aGVzZSBmcmFtZWQgYnl0ZXMgb24gYSByYW1waW5nXG4vLyBwZXItY29sbGVjdGlvbiBzY2hlZHVsZSAoc2VlIHN0cmVhbUFwcGVuZCBpbiBCdWxrRGF0YWJhc2VCYXNlKSwgYmVjYXVzZSB0aGUgYnJvd3NlciBGaWxlIFN5c3RlbSBBY2Nlc3Ncbi8vIEFQSSByZXdyaXRlcyB0aGUgd2hvbGUgZmlsZSBvbiBldmVyeSBhcHBlbmQsIHNvIG9uZS1hcHBlbmQtcGVyLXdyaXRlIGlzIHF1YWRyYXRpYy4gVGhlIGZpcnN0IHdyaXRlXG4vLyBhZnRlciBhIGx1bGwgc3RpbGwgZmx1c2hlcyBpbW1lZGlhdGVseSwgc28gYSBzaW5nbGUgYWN0aW9uIHRoZW4gYSB0YWIgY2xvc2UgaXMgc2F2ZWQgYXQgb25jZS5cblxuLy8gVGltZXMgYXJlIGFzc2lnbmVkIGJ5IHRoZSBjYWxsZXIgKEJ1bGtEYXRhYmFzZTIpIHNvIHRoZSBleGFjdCBzYW1lIHRpbWVzdGFtcCBsYW5kcyBvbiBkaXNrLCBpbiB0aGVcbi8vIGluLW1lbW9yeSBvdmVybGF5LCBhbmQgaW4gdGhlIGNyb3NzLXRhYiBicm9hZGNhc3Qg4oCUIGtlZXBpbmcgdGhlIGdsb2JhbCB3cml0ZSBvcmRlciBjb25zaXN0ZW50LlxuZXhwb3J0IGZ1bmN0aW9uIGZyYW1lUm93cyhlbnRyaWVzOiB7IHRpbWU6IG51bWJlcjsgcm93OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9W10pOiBCdWZmZXIge1xuICAgIHJldHVybiBCdWZmZXIuY29uY2F0KGVudHJpZXMubWFwKGUgPT4gZnJhbWUoQnVmZmVyLmZyb20oY2JvckVuY29kZXIuZW5jb2RlKHsgdDogZS50aW1lLCB2OiBlLnJvdyB9KSkpKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmcmFtZURlbGV0ZXMoZW50cmllczogeyB0aW1lOiBudW1iZXI7IGtleTogc3RyaW5nIH1bXSk6IEJ1ZmZlciB7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoZW50cmllcy5tYXAoZSA9PiBmcmFtZShCdWZmZXIuZnJvbShjYm9yRW5jb2Rlci5lbmNvZGUoeyB0OiBlLnRpbWUsIGQ6IGUua2V5IH0pKSkpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlU3RyZWFtKGJ1ZmZlcjogQnVmZmVyKTogeyBlbnRyaWVzOiBTdHJlYW1FbnRyeVtdOyBiYWRCeXRlczogbnVtYmVyIH0ge1xuICAgIGxldCBlbnRyaWVzOiBTdHJlYW1FbnRyeVtdID0gW107XG4gICAgbGV0IHBvcyA9IDA7XG4gICAgd2hpbGUgKHBvcyArIDQgPD0gYnVmZmVyLmxlbmd0aCkge1xuICAgICAgICBsZXQgbGVuID0gYnVmZmVyLnJlYWRVSW50MzJMRShwb3MpO1xuICAgICAgICBsZXQgcGF5bG9hZFN0YXJ0ID0gcG9zICsgNDtcbiAgICAgICAgbGV0IHN1ZmZpeFN0YXJ0ID0gcGF5bG9hZFN0YXJ0ICsgbGVuO1xuICAgICAgICBpZiAoc3VmZml4U3RhcnQgKyA0ID4gYnVmZmVyLmxlbmd0aCkgYnJlYWs7XG4gICAgICAgIGlmIChidWZmZXIucmVhZFVJbnQzMkxFKHN1ZmZpeFN0YXJ0KSAhPT0gbGVuKSBicmVhaztcbiAgICAgICAgbGV0IGRlY29kZWQ6IHsgdDogbnVtYmVyOyB2PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47IGQ/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRlY29kZWQgPSBjYm9yRW5jb2Rlci5kZWNvZGUoYnVmZmVyLnN1YmFycmF5KHBheWxvYWRTdGFydCwgc3VmZml4U3RhcnQpKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVjb2RlZCAmJiBkZWNvZGVkLmQgIT09IHVuZGVmaW5lZCkgZW50cmllcy5wdXNoKHsgdGltZTogZGVjb2RlZC50LCBkZWxldGVkS2V5OiBkZWNvZGVkLmQgfSk7XG4gICAgICAgIGVsc2UgaWYgKGRlY29kZWQgJiYgZGVjb2RlZC52KSBlbnRyaWVzLnB1c2goeyB0aW1lOiBkZWNvZGVkLnQsIHJvdzogZGVjb2RlZC52IH0pO1xuICAgICAgICBwb3MgPSBzdWZmaXhTdGFydCArIDQ7XG4gICAgfVxuICAgIHJldHVybiB7IGVudHJpZXMsIGJhZEJ5dGVzOiBidWZmZXIubGVuZ3RoIC0gcG9zIH07XG59XG5cbi8vIFdyYXBzIHN0cmVhbWVkIGVudHJpZXMgKGFscmVhZHkgb3JkZXJlZCBvbGRlc3QtZmlyc3QpIGFzIGEgQmFzZUJ1bGtEYXRhYmFzZVJlYWRlci4gRWFjaCBzZXQgTUVSR0VTXG4vLyBpdHMgZmllbGRzIG9udG8gdGhlIGtleSdzIGN1cnJlbnQgcm93IChzbyBhIHBhcnRpYWwgd3JpdGUvdXBkYXRlIG9ubHkgY2hhbmdlcyB0aGUgY29sdW1ucyBpdFxuLy8gaW5jbHVkZXMpOyBhIGRlbGV0ZSB0b21ic3RvbmVzIHRoZSBrZXkgKGV4cG9zZWQgdmlhIGRlbGV0ZWRLZXlzIHNvIHRoZSBqb2luIHN1cHByZXNzZXMgaXQgaW4gb2xkZXJcbi8vIGJ1bGsgcmVhZGVycykgYW5kIHJlc2V0cyB0aGUgbWVyZ2UuIEEgY29sdW1uIHRoZSBtZXJnZWQgcm93IG5ldmVyIHNldCByZWFkcyBhcyBBQlNFTlQsIHNvIHRoZSBqb2luXG4vLyBmYWxscyB0aHJvdWdoIHRvIG9sZGVyIHJlYWRlcnMgZm9yIGl0LiBBbHNvIHJldHVybnMgdGhlIGxhdGVzdCB0aW1lc3RhbXAgc2VlbiBwZXIga2V5IChsaXZlIG9yXG4vLyBkZWxldGVkKSwgdXNlZCBmb3IgY3Jvc3MtdGFiIGNvbmZsaWN0IHJlc29sdXRpb24uXG5leHBvcnQgZnVuY3Rpb24gc3RyZWFtUmVhZGVyRnJvbUVudHJpZXMoZW50cmllczogU3RyZWFtRW50cnlbXSwgdG90YWxCeXRlczogbnVtYmVyKTogeyByZWFkZXI6IEJhc2VCdWxrRGF0YWJhc2VSZWFkZXI7IHRpbWVzOiBNYXA8c3RyaW5nLCBudW1iZXI+IH0ge1xuICAgIGxldCBieUtleSA9IG5ldyBNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4oKTtcbiAgICBsZXQgZGVsZXRlZEtleXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBsZXQgdGltZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmRlbGV0ZWRLZXkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgYnlLZXkuZGVsZXRlKGVudHJ5LmRlbGV0ZWRLZXkpO1xuICAgICAgICAgICAgZGVsZXRlZEtleXMuYWRkKGVudHJ5LmRlbGV0ZWRLZXkpO1xuICAgICAgICAgICAgdGltZXMuc2V0KGVudHJ5LmRlbGV0ZWRLZXksIGVudHJ5LnRpbWUpO1xuICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnJvdykge1xuICAgICAgICAgICAgbGV0IGtleSA9IGVudHJ5LnJvdy5rZXkgYXMgc3RyaW5nO1xuICAgICAgICAgICAgYnlLZXkuc2V0KGtleSwgeyAuLi5ieUtleS5nZXQoa2V5KSwgLi4uZW50cnkucm93IH0pO1xuICAgICAgICAgICAgZGVsZXRlZEtleXMuZGVsZXRlKGtleSk7XG4gICAgICAgICAgICB0aW1lcy5zZXQoa2V5LCBlbnRyeS50aW1lKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBsZXQga2V5cyA9IFsuLi5ieUtleS5rZXlzKCldO1xuICAgIGxldCBjb2x1bW5OYW1lczogc3RyaW5nW10gPSBbXTtcbiAgICBsZXQgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGZvciAobGV0IHJvdyBvZiBieUtleS52YWx1ZXMoKSkge1xuICAgICAgICBmb3IgKGxldCBmaWVsZCBvZiBPYmplY3Qua2V5cyhyb3cpKSB7XG4gICAgICAgICAgICBpZiAoc2Vlbi5oYXMoZmllbGQpKSBjb250aW51ZTtcbiAgICAgICAgICAgIHNlZW4uYWRkKGZpZWxkKTtcbiAgICAgICAgICAgIGNvbHVtbk5hbWVzLnB1c2goZmllbGQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCBjb2x1bW5zID0gY29sdW1uTmFtZXMubWFwKGNvbHVtbiA9PiAoeyBjb2x1bW4sIGJ5dGVTaXplOiAwIH0pKTtcbiAgICAvLyBQZXIta2V5IHRvbWJzdG9uZSB0aW1lcyBmb3IgdGhlIGpvaW4ncyBkZWxldGUgcmVzb2x1dGlvbi5cbiAgICBsZXQgZGVsZXRlVGltZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIGZvciAobGV0IGtleSBvZiBkZWxldGVkS2V5cykgZGVsZXRlVGltZXMuc2V0KGtleSwgdGltZXMuZ2V0KGtleSkgfHwgMCk7XG4gICAgLy8gSXRlcmF0ZSB0byBmaW5kIG1pbi9tYXgg4oCUIE5PVCBNYXRoLm1pbiguLi50aW1lcykvTWF0aC5tYXgoLi4udGltZXMpOiBzcHJlYWRpbmcgYSBsYXJnZSBhcnJheSBhcyBjYWxsXG4gICAgLy8gYXJndW1lbnRzIG92ZXJmbG93cyB0aGUgc3RhY2sgKFwiTWF4aW11bSBjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIikgb25jZSBhIHN0cmVhbSBoYXMgbWFueSBrZXlzLlxuICAgIGxldCBtaW5UaW1lID0gSW5maW5pdHksIG1heFRpbWUgPSAtSW5maW5pdHk7XG4gICAgZm9yIChsZXQgdCBvZiB0aW1lcy52YWx1ZXMoKSkge1xuICAgICAgICBpZiAodCA8IG1pblRpbWUpIG1pblRpbWUgPSB0O1xuICAgICAgICBpZiAodCA+IG1heFRpbWUpIG1heFRpbWUgPSB0O1xuICAgIH1cbiAgICBjb25zdCBrZXlJbmRleE1hcCA9IGJ1aWxkS2V5SW5kZXgoa2V5cyk7XG4gICAgbGV0IHJlYWRlcjogQmFzZUJ1bGtEYXRhYmFzZVJlYWRlciA9IHtcbiAgICAgICAgbmFtZTogXCIoc3RyZWFtcylcIixcbiAgICAgICAgdG90YWxCeXRlcyxcbiAgICAgICAgcm93Q291bnQ6IGtleXMubGVuZ3RoLFxuICAgICAgICBtaW5UaW1lOiB0aW1lcy5zaXplID8gbWluVGltZSA6IDAsXG4gICAgICAgIG1heFRpbWU6IHRpbWVzLnNpemUgPyBtYXhUaW1lIDogMCxcbiAgICAgICAga2V5cyxcbiAgICAgICAga2V5VGltZXM6IG5ldyBNYXAoa2V5cy5tYXAoa2V5ID0+IFtrZXksIHRpbWVzLmdldChrZXkpIHx8IDBdKSksXG4gICAgICAgIGNvbHVtbnMsXG4gICAgICAgIGRlbGV0ZVRpbWVzLFxuICAgICAgICAvLyBBIGtleSdzIHRpbWUgaXMgaXRzIGxhdGVzdCB3cml0ZSBhY3Jvc3MgYWxsIGNvbHVtbnMgKHBlci1rZXksIG5vdCBwZXItY29sdW1uKS4gRm9yIGEgY29sdW1uXG4gICAgICAgIC8vIGl0IG5ldmVyIHNldCB3ZSByZXR1cm4gQUJTRU5UIHNvIHRoZSBqb2luIGZhbGxzIHRocm91Z2ggdG8gYW4gb2xkZXIgcmVhZGVyLlxuICAgICAgICBhc3luYyBnZXRDb2x1bW4oY29sdW1uKSB7XG4gICAgICAgICAgICByZXR1cm4ga2V5cy5tYXAoa2V5ID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgcm93ID0gYnlLZXkuZ2V0KGtleSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHsga2V5LCB2YWx1ZTogcm93ICYmIGNvbHVtbiBpbiByb3cgPyByb3dbY29sdW1uXSA6IEFCU0VOVCwgdGltZTogdGltZXMuZ2V0KGtleSkgfHwgMCB9O1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jIGdldFNpbmdsZUZpZWxkKGtleSwgY29sdW1uKSB7XG4gICAgICAgICAgICBsZXQgcm93ID0gYnlLZXkuZ2V0KGtleSk7XG4gICAgICAgICAgICBpZiAoIXJvdyB8fCAhKGNvbHVtbiBpbiByb3cpKSByZXR1cm4gQUJTRU5UO1xuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IHJvd1tjb2x1bW5dLCB0aW1lOiB0aW1lcy5nZXQoa2V5KSB8fCAwIH07XG4gICAgICAgIH0sXG4gICAgICAgIC8vIFN0cmVhbSB2YWx1ZXMgYXJlIGRlY29kZWQgb2JqZWN0cyAoQ0JPUiksIHNvIHVubGlrZSBhIGJ1bGsgZmlsZSB3ZSBoYXZlIHRvIGVuY29kZSB0aGVtIHRvIHJhd1xuICAgICAgICAvLyBjZWxscyBoZXJlLiBTdHJlYW0gZGF0YSBpcyBzbWFsbCAodGllci0wLCBzaXplLWNhcHBlZCksIHNvIHRoaXMgaXMgY2hlYXAuIEEgY29sdW1uIHRoZSByb3cgbmV2ZXJcbiAgICAgICAgLy8gc2V0IGlzIG9taXR0ZWQgKEFCU0VOVCDihpIgZmFsbCB0aHJvdWdoKTsgYSBzdG9yZWQgdW5kZWZpbmVkIGlzIGtlcHQgKGEgcmVhbCBjbGVhcikuXG4gICAgICAgIGFzeW5jIGdldFJhd0NvbHVtbihjb2x1bW4pIHtcbiAgICAgICAgICAgIGxldCBtYXAgPSBuZXcgTWFwPHN0cmluZywgUmF3Q2VsbD4oKTtcbiAgICAgICAgICAgIGZvciAobGV0IGtleSBvZiBrZXlzKSB7XG4gICAgICAgICAgICAgICAgbGV0IHJvdyA9IGJ5S2V5LmdldChrZXkpO1xuICAgICAgICAgICAgICAgIGlmICghcm93IHx8ICEoY29sdW1uIGluIHJvdykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIG1hcC5zZXQoa2V5LCBlbmNvZGVWYWx1ZShyb3dbY29sdW1uXSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG1hcDtcbiAgICAgICAgfSxcbiAgICAgICAgLy8gUGVyLWNvbHVtbiBpbmRleCBpbiB0aGUgc2FtZSBzaGFwZSBhIGJ1bGsgZmlsZSBleHBvc2VzLCBtYXRlcmlhbGl6ZWQgaW4gbWVtb3J5IG9uY2UgKHN0cmVhbSBkYXRhXG4gICAgICAgIC8vIGlzIHRpZXItMCwgc2l6ZS1jYXBwZWQsIHNvIHRoZSBlbmNvZGUgaXMgY2hlYXApLiBMZXRzIHRoZSBwbGFubmVkIG1lcmdlIHRyZWF0IHN0cmVhbSArIGJ1bGtcbiAgICAgICAgLy8gc291cmNlcyB1bmlmb3JtbHk6IGl0IGxvYWRzIGVhY2ggKHNvdXJjZSwgY29sdW1uKSBpbmRleCwgdXNlcyBvZmZzZXRzL3R5cGVzIHRvIHBsYW4gdGhlIG91dHB1dCdzXG4gICAgICAgIC8vIGJ5dGUgbGF5b3V0LCBhbmQgcmVhZHMgY29udGlndW91cyBydW5zIGZyb20gdGhpcyBpbmRleCdzIGluLW1lbW9yeSBkYXRhIGJ1ZmZlciBkdXJpbmcgZXhlY3V0ZS5cbiAgICAgICAgYXN5bmMgZ2V0Q29sdW1uSW5kZXgoY29sdW1uKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0U3RyZWFtQ29sdW1uSW5kZXgoa2V5cywgYnlLZXksIGNvbHVtbik7XG4gICAgICAgIH0sXG4gICAgICAgIHJvd09mS2V5KGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIGtleUluZGV4TWFwLmdldChrZXkpO1xuICAgICAgICB9LFxuICAgIH07XG4gICAgcmV0dXJuIHsgcmVhZGVyLCB0aW1lcyB9O1xufVxuXG4vLyBrZXlzW10gaXMgdGhlIGNvbHVtbi1zaWRlIHJvdyBvcmRlciBmb3IgdGhpcyBzdHJlYW0gcmVhZGVyOyByb3dPZktleSBpcyB1c2VkIGJ5IHRoZSBwbGFubmVyIHRvIGxvb2sgdXBcbi8vIGEgd2lubmluZyBjZWxsJ3Mgc291cmNlIHJvdyB3aXRob3V0IGdvaW5nIHRocm91Z2ggYSBjb2x1bW4gcmVhZC4gU3RheXMgY29uc2lzdGVudCB3aXRoIGdldENvbHVtbkluZGV4LFxuLy8gd2hpY2ggYnVpbGRzIGl0cyBvZmZzZXRzL3R5cGVzIG92ZXIgdGhlIHNhbWUgYGtleXNgIGFycmF5IGluIHRoZSBzYW1lIG9yZGVyLlxuZnVuY3Rpb24gYnVpbGRLZXlJbmRleChrZXlzOiBzdHJpbmdbXSk6IE1hcDxzdHJpbmcsIG51bWJlcj4ge1xuICAgIGNvbnN0IG0gPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykgbS5zZXQoa2V5c1tpXSwgaSk7XG4gICAgcmV0dXJuIG07XG59XG5cbi8vIEJ1aWxkIGEgc3RyZWFtLXNpZGUgQ29sdW1uSW5kZXggKG9mZnNldHMgKyB0eXBlcyArIGEgY29udGlndW91cy1yb3cgYnl0ZSBzbGljZXIpIG92ZXIgdGhlIGluLW1lbW9yeVxuLy8gbWVyZ2VkIHJvd3MuIEVuY29kZXMgZWFjaCByb3cncyB2YWx1ZSBmb3IgdGhpcyBjb2x1bW4gb25jZSBpbnRvIGEgc2luZ2xlIGJhY2tpbmcgYnVmZmVyOyByZWFkVmFsdWVCeXRlc1xuLy8gdGhlbiBzbGljZXMgaXQuIENhY2hlZCBwZXIgKHJlYWRlciwgY29sdW1uKSBzbyBhIG1lcmdlIHBsYW5uaW5nICsgZXhlY3V0aW9uIHBhc3MgZG9lc24ndCByZS1lbmNvZGUuXG5mdW5jdGlvbiBnZXRTdHJlYW1Db2x1bW5JbmRleChrZXlzOiBzdHJpbmdbXSwgYnlLZXk6IE1hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+PiwgY29sdW1uOiBzdHJpbmcpOiBDb2x1bW5JbmRleCB7XG4gICAgbGV0IGNhY2hlZCA9IGNvbHVtbkluZGV4Q2FjaGUuZ2V0KGJ5S2V5KT8uZ2V0KGNvbHVtbik7XG4gICAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcbiAgICBjb25zdCBvZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KGtleXMubGVuZ3RoICsgMSk7XG4gICAgY29uc3QgdHlwZXMgPSBuZXcgVWludDhBcnJheShrZXlzLmxlbmd0aCk7XG4gICAgY29uc3QgcGFydHM6IEJ1ZmZlcltdID0gW107XG4gICAgbGV0IHBvcyA9IDA7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHJvdyA9IGJ5S2V5LmdldChrZXlzW2ldKTtcbiAgICAgICAgb2Zmc2V0c1tpXSA9IHBvcztcbiAgICAgICAgaWYgKCFyb3cgfHwgIShjb2x1bW4gaW4gcm93KSkge1xuICAgICAgICAgICAgdHlwZXNbaV0gPSBUWVBFX0FCU0VOVF9UQUc7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB7IHR5cGUsIGJ5dGVzIH0gPSBlbmNvZGVWYWx1ZShyb3dbY29sdW1uXSk7XG4gICAgICAgIHR5cGVzW2ldID0gdHlwZTtcbiAgICAgICAgcGFydHMucHVzaChieXRlcyk7XG4gICAgICAgIHBvcyArPSBieXRlcy5sZW5ndGg7XG4gICAgfVxuICAgIG9mZnNldHNba2V5cy5sZW5ndGhdID0gcG9zO1xuICAgIGNvbnN0IGRhdGEgPSBwYXJ0cy5sZW5ndGggPyBCdWZmZXIuY29uY2F0KHBhcnRzKSA6IEVNUFRZX0JVRkZFUjtcbiAgICBjb25zdCBpZHg6IENvbHVtbkluZGV4ID0ge1xuICAgICAgICBvZmZzZXRzLFxuICAgICAgICB0eXBlcyxcbiAgICAgICAgYXN5bmMgcmVhZFZhbHVlQnl0ZXMoc3RhcnRSb3csIGVuZFJvdykge1xuICAgICAgICAgICAgaWYgKGVuZFJvdyA8PSBzdGFydFJvdykgcmV0dXJuIEVNUFRZX0JVRkZFUjtcbiAgICAgICAgICAgIGNvbnN0IHN0YXJ0ID0gb2Zmc2V0c1tzdGFydFJvd107XG4gICAgICAgICAgICBjb25zdCBlbmQgPSBvZmZzZXRzW2VuZFJvd107XG4gICAgICAgICAgICBpZiAoZW5kIDw9IHN0YXJ0KSByZXR1cm4gRU1QVFlfQlVGRkVSO1xuICAgICAgICAgICAgcmV0dXJuIGRhdGEuc3ViYXJyYXkoc3RhcnQsIGVuZCk7XG4gICAgICAgIH0sXG4gICAgfTtcbiAgICBsZXQgcGVyUmVhZGVyID0gY29sdW1uSW5kZXhDYWNoZS5nZXQoYnlLZXkpO1xuICAgIGlmICghcGVyUmVhZGVyKSB7IHBlclJlYWRlciA9IG5ldyBNYXAoKTsgY29sdW1uSW5kZXhDYWNoZS5zZXQoYnlLZXksIHBlclJlYWRlcik7IH1cbiAgICBwZXJSZWFkZXIuc2V0KGNvbHVtbiwgaWR4KTtcbiAgICByZXR1cm4gaWR4O1xufVxuXG4vLyBQZXIgc3RyZWFtLXJlYWRlciBjYWNoZSBvZiBpdHMgY29sdW1uIGluZGV4ZXMuIEtleWVkIGJ5IHRoZSByZWFkZXIncyBieUtleSBtYXAgKGEgZnJlc2hcbi8vIHN0cmVhbVJlYWRlckZyb21FbnRyaWVzIGNhbGwgcHJvZHVjZXMgYSBmcmVzaCBtYXAsIHNvIHRoaXMgaXMgZWZmZWN0aXZlbHkgcGVyLXJlYWRlcikuXG5jb25zdCBjb2x1bW5JbmRleENhY2hlID0gbmV3IFdlYWtNYXA8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj4+LCBNYXA8c3RyaW5nLCBDb2x1bW5JbmRleD4+KCk7XG4iXX0=
227
+ /* _JS_SOURCE_HASH = "08eaba4c0c9769af93ebb263b95b81e1794078b5b393f952ec461f32722944e8"; */
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ // Browser-side cross-tab write sync for BulkDatabase2, over BroadcastChannel (one channel per
3
+ // collection, same-origin tabs and workers). It does NOT persist anything — each side writes to disk
4
+ // itself; this just relays live writes to other open tabs/workers and, when one starts up, asks peers
5
+ // for writes they've made recently that may not be on disk yet. No-op in Node / where
6
+ // BroadcastChannel is unavailable, so BulkDatabase2 can call these unconditionally. This is an
7
+ // optional feature, so there is no fallback.
8
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
9
+ //exports.broadcastSeal = exports.broadcast = exports.connect = exports.isSyncSupported = void 0;
10
+ // Writes older than this are assumed already flushed to disk (a freshly-opened tab gets those by
11
+ // reading disk), so a tab only replays writes newer than this when a peer says hello.
12
+ const RECENT_WINDOW_MS = 60000;
13
+ const channels = new Map();
14
+ function isSyncSupported() {
15
+ // window (main-thread browser) or WorkerGlobalScope (Web/Service/Shared worker) — but not Node
16
+ // (typesafecss's isNode is `typeof window === "undefined"`, which misclassifies workers)
17
+ let isBrowserOrWorker = typeof window !== "undefined"
18
+ || "WorkerGlobalScope" in globalThis;
19
+ return isBrowserOrWorker && typeof BroadcastChannel !== "undefined";
20
+ }
21
+ exports.isSyncSupported = isSyncSupported;
22
+ function pruneRecent(channel) {
23
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
24
+ channel.recent = channel.recent.filter(w => w.time >= cutoff);
25
+ }
26
+ function deliver(channel, write) {
27
+ for (const sub of channel.subscribers)
28
+ sub(write);
29
+ }
30
+ function ensure(collection) {
31
+ if (!isSyncSupported())
32
+ return undefined;
33
+ let channel = channels.get(collection);
34
+ if (channel)
35
+ return channel;
36
+ // BroadcastChannel never delivers a message back to the instance that sent it, so a tab never
37
+ // hears its own writes — only the other open tabs do.
38
+ const bc = new BroadcastChannel(`bulkDatabase2:${collection}`);
39
+ const created = { bc, subscribers: [], sealSubscribers: [], recent: [] };
40
+ bc.onmessage = (event) => {
41
+ const msg = event.data;
42
+ if (!msg)
43
+ return;
44
+ if (msg.type === "write" && msg.write) {
45
+ deliver(created, msg.write);
46
+ }
47
+ else if (msg.type === "recent" && msg.writes) {
48
+ for (const write of msg.writes)
49
+ deliver(created, write);
50
+ }
51
+ else if (msg.type === "seal") {
52
+ // A peer is about to fold recent data; stop appending to our current stream file so it
53
+ // becomes complete and the merge can fold it whole. Our next write starts a fresh file.
54
+ for (const sub of created.sealSubscribers)
55
+ sub();
56
+ }
57
+ else if (msg.type === "hello") {
58
+ // Another tab just started; replay our recent writes so it doesn't miss any. The reply goes
59
+ // to every tab, but peers that already have a write ignore it (its timestamp isn't newer
60
+ // than what they hold), so the redundant broadcast is harmless.
61
+ pruneRecent(created);
62
+ if (created.recent.length)
63
+ created.bc.postMessage({ type: "recent", writes: created.recent });
64
+ }
65
+ };
66
+ channels.set(collection, created);
67
+ return created;
68
+ }
69
+ // Subscribe to remote writes for a collection. Recent writes from already-open tabs arrive through the
70
+ // same onWrite callback (as the reply to our hello), so the returned array is always empty — it's kept
71
+ // only for API compatibility with callers that await it.
72
+ function connect(collection, onWrite, onSeal) {
73
+ const channel = ensure(collection);
74
+ if (!channel)
75
+ return Promise.resolve([]);
76
+ channel.subscribers.push(onWrite);
77
+ if (onSeal)
78
+ channel.sealSubscribers.push(onSeal);
79
+ channel.bc.postMessage({ type: "hello" });
80
+ return Promise.resolve([]);
81
+ }
82
+ exports.connect = connect;
83
+ function broadcast(collection, write) {
84
+ const channel = ensure(collection);
85
+ if (!channel)
86
+ return;
87
+ channel.recent.push(write);
88
+ pruneRecent(channel);
89
+ channel.bc.postMessage({ type: "write", write });
90
+ }
91
+ exports.broadcast = broadcast;
92
+ // Ask every other open tab of this collection to seal (stop appending to) its current stream file, so
93
+ // a merge can fold recent data up to the present without racing an append. Best-effort: no-op in Node,
94
+ // and a peer that misses it just keeps appending — worst case the merge folds a prefix and the rest
95
+ // folds later (duplication, resolved by write-time), never data loss.
96
+ function broadcastSeal(collection) {
97
+ const channel = ensure(collection);
98
+ if (!channel)
99
+ return;
100
+ channel.bc.postMessage({ type: "seal" });
101
+ }
102
+ exports.broadcastSeal = broadcastSeal;
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luY0NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInN5bmNDbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDhGQUE4RjtBQUM5RixxR0FBcUc7QUFDckcsc0dBQXNHO0FBQ3RHLHNGQUFzRjtBQUN0RiwrRkFBK0Y7QUFDL0YsNkNBQTZDOzs7QUFJN0MsaUdBQWlHO0FBQ2pHLHNGQUFzRjtBQUN0RixNQUFNLGdCQUFnQixHQUFHLEtBQU0sQ0FBQztBQVdoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztBQUU1QyxTQUFnQixlQUFlO0lBQzNCLCtGQUErRjtJQUMvRix5RkFBeUY7SUFDekYsSUFBSSxpQkFBaUIsR0FBRyxPQUFPLE1BQU0sS0FBSyxXQUFXO1dBQzlDLG1CQUFtQixJQUFJLFVBQVUsQ0FBQztJQUN6QyxPQUFPLGlCQUFpQixJQUFJLE9BQU8sZ0JBQWdCLEtBQUssV0FBVyxDQUFDO0FBQ3hFLENBQUM7QUFORCwwQ0FNQztBQUVELFNBQVMsV0FBVyxDQUFDLE9BQWdCO0lBQ2pDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxnQkFBZ0IsQ0FBQztJQUM3QyxPQUFPLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsU0FBUyxPQUFPLENBQUMsT0FBZ0IsRUFBRSxLQUFrQjtJQUNqRCxLQUFLLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxXQUFXO1FBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFFRCxTQUFTLE1BQU0sQ0FBQyxVQUFrQjtJQUM5QixJQUFJLENBQUMsZUFBZSxFQUFFO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDekMsSUFBSSxPQUFPLEdBQUcsUUFBUSxDQUFDLEdB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QUFPLENBQUMsQ0FBQztJQUNyQixPQUFPLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUNyRCxDQUFDO0FBTkQsOEJBTUM7QUFFRCxzR0FBc0c7QUFDdEcsdUdBQXVHO0FBQ3ZHLG9HQUFvRztBQUNwRyxzRUFBc0U7QUFDdEUsU0FBZ0IsYUFBYSxDQUFDLFVBQWtCO0lBQzVDLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsT0FBTztRQUFFLE9BQU87SUFDckIsT0FBTyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztBQUM3QyxDQUFDO0FBSkQsc0NBSUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBCcm93c2VyLXNpZGUgY3Jvc3MtdGFiIHdyaXRlIHN5bmMgZm9yIEJ1bGtEYXRhYmFzZTIsIG92ZXIgQnJvYWRjYXN0Q2hhbm5lbCAob25lIGNoYW5uZWwgcGVyXG4vLyBjb2xsZWN0aW9uLCBzYW1lLW9yaWdpbiB0YWJzIGFuZCB3b3JrZXJzKS4gSXQgZG9lcyBOT1QgcGVyc2lzdCBhbnl0aGluZyDigJQgZWFjaCBzaWRlIHdyaXRlcyB0byBkaXNrXG4vLyBpdHNlbGY7IHRoaXMganVzdCByZWxheXMgbGl2ZSB3cml0ZXMgdG8gb3RoZXIgb3BlbiB0YWJzL3dvcmtlcnMgYW5kLCB3aGVuIG9uZSBzdGFydHMgdXAsIGFza3MgcGVlcnNcbi8vIGZvciB3cml0ZXMgdGhleSd2ZSBtYWRlIHJlY2VudGx5IHRoYXQgbWF5IG5vdCBiZSBvbiBkaXNrIHlldC4gTm8tb3AgaW4gTm9kZSAvIHdoZXJlXG4vLyBCcm9hZGNhc3RDaGFubmVsIGlzIHVuYXZhaWxhYmxlLCBzbyBCdWxrRGF0YWJhc2UyIGNhbiBjYWxsIHRoZXNlIHVuY29uZGl0aW9uYWxseS4gVGhpcyBpcyBhblxuLy8gb3B0aW9uYWwgZmVhdHVyZSwgc28gdGhlcmUgaXMgbm8gZmFsbGJhY2suXG5cbmV4cG9ydCB0eXBlIFJlbW90ZVdyaXRlID0geyBrZXk6IHN0cmluZzsgdGltZTogbnVtYmVyOyBkZWxldGVkPzogYm9vbGVhbjsgdmFsdWU/OiB1bmtub3duIH07XG5cbi8vIFdyaXRlcyBvbGRlciB0aGFuIHRoaXMgYXJlIGFzc3VtZWQgYWxyZWFkeSBmbHVzaGVkIHRvIGRpc2sgKGEgZnJlc2hseS1vcGVuZWQgdGFiIGdldHMgdGhvc2UgYnlcbi8vIHJlYWRpbmcgZGlzayksIHNvIGEgdGFiIG9ubHkgcmVwbGF5cyB3cml0ZXMgbmV3ZXIgdGhhbiB0aGlzIHdoZW4gYSBwZWVyIHNheXMgaGVsbG8uXG5jb25zdCBSRUNFTlRfV0lORE9XX01TID0gNjBfMDAwO1xuXG50eXBlIENoYW5uZWwgPSB7XG4gICAgYmM6IEJyb2FkY2FzdENoYW5uZWw7XG4gICAgc3Vic2NyaWJlcnM6ICgod3JpdGU6IFJlbW90ZVdyaXRlKSA9PiB2b2lkKVtdO1xuICAgIC8vIENhbGxlZCB3aGVuIGEgcGVlciBhc2tzIGV2ZXJ5b25lIHRvIHNlYWwgKHN0b3AgYXBwZW5kaW5nIHRvKSB0aGVpciBjdXJyZW50IHN0cmVhbSBmaWxlLlxuICAgIHNlYWxTdWJzY3JpYmVyczogKCgpID0+IHZvaWQpW107XG4gICAgLy8gVGhpcyB0YWIncyBvd24gcmVjZW50IHdyaXRlcywga2VwdCBzbyBpdCBjYW4gYW5zd2VyIGFub3RoZXIgdGFiJ3MgXCJoZWxsb1wiLlxuICAgIHJlY2VudDogUmVtb3RlV3JpdGVbXTtcbn07XG5cbmNvbnN0IGNoYW5uZWxzID0gbmV3IE1hcDxzdHJpbmcsIENoYW5uZWw+KCk7XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1N5bmNTdXBwb3J0ZWQoKTogYm9vbGVhbiB7XG4gICAgLy8gd2luZG93IChtYWluLXRocmVhZCBicm93c2VyKSBvciBXb3JrZXJHbG9iYWxTY29wZSAoV2ViL1NlcnZpY2UvU2hhcmVkIHdvcmtlcikg4oCUIGJ1dCBub3QgTm9kZVxuICAgIC8vICh0eXBlc2FmZWNzcydzIGlzTm9kZSBpcyBgdHlwZW9mIHdpbmRvdyA9PT0gXCJ1bmRlZmluZWRcImAsIHdoaWNoIG1pc2NsYXNzaWZpZXMgd29ya2VycylcbiAgICBsZXQgaXNCcm93c2VyT3JXb3JrZXIgPSB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiXG4gICAgICAgIHx8IFwiV29ya2VyR2xvYmFsU2NvcGVcIiBpbiBnbG9iYWxUaGlzO1xuICAgIHJldHVybiBpc0Jyb3dzZXJPcldvcmtlciAmJiB0eXBlb2YgQnJvYWRjYXN0Q2hhbm5lbCAhPT0gXCJ1bmRlZmluZWRcIjtcbn1cblxuZnVuY3Rpb24gcHJ1bmVSZWNlbnQoY2hhbm5lbDogQ2hhbm5lbCkge1xuICAgIGNvbnN0IGN1dG9mZiA9IERhdGUubm93KCkgLSBSRUNFTlRfV0lORE9XX01TO1xuICAgIGNoYW5uZWwucmVjZW50ID0gY2hhbm5lbC5yZWNlbnQuZmlsdGVyKHcgPT4gdy50aW1lID49IGN1dG9mZik7XG59XG5cbmZ1bmN0aW9uIGRlbGl2ZXIoY2hhbm5lbDogQ2hhbm5lbCwgd3JpdGU6IFJlbW90ZVdyaXRlKSB7XG4gICAgZm9yIChjb25zdCBzdWIgb2YgY2hhbm5lbC5zdWJzY3JpYmVycykgc3ViKHdyaXRlKTtcbn1cblxuZnVuY3Rpb24gZW5zdXJlKGNvbGxlY3Rpb246IHN0cmluZyk6IENoYW5uZWwgfCB1bmRlZmluZWQge1xuICAgIGlmICghaXNTeW5jU3VwcG9ydGVkKCkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgbGV0IGNoYW5uZWwgPSBjaGFubmVscy5nZXQoY29sbGVjdGlvbik7XG4gICAgaWYgKGNoYW5uZWwpIHJldHVybiBjaGFubmVsO1xuICAgIC8vIEJyb2FkY2FzdENoYW5uZWwgbmV2ZXIgZGVsaXZlcnMgYSBtZXNzYWdlIGJhY2sgdG8gdGhlIGluc3RhbmNlIHRoYXQgc2VudCBpdCwgc28gYSB0YWIgbmV2ZXJcbiAgICAvLyBoZWFycyBpdHMgb3duIHdyaXRlcyDigJQgb25seSB0aGUgb3RoZXIgb3BlbiB0YWJzIGRvLlxuICAgIGNvbnN0IGJjID0gbmV3IEJyb2FkY2FzdENoYW5uZWwoYGJ1bGtEYXRhYmFzZTI6JHtjb2xsZWN0aW9ufWApO1xuICAgIGNvbnN0IGNyZWF0ZWQ6IENoYW5uZWwgPSB7IGJjLCBzdWJzY3JpYmVyczogW10sIHNlYWxTdWJzY3JpYmVyczogW10sIHJlY2VudDogW10gfTtcbiAgICBiYy5vbm1lc3NhZ2UgPSAoZXZlbnQ6IE1lc3NhZ2VFdmVudCkgPT4ge1xuICAgICAgICBjb25zdCBtc2cgPSBldmVudC5kYXRhIGFzIHsgdHlwZTogc3RyaW5nOyB3cml0ZT86IFJlbW90ZVdyaXRlOyB3cml0ZXM/OiBSZW1vdGVXcml0ZVtdIH07XG4gICAgICAgIGlmICghbXNnKSByZXR1cm47XG4gICAgICAgIGlmIChtc2cudHlwZSA9PT0gXCJ3cml0ZVwiICYmIG1zZy53cml0ZSkge1xuICAgICAgICAgICAgZGVsaXZlcihjcmVhdGVkLCBtc2cud3JpdGUpO1xuICAgICAgICB9IGVsc2UgaWYgKG1zZy50eXBlID09PSBcInJlY2VudFwiICYmIG1zZy53cml0ZXMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3Qgd3JpdGUgb2YgbXNnLndyaXRlcykgZGVsaXZlcihjcmVhdGVkLCB3cml0ZSk7XG4gICAgICAgIH0gZWxzZSBpZiAobXNnLnR5cGUgPT09IFwic2VhbFwiKSB7XG4gICAgICAgICAgICAvLyBBIHBlZXIgaXMgYWJvdXQgdG8gZm9sZCByZWNlbnQgZGF0YTsgc3RvcCBhcHBlbmRpbmcgdG8gb3VyIGN1cnJlbnQgc3RyZWFtIGZpbGUgc28gaXRcbiAgICAgICAgICAgIC8vIGJlY29tZXMgY29tcGxldGUgYW5kIHRoZSBtZXJnZSBjYW4gZm9sZCBpdCB3aG9sZS4gT3VyIG5leHQgd3JpdGUgc3RhcnRzIGEgZnJlc2ggZmlsZS5cbiAgICAgICAgICAgIGZvciAoY29uc3Qgc3ViIG9mIGNyZWF0ZWQuc2VhbFN1YnNjcmliZXJzKSBzdWIoKTtcbiAgICAgICAgfSBlbHNlIGlmIChtc2cudHlwZSA9PT0gXCJoZWxsb1wiKSB7XG4gICAgICAgICAgICAvLyBBbm90aGVyIHRhYiBqdXN0IHN0YXJ0ZWQ7IHJlcGxheSBvdXIgcmVjZW50IHdyaXRlcyBzbyBpdCBkb2Vzbid0IG1pc3MgYW55LiBUaGUgcmVwbHkgZ29lc1xuICAgICAgICAgICAgLy8gdG8gZXZlcnkgdGFiLCBidXQgcGVlcnMgdGhhdCBhbHJlYWR5IGhhdmUgYSB3cml0ZSBpZ25vcmUgaXQgKGl0cyB0aW1lc3RhbXAgaXNuJ3QgbmV3ZXJcbiAgICAgICAgICAgIC8vIHRoYW4gd2hhdCB0aGV5IGhvbGQpLCBzbyB0aGUgcmVkdW5kYW50IGJyb2FkY2FzdCBpcyBoYXJtbGVzcy5cbiAgICAgICAgICAgIHBydW5lUmVjZW50KGNyZWF0ZWQpO1xuICAgICAgICAgICAgaWYgKGNyZWF0ZWQucmVjZW50Lmxlbmd0aCkgY3JlYXRlZC5iYy5wb3N0TWVzc2FnZSh7IHR5cGU6IFwicmVjZW50XCIsIHdyaXRlczogY3JlYXRlZC5yZWNlbnQgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGNoYW5uZWxzLnNldChjb2xsZWN0aW9uLCBjcmVhdGVkKTtcbiAgICByZXR1cm4gY3JlYXRlZDtcbn1cblxuLy8gU3Vic2NyaWJlIHRvIHJlbW90ZSB3cml0ZXMgZm9yIGEgY29sbGVjdGlvbi4gUmVjZW50IHdyaXRlcyBmcm9tIGFscmVhZHktb3BlbiB0YWJzIGFycml2ZSB0aHJvdWdoIHRoZVxuLy8gc2FtZSBvbldyaXRlIGNhbGxiYWNrIChhcyB0aGUgcmVwbHkgdG8gb3VyIGhlbGxvKSwgc28gdGhlIHJldHVybmVkIGFycmF5IGlzIGFsd2F5cyBlbXB0eSDigJQgaXQncyBrZXB0XG4vLyBvbmx5IGZvciBBUEkgY29tcGF0aWJpbGl0eSB3aXRoIGNhbGxlcnMgdGhhdCBhd2FpdCBpdC5cbmV4cG9ydCBmdW5jdGlvbiBjb25uZWN0KGNvbGxlY3Rpb246IHN0cmluZywgb25Xcml0ZTogKHdyaXRlOiBSZW1vdGVXcml0ZSkgPT4gdm9pZCwgb25TZWFsPzogKCkgPT4gdm9pZCk6IFByb21pc2U8UmVtb3RlV3JpdGVbXT4ge1xuICAgIGNvbnN0IGNoYW5uZWwgPSBlbnN1cmUoY29sbGVjdGlvbik7XG4gICAgaWYgKCFjaGFubmVsKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKFtdKTtcbiAgICBjaGFubmVsLnN1YnNjcmliZXJzLnB1c2gob25Xcml0ZSk7XG4gICAgaWYgKG9uU2VhbCkgY2hhbm5lbC5zZWFsU3Vic2NyaWJlcnMucHVzaChvblNlYWwpO1xuICAgIGNoYW5uZWwuYmMucG9zdE1lc3NhZ2UoeyB0eXBlOiBcImhlbGxvXCIgfSk7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShbXSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBicm9hZGNhc3QoY29sbGVjdGlvbjogc3RyaW5nLCB3cml0ZTogUmVtb3RlV3JpdGUpOiB2b2lkIHtcbiAgICBjb25zdCBjaGFubmVsID0gZW5zdXJlKGNvbGxlY3Rpb24pO1xuICAgIGlmICghY2hhbm5lbCkgcmV0dXJuO1xuICAgIGNoYW5uZWwucmVjZW50LnB1c2god3JpdGUpO1xuICAgIHBydW5lUmVjZW50KGNoYW5uZWwpO1xuICAgIGNoYW5uZWwuYmMucG9zdE1lc3NhZ2UoeyB0eXBlOiBcIndyaXRlXCIsIHdyaXRlIH0pO1xufVxuXG4vLyBBc2sgZXZlcnkgb3RoZXIgb3BlbiB0YWIgb2YgdGhpcyBjb2xsZWN0aW9uIHRvIHNlYWwgKHN0b3AgYXBwZW5kaW5nIHRvKSBpdHMgY3VycmVudCBzdHJlYW0gZmlsZSwgc29cbi8vIGEgbWVyZ2UgY2FuIGZvbGQgcmVjZW50IGRhdGEgdXAgdG8gdGhlIHByZXNlbnQgd2l0aG91dCByYWNpbmcgYW4gYXBwZW5kLiBCZXN0LWVmZm9ydDogbm8tb3AgaW4gTm9kZSxcbi8vIGFuZCBhIHBlZXIgdGhhdCBtaXNzZXMgaXQganVzdCBrZWVwcyBhcHBlbmRpbmcg4oCUIHdvcnN0IGNhc2UgdGhlIG1lcmdlIGZvbGRzIGEgcHJlZml4IGFuZCB0aGUgcmVzdFxuLy8gZm9sZHMgbGF0ZXIgKGR1cGxpY2F0aW9uLCByZXNvbHZlZCBieSB3cml0ZS10aW1lKSwgbmV2ZXIgZGF0YSBsb3NzLlxuZXhwb3J0IGZ1bmN0aW9uIGJyb2FkY2FzdFNlYWwoY29sbGVjdGlvbjogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgY2hhbm5lbCA9IGVuc3VyZShjb2xsZWN0aW9uKTtcbiAgICBpZiAoIWNoYW5uZWwpIHJldHVybjtcbiAgICBjaGFubmVsLmJjLnBvc3RNZXNzYWdlKHsgdHlwZTogXCJzZWFsXCIgfSk7XG59XG4iXX0=
104
+ /* _JS_SOURCE_HASH = "b93362d0415ac9f4de1e50ad306197d3fe8c05e347176699d05643c2663e079a"; */
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  export declare const MAX_LAST_MODIFIED_FUTURE: number;
4
+ export declare const IMMUTABLE_CACHE_TIME: number;
4
5
  export declare function assertValidLastModified(lastModified: number): void;
5
6
  export type RemoteConfig = {
6
7
  version?: number;
@@ -19,8 +20,14 @@ export type RemoteConfig = {
19
20
  */
20
21
  export type RemoteConfigBase = string | HostedConfig | BackblazeConfig;
21
22
  export type CommonConfig = {
22
- /** The default options for the first config in a list is DEFAULT_BASE_SYNC_OPTIONS. The rest default to DEFAULT_SYNC_OPTIONS. */
23
- syncOptions?: SyncOptions;
23
+ /** By default a server hosting this bucket eagerly copies this source's full contents onto its own disk (on top of the lazy read-through caching). Set this to be a front end for a very large database without copying the full database - reads still down-cache individual files on demand. */
24
+ noFullSync?: boolean;
25
+ /** Bytes of read-cache this server's disk may hold; least-recently-used files are deleted from disk to stay under it (only ever when another source verifiably holds the file - the only copy is never deleted). Requires noFullSync (a full copy can't be bounded). */
26
+ readerDiskLimit?: number;
27
+ /** The write times ([startMs, endMs]) this source is valid for (see ArchivesSource.validWindow for the synchronization semantics). Required on object configs: configuration changes must be SCHEDULED (a new source becomes valid at a future time while the old one's window ends), not flipped instantly. Plain URL-string sources default to FULL_VALID_WINDOW - once you're writing object configs, you're doing something complicated enough to think about when things change. */
28
+ validWindow: [number, number];
29
+ /** Sharding: the fraction of the key space this source handles, as [start, end) over [0, 1) (keys are routed by getRoute in remoteConfig.ts). Defaults to FULL_ROUTE (unsharded). At every point in time the sources' routes must fully cover [0, 1), or some keys could never be read. */
30
+ route?: [number, number];
24
31
  };
25
32
  export type HostedConfig = CommonConfig & {
26
33
  type: "remote";
@@ -35,34 +42,56 @@ export type HostedConfig = CommonConfig & {
35
42
  export type BackblazeConfig = CommonConfig & {
36
43
  type: "backblaze";
37
44
  url: string;
38
- bucketName: string;
39
45
  public?: boolean;
40
46
  immutable?: boolean;
41
47
  };
42
- export declare const DEFAULT_BASE_SYNC_OPTIONS: SyncOptions;
43
- export declare const DEFAULT_SYNC_OPTIONS: SyncOptions;
48
+ export declare const FULL_VALID_WINDOW: [number, number];
44
49
  export type ArchiveFileInfo = {
45
50
  path: string;
46
51
  createTime: number;
47
52
  size: number;
48
53
  };
54
+ export type SyncActivity = {
55
+ type: "metadataScan" | "fullSync";
56
+ sourceDebugName: string;
57
+ startTime: number;
58
+ doneFiles?: number;
59
+ totalFiles?: number;
60
+ doneBytes?: number;
61
+ totalBytes?: number;
62
+ };
49
63
  export type ArchivesConfig = {
50
64
  supportsChangesAfter?: boolean;
51
- };
52
- export type SyncOptions = {
53
- copyFiles?: boolean;
54
- noWriteBack?: boolean;
55
- cacheReads?: boolean;
56
- validWindow: [number, number];
57
- required?: boolean;
65
+ remoteConfig?: RemoteConfig;
66
+ index?: {
67
+ fileCount: number;
68
+ byteCount: number;
69
+ };
70
+ indexSources?: {
71
+ debugName: string;
72
+ fileCount: number;
73
+ byteCount: number;
74
+ }[];
75
+ readerDiskLimit?: number;
76
+ syncing?: SyncActivity[];
58
77
  };
59
78
  export type ArchivesSource = {
60
79
  source: IArchives;
61
- options: SyncOptions;
80
+ validWindow: [number, number];
81
+ route?: [number, number];
82
+ noFullSync?: boolean;
62
83
  };
84
+ export declare const WRITE_PAST_WINDOW_GRACE: number;
85
+ export declare const STORAGE_WRONG_VALID_WINDOW = "REMOTE_STORAGE_WRONG_VALID_WINDOW_a7c1f04e";
86
+ export declare const STORAGE_WRONG_ROUTE = "REMOTE_STORAGE_WRONG_ROUTE_c94d2e17";
87
+ export declare const FULL_ROUTE: [number, number];
88
+ export declare const VARIABLE_SHARD = "VARIABLE_SHARD_f0234jfah08fgyhfgyssdds83nmp";
89
+ export declare function windowAcceptsWrites(validWindow: [number, number] | undefined): boolean;
63
90
  export type ArchivesSyncSourceStatus = {
64
91
  debugName: string;
65
- options: SyncOptions;
92
+ validWindow: [number, number];
93
+ route?: [number, number];
94
+ noFullSync?: boolean;
66
95
  supportsChangesAfter: boolean;
67
96
  initialScanComplete: boolean;
68
97
  scannedCount: number;
@@ -74,13 +103,15 @@ export type ArchivesSyncStatus = {
74
103
  };
75
104
  export interface IArchives {
76
105
  getDebugName(): string;
106
+ /** Whether writes would be accepted (credentials exist, the account trusts this machine, etc).
107
+ * Checked without writing anything. */
108
+ hasWriteAccess(): Promise<boolean>;
77
109
  get(fileName: string, config?: {
78
110
  range?: {
79
111
  start: number;
80
112
  end: number;
81
113
  };
82
114
  }): Promise<Buffer | undefined>;
83
- /** Like get, but also returns the last-write time of the file. get just calls get2. */
84
115
  get2(fileName: string, config?: {
85
116
  range?: {
86
117
  start: number;
@@ -89,6 +120,7 @@ export interface IArchives {
89
120
  }): Promise<{
90
121
  data: Buffer;
91
122
  writeTime: number;
123
+ size: number;
92
124
  } | undefined>;
93
125
  /**
94
126
  * lastModified stamps the write with that last-write time instead of now. If it is OLDER than