@saltcorn/admin-models 1.7.0-alpha.0 → 1.7.0-beta.0

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 (69) hide show
  1. package/cjs/models/backup-retention.cjs +18 -0
  2. package/cjs/models/file-globs.cjs +18 -0
  3. package/cjs/models/zip-extract.cjs +18 -0
  4. package/cjs/models/zip-format.cjs +18 -0
  5. package/cjs/models/zip-worker.cjs +18 -0
  6. package/cjs/models/zip-writer.cjs +18 -0
  7. package/cjs/models/zip.cjs +18 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/models/backup-retention.d.ts +57 -0
  11. package/dist/models/backup-retention.d.ts.map +1 -0
  12. package/dist/models/backup-retention.js +108 -0
  13. package/dist/models/backup-retention.js.map +1 -0
  14. package/dist/models/backup.d.ts +4 -1
  15. package/dist/models/backup.d.ts.map +1 -1
  16. package/dist/models/backup.js +364 -302
  17. package/dist/models/backup.js.map +1 -1
  18. package/dist/models/file-globs.d.ts +34 -0
  19. package/dist/models/file-globs.d.ts.map +1 -0
  20. package/dist/models/file-globs.js +47 -0
  21. package/dist/models/file-globs.js.map +1 -0
  22. package/dist/models/pack.d.ts +1 -1
  23. package/dist/models/pack.d.ts.map +1 -1
  24. package/dist/models/pack.js +26 -1
  25. package/dist/models/pack.js.map +1 -1
  26. package/dist/models/tenant.d.ts.map +1 -1
  27. package/dist/models/tenant.js +2 -0
  28. package/dist/models/tenant.js.map +1 -1
  29. package/dist/models/zip-extract.d.ts +14 -0
  30. package/dist/models/zip-extract.d.ts.map +1 -0
  31. package/dist/models/zip-extract.js +110 -0
  32. package/dist/models/zip-extract.js.map +1 -0
  33. package/dist/models/zip-format.d.ts +57 -0
  34. package/dist/models/zip-format.d.ts.map +1 -0
  35. package/dist/models/zip-format.js +106 -0
  36. package/dist/models/zip-format.js.map +1 -0
  37. package/dist/models/zip-worker.d.ts +2 -0
  38. package/dist/models/zip-worker.d.ts.map +1 -0
  39. package/dist/models/zip-worker.js +177 -0
  40. package/dist/models/zip-worker.js.map +1 -0
  41. package/dist/models/zip-writer.d.ts +75 -0
  42. package/dist/models/zip-writer.d.ts.map +1 -0
  43. package/dist/models/zip-writer.js +321 -0
  44. package/dist/models/zip-writer.js.map +1 -0
  45. package/dist/models/zip.d.ts +101 -0
  46. package/dist/models/zip.d.ts.map +1 -0
  47. package/dist/models/zip.js +211 -0
  48. package/dist/models/zip.js.map +1 -0
  49. package/dist/tests/backup-retention.test.d.ts +2 -0
  50. package/dist/tests/backup-retention.test.d.ts.map +1 -0
  51. package/dist/tests/backup-retention.test.js +134 -0
  52. package/dist/tests/backup-retention.test.js.map +1 -0
  53. package/dist/tests/backup.test.js +186 -2
  54. package/dist/tests/backup.test.js.map +1 -1
  55. package/dist/tests/file-globs.test.d.ts +2 -0
  56. package/dist/tests/file-globs.test.d.ts.map +1 -0
  57. package/dist/tests/file-globs.test.js +66 -0
  58. package/dist/tests/file-globs.test.js.map +1 -0
  59. package/dist/tests/pack.test.js +14 -3
  60. package/dist/tests/pack.test.js.map +1 -1
  61. package/dist/tests/random.test.js +3 -3
  62. package/dist/tests/random.test.js.map +1 -1
  63. package/dist/tests/tenant.test.js +7 -7
  64. package/dist/tests/tenant.test.js.map +1 -1
  65. package/dist/tests/zip.test.d.ts +2 -0
  66. package/dist/tests/zip.test.d.ts.map +1 -0
  67. package/dist/tests/zip.test.js +319 -0
  68. package/dist/tests/zip.test.js.map +1 -0
  69. package/package.json +15 -9
@@ -0,0 +1,321 @@
1
+ /**
2
+ * A streaming ZIP writer.
3
+ *
4
+ * Entries are compressed and written out as they are added, so the archive is
5
+ * never held in memory: a backup of a 50 GB file store needs no more memory
6
+ * than a few buffers, whatever its size. Deflation runs on libuv's thread
7
+ * pool (zlib's streaming API), and the whole writer is driven from the zip
8
+ * worker thread, so nothing here competes with the server's event loop.
9
+ *
10
+ * Sizes and CRCs are not known until an entry has been written, so entries
11
+ * carry a data descriptor (general purpose bit 3) instead. Entries larger
12
+ * than ZIP64_THRESHOLD are written in zip64 format, which lifts the 4 GiB
13
+ * limit on entry and archive size.
14
+ *
15
+ * @category saltcorn-admin-models
16
+ * @module models/zip-writer
17
+ */
18
+ import { createDeflateRaw } from "zlib";
19
+ import { createReadStream } from "fs";
20
+ import { stat } from "fs/promises";
21
+ import { randomBytes } from "crypto";
22
+ import { Readable } from "stream";
23
+ import { once } from "events";
24
+ import { CENTRAL_HEADER_SIZE, CENTRAL_SIG, DESCRIPTOR_SIG, EOCD_SIG, EOCD_SIZE, FLAG_DESCRIPTOR, FLAG_ENCRYPTED, FLAG_UTF8, LOCAL_HEADER_SIZE, LOCAL_SIG, METHOD_DEFLATED, METHOD_STORED, UINT16_MAX, UINT32_MAX, ZIP64_EOCD_SIG, ZIP64_EOCD_SIZE, ZIP64_EXTRA_ID, ZIP64_LOCATOR_SIG, ZIP64_LOCATOR_SIZE, ZIP64_THRESHOLD, ZipCrypto, crc32, dosDateTime, writeUInt64, } from "./zip-format.js";
25
+ export class ZipStreamWriter {
26
+ constructor(out, options = {}) {
27
+ this.offset = 0;
28
+ this.entries = [];
29
+ this.names = new Set();
30
+ this.out = out;
31
+ this.password = options.password || undefined;
32
+ this.level = options.level ?? 5;
33
+ this.zip64Threshold = options.zip64Threshold ?? ZIP64_THRESHOLD;
34
+ this.probeLimit = options.probeLimit ?? 32 * 1024 * 1024;
35
+ }
36
+ /** Write to the output, respecting its backpressure */
37
+ async put(buf) {
38
+ if (!this.out.write(buf))
39
+ await once(this.out, "drain");
40
+ this.offset += buf.length;
41
+ }
42
+ /**
43
+ * Zip entry names are always forward-slash separated and never absolute.
44
+ * A duplicate name would make the archive ambiguous, so it is an error.
45
+ */
46
+ entryName(name, isDirectory) {
47
+ let clean = name.replace(/\\/g, "/").replace(/^\/+/, "");
48
+ if (isDirectory && !clean.endsWith("/"))
49
+ clean += "/";
50
+ if (this.names.has(clean))
51
+ throw new Error(`Duplicate zip entry: ${clean}`);
52
+ this.names.add(clean);
53
+ return Buffer.from(clean, "utf8");
54
+ }
55
+ /**
56
+ * The local file header. When an entry is zip64 the header carries a
57
+ * zip64 extra field with placeholder sizes, which is what tells a reader
58
+ * that the trailing data descriptor has 8-byte sizes.
59
+ */
60
+ localHeader(entry) {
61
+ const extraSize = entry.zip64 ? 20 : 0;
62
+ const buf = Buffer.alloc(LOCAL_HEADER_SIZE + entry.name.length + extraSize);
63
+ buf.writeUInt32LE(LOCAL_SIG, 0);
64
+ buf.writeUInt16LE(entry.zip64 ? 45 : 20, 4);
65
+ buf.writeUInt16LE(entry.flags, 6);
66
+ buf.writeUInt16LE(entry.method, 8);
67
+ buf.writeUInt16LE(entry.time, 10);
68
+ buf.writeUInt16LE(entry.date, 12);
69
+ // crc and sizes follow in the data descriptor, except for entries
70
+ // written whole (directories), which have nothing to describe
71
+ buf.writeUInt32LE(entry.crc, 14);
72
+ buf.writeUInt32LE(entry.zip64 ? UINT32_MAX : entry.compressedSize, 18);
73
+ buf.writeUInt32LE(entry.zip64 ? UINT32_MAX : entry.uncompressedSize, 22);
74
+ buf.writeUInt16LE(entry.name.length, 26);
75
+ buf.writeUInt16LE(extraSize, 28);
76
+ entry.name.copy(buf, LOCAL_HEADER_SIZE);
77
+ if (entry.zip64) {
78
+ const at = LOCAL_HEADER_SIZE + entry.name.length;
79
+ buf.writeUInt16LE(ZIP64_EXTRA_ID, at);
80
+ buf.writeUInt16LE(16, at + 2);
81
+ writeUInt64(buf, entry.uncompressedSize, at + 4);
82
+ writeUInt64(buf, entry.compressedSize, at + 12);
83
+ }
84
+ return buf;
85
+ }
86
+ /** The data descriptor written after an entry's data */
87
+ dataDescriptor(entry) {
88
+ const buf = Buffer.alloc(entry.zip64 ? 24 : 16);
89
+ buf.writeUInt32LE(DESCRIPTOR_SIG, 0);
90
+ buf.writeUInt32LE(entry.crc, 4);
91
+ if (entry.zip64) {
92
+ writeUInt64(buf, entry.compressedSize, 8);
93
+ writeUInt64(buf, entry.uncompressedSize, 16);
94
+ }
95
+ else {
96
+ buf.writeUInt32LE(entry.compressedSize, 8);
97
+ buf.writeUInt32LE(entry.uncompressedSize, 12);
98
+ }
99
+ return buf;
100
+ }
101
+ /**
102
+ * Add an entry whose contents come from a stream.
103
+ *
104
+ * Whether an entry is zip64 has to be settled before any of its data is
105
+ * written, so a source of unknown length is read ahead of up to
106
+ * `probeLimit` bytes to find out which it is.
107
+ *
108
+ * @param options.sizeHint how large the source is known to be, if it is
109
+ */
110
+ async addStream(name, source, options = {}) {
111
+ const iterator = source[Symbol.asyncIterator]();
112
+ const probed = [];
113
+ let zip64;
114
+ if (options.sizeHint !== undefined)
115
+ zip64 = options.sizeHint >= this.zip64Threshold;
116
+ else {
117
+ let seen = 0;
118
+ let ended = false;
119
+ while (seen <= this.probeLimit) {
120
+ const next = await iterator.next();
121
+ if (next.done) {
122
+ ended = true;
123
+ break;
124
+ }
125
+ probed.push(next.value);
126
+ seen += next.value.length;
127
+ }
128
+ zip64 = !ended || seen >= this.zip64Threshold;
129
+ }
130
+ const { time, date } = dosDateTime(options.mtime ?? new Date());
131
+ const entry = {
132
+ name: this.entryName(name, false),
133
+ flags: FLAG_DESCRIPTOR | FLAG_UTF8 | (this.password ? FLAG_ENCRYPTED : 0),
134
+ method: METHOD_DEFLATED,
135
+ time,
136
+ date,
137
+ crc: 0,
138
+ compressedSize: 0,
139
+ uncompressedSize: 0,
140
+ offset: this.offset,
141
+ mode: options.mode ?? 0o644,
142
+ isDirectory: false,
143
+ zip64,
144
+ };
145
+ await this.put(this.localHeader(entry));
146
+ const crypto = this.password ? new ZipCrypto(this.password) : null;
147
+ if (crypto) {
148
+ // the 12 byte encryption header. Its last byte is a check byte the
149
+ // reader compares against - the high byte of the modification time,
150
+ // because with a data descriptor the CRC is not known yet
151
+ const salt = randomBytes(12);
152
+ salt[11] = (time >>> 8) & 0xff;
153
+ await this.put(crypto.encrypt(salt));
154
+ entry.compressedSize += 12;
155
+ }
156
+ const deflate = createDeflateRaw({ level: this.level });
157
+ let feedError;
158
+ const feed = (async () => {
159
+ const consume = async (buf) => {
160
+ entry.crc = crc32(buf, entry.crc);
161
+ entry.uncompressedSize += buf.length;
162
+ if (!deflate.write(buf))
163
+ await once(deflate, "drain");
164
+ };
165
+ // whatever the format probe already read, then the rest of the source
166
+ for (const buf of probed)
167
+ await consume(buf);
168
+ while (true) {
169
+ const next = await iterator.next();
170
+ if (next.done)
171
+ break;
172
+ await consume(next.value);
173
+ }
174
+ deflate.end();
175
+ })().catch((e) => {
176
+ feedError = e;
177
+ // unblock the consumer below, which would otherwise wait for an end
178
+ // that is never coming
179
+ deflate.destroy(e);
180
+ });
181
+ try {
182
+ for await (const chunk of deflate) {
183
+ const data = crypto
184
+ ? crypto.encrypt(chunk)
185
+ : chunk;
186
+ entry.compressedSize += data.length;
187
+ await this.put(data);
188
+ }
189
+ }
190
+ finally {
191
+ await feed;
192
+ }
193
+ if (feedError)
194
+ throw feedError;
195
+ if (!entry.zip64 &&
196
+ (entry.compressedSize > UINT32_MAX || entry.uncompressedSize > UINT32_MAX))
197
+ throw new Error(`Zip entry ${name} grew past 4GB while it was being written`);
198
+ await this.put(this.dataDescriptor(entry));
199
+ this.entries.push(entry);
200
+ }
201
+ /** Add an entry from content held in memory */
202
+ async addBuffer(name, data, options = {}) {
203
+ await this.addStream(name, Readable.from([data]), {
204
+ ...options,
205
+ sizeHint: data.length,
206
+ });
207
+ }
208
+ /** Add an entry read from a file on disk. The file is streamed. */
209
+ async addFile(name, localPath) {
210
+ const stats = await stat(localPath);
211
+ await this.addStream(name, createReadStream(localPath), {
212
+ sizeHint: stats.size,
213
+ mode: stats.mode & 0o7777,
214
+ mtime: stats.mtime,
215
+ });
216
+ }
217
+ /** Add a directory entry */
218
+ async addDirectory(name, options = {}) {
219
+ const { time, date } = dosDateTime(options.mtime ?? new Date());
220
+ const entry = {
221
+ name: this.entryName(name, true),
222
+ flags: FLAG_UTF8,
223
+ method: METHOD_STORED,
224
+ time,
225
+ date,
226
+ crc: 0,
227
+ compressedSize: 0,
228
+ uncompressedSize: 0,
229
+ offset: this.offset,
230
+ mode: options.mode ?? 0o755,
231
+ isDirectory: true,
232
+ zip64: false,
233
+ };
234
+ await this.put(this.localHeader(entry));
235
+ this.entries.push(entry);
236
+ }
237
+ /** The central directory record of one entry */
238
+ centralHeader(entry) {
239
+ // only the values that do not fit go into the zip64 extra field, in the
240
+ // order the format prescribes
241
+ const zip64Fields = [];
242
+ if (entry.uncompressedSize > UINT32_MAX)
243
+ zip64Fields.push(entry.uncompressedSize);
244
+ if (entry.compressedSize > UINT32_MAX)
245
+ zip64Fields.push(entry.compressedSize);
246
+ if (entry.offset > UINT32_MAX)
247
+ zip64Fields.push(entry.offset);
248
+ const extraSize = zip64Fields.length ? 4 + zip64Fields.length * 8 : 0;
249
+ const buf = Buffer.alloc(CENTRAL_HEADER_SIZE + entry.name.length + extraSize);
250
+ buf.writeUInt32LE(CENTRAL_SIG, 0);
251
+ buf.writeUInt16LE((3 << 8) | 45, 4); // made by unix
252
+ buf.writeUInt16LE(extraSize ? 45 : 20, 6);
253
+ buf.writeUInt16LE(entry.flags, 8);
254
+ buf.writeUInt16LE(entry.method, 10);
255
+ buf.writeUInt16LE(entry.time, 12);
256
+ buf.writeUInt16LE(entry.date, 14);
257
+ buf.writeUInt32LE(entry.crc, 16);
258
+ buf.writeUInt32LE(Math.min(entry.compressedSize, UINT32_MAX), 20);
259
+ buf.writeUInt32LE(Math.min(entry.uncompressedSize, UINT32_MAX), 24);
260
+ buf.writeUInt16LE(entry.name.length, 28);
261
+ buf.writeUInt16LE(extraSize, 30);
262
+ buf.writeUInt16LE(0, 32); // comment length
263
+ buf.writeUInt16LE(0, 34); // disk number
264
+ buf.writeUInt16LE(0, 36); // internal attributes
265
+ buf.writeUInt32LE(((entry.mode & 0xffff) << 16) | (entry.isDirectory ? 0x10 : 0), 38);
266
+ buf.writeUInt32LE(Math.min(entry.offset, UINT32_MAX), 42);
267
+ entry.name.copy(buf, CENTRAL_HEADER_SIZE);
268
+ if (extraSize) {
269
+ const at = CENTRAL_HEADER_SIZE + entry.name.length;
270
+ buf.writeUInt16LE(ZIP64_EXTRA_ID, at);
271
+ buf.writeUInt16LE(extraSize - 4, at + 2);
272
+ zip64Fields.forEach((v, i) => writeUInt64(buf, v, at + 4 + i * 8));
273
+ }
274
+ return buf;
275
+ }
276
+ /**
277
+ * Write the central directory and the end of central directory records.
278
+ * The writer cannot be used afterwards.
279
+ */
280
+ async finalize() {
281
+ const centralStart = this.offset;
282
+ for (const entry of this.entries)
283
+ await this.put(this.centralHeader(entry));
284
+ const centralSize = this.offset - centralStart;
285
+ const needsZip64 = this.entries.length > UINT16_MAX ||
286
+ centralStart > UINT32_MAX ||
287
+ centralSize > UINT32_MAX;
288
+ if (needsZip64) {
289
+ const zip64Eocd = Buffer.alloc(ZIP64_EOCD_SIZE);
290
+ zip64Eocd.writeUInt32LE(ZIP64_EOCD_SIG, 0);
291
+ writeUInt64(zip64Eocd, ZIP64_EOCD_SIZE - 12, 4);
292
+ zip64Eocd.writeUInt16LE((3 << 8) | 45, 12);
293
+ zip64Eocd.writeUInt16LE(45, 14);
294
+ zip64Eocd.writeUInt32LE(0, 16); // this disk
295
+ zip64Eocd.writeUInt32LE(0, 20); // disk with central directory
296
+ writeUInt64(zip64Eocd, this.entries.length, 24);
297
+ writeUInt64(zip64Eocd, this.entries.length, 32);
298
+ writeUInt64(zip64Eocd, centralSize, 40);
299
+ writeUInt64(zip64Eocd, centralStart, 48);
300
+ const eocdOffset = this.offset;
301
+ await this.put(zip64Eocd);
302
+ const locator = Buffer.alloc(ZIP64_LOCATOR_SIZE);
303
+ locator.writeUInt32LE(ZIP64_LOCATOR_SIG, 0);
304
+ locator.writeUInt32LE(0, 4);
305
+ writeUInt64(locator, eocdOffset, 8);
306
+ locator.writeUInt32LE(1, 16);
307
+ await this.put(locator);
308
+ }
309
+ const eocd = Buffer.alloc(EOCD_SIZE);
310
+ eocd.writeUInt32LE(EOCD_SIG, 0);
311
+ eocd.writeUInt16LE(0, 4);
312
+ eocd.writeUInt16LE(0, 6);
313
+ eocd.writeUInt16LE(Math.min(this.entries.length, UINT16_MAX), 8);
314
+ eocd.writeUInt16LE(Math.min(this.entries.length, UINT16_MAX), 10);
315
+ eocd.writeUInt32LE(Math.min(centralSize, UINT32_MAX), 12);
316
+ eocd.writeUInt32LE(Math.min(centralStart, UINT32_MAX), 16);
317
+ eocd.writeUInt16LE(0, 20); // comment length
318
+ await this.put(eocd);
319
+ }
320
+ }
321
+ //# sourceMappingURL=zip-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-writer.js","sourceRoot":"","sources":["../../models/zip-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,IAAI,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAY,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,SAAS,EACT,eAAe,EACf,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,EACV,UAAU,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,KAAK,EACL,WAAW,EACX,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAgCzB,MAAM,OAAO,eAAe;IAU1B,YAAY,GAAa,EAAE,UAA4B,EAAE;QAJjD,WAAM,GAAW,CAAC,CAAC;QACnB,YAAO,GAAmB,EAAE,CAAC;QAC7B,UAAK,GAAgB,IAAI,GAAG,EAAE,CAAC;QAGrC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC;QAC9C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,eAAe,CAAC;QAChE,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3D,CAAC;IAED,uDAAuD;IAC/C,KAAK,CAAC,GAAG,CAAC,GAAW;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACK,SAAS,CAAC,IAAY,EAAE,WAAoB;QAClD,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,WAAW,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,KAAK,IAAI,GAAG,CAAC;QACtD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,KAAmB;QACrC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;QAC5E,GAAG,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAChC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5C,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACnC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClC,kEAAkE;QAClE,8DAA8D;QAC9D,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACjC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACvE,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;QACzE,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzC,GAAG,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,EAAE,GAAG,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YACjD,GAAG,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YAC9B,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACjD,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,wDAAwD;IAChD,cAAc,CAAC,KAAmB;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChD,GAAG,CAAC,aAAa,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QACrC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;YAC1C,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,MAAgB,EAChB,UAA8D,EAAE;QAEhE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAc,CAAC;QACnB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;YAChC,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,CAAC;aAC7C,CAAC;YACJ,IAAI,IAAI,GAAG,CAAC,CAAC;YACb,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,OAAO,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,KAAK,GAAG,IAAI,CAAC;oBACb,MAAM;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;gBAClC,IAAI,IAAK,IAAI,CAAC,KAAgB,CAAC,MAAM,CAAC;YACxC,CAAC;YACD,KAAK,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,cAAc,CAAC;QAChD,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,KAAK,GAAiB;YAC1B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC;YACjC,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,MAAM,EAAE,eAAe;YACvB,IAAI;YACJ,IAAI;YACJ,GAAG,EAAE,CAAC;YACN,cAAc,EAAE,CAAC;YACjB,gBAAgB,EAAE,CAAC;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;YAC3B,WAAW,EAAE,KAAK;YAClB,KAAK;SACN,CAAC;QACF,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAExC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACnE,IAAI,MAAM,EAAE,CAAC;YACX,mEAAmE;YACnE,oEAAoE;YACpE,0DAA0D;YAC1D,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;YAC/B,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACrC,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;QAC7B,CAAC;QAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACxD,IAAI,SAAc,CAAC;QACnB,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;YACvB,MAAM,OAAO,GAAG,KAAK,EAAE,GAAW,EAAE,EAAE;gBACpC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClC,KAAK,CAAC,gBAAgB,IAAI,GAAG,CAAC,MAAM,CAAC;gBACrC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;oBAAE,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACxD,CAAC,CAAC;YACF,sEAAsE;YACtE,KAAK,MAAM,GAAG,IAAI,MAAM;gBAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7C,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,IAAI,CAAC,IAAI;oBAAE,MAAM;gBACrB,MAAM,OAAO,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACf,SAAS,GAAG,CAAC,CAAC;YACd,oEAAoE;YACpE,uBAAuB;YACvB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,MAAM;oBACjB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAe,CAAC;oBACjC,CAAC,CAAE,KAAgB,CAAC;gBACtB,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,MAAM,CAAC;gBACpC,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC;QACb,CAAC;QACD,IAAI,SAAS;YAAE,MAAM,SAAS,CAAC;QAE/B,IACE,CAAC,KAAK,CAAC,KAAK;YACZ,CAAC,KAAK,CAAC,cAAc,GAAG,UAAU,IAAI,KAAK,CAAC,gBAAgB,GAAG,UAAU,CAAC;YAE1E,MAAM,IAAI,KAAK,CACb,aAAa,IAAI,2CAA2C,CAC7D,CAAC;QAEJ,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,+CAA+C;IAC/C,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,IAAY,EACZ,UAA2C,EAAE;QAE7C,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;YAChD,GAAG,OAAO;YACV,QAAQ,EAAE,IAAI,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,SAAiB;QAC3C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,SAAS,CAAC,EAAE;YACtD,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM;YACzB,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,KAAK,CAAC,YAAY,CAChB,IAAY,EACZ,UAA2C,EAAE;QAE7C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,KAAK,GAAiB;YAC1B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;YAChC,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,aAAa;YACrB,IAAI;YACJ,IAAI;YACJ,GAAG,EAAE,CAAC;YACN,cAAc,EAAE,CAAC;YACjB,gBAAgB,EAAE,CAAC;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;YAC3B,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,KAAK;SACb,CAAC;QACF,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,gDAAgD;IACxC,aAAa,CAAC,KAAmB;QACvC,wEAAwE;QACxE,8BAA8B;QAC9B,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,gBAAgB,GAAG,UAAU;YACrC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,cAAc,GAAG,UAAU;YACnC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACzC,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU;YAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtE,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CACtB,mBAAmB,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CACpD,CAAC;QACF,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe;QACpD,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1C,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACpC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACjC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAClE,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzC,GAAG,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACjC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB;QAC3C,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc;QACxC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB;QAChD,GAAG,CAAC,aAAa,CACf,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAC9D,EAAE,CACH,CAAC;QACF,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAC1C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,EAAE,GAAG,mBAAmB,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YACnD,GAAG,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACtC,GAAG,CAAC,aAAa,CAAC,SAAS,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACzC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5E,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;QAE/C,MAAM,UAAU,GACd,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,UAAU;YAChC,YAAY,GAAG,UAAU;YACzB,WAAW,GAAG,UAAU,CAAC;QAE3B,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAChD,SAAS,CAAC,aAAa,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;YAC3C,WAAW,CAAC,SAAS,EAAE,eAAe,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAChD,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3C,SAAS,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAChC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY;YAC5C,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,8BAA8B;YAC9D,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChD,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChD,WAAW,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;YACxC,WAAW,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;YACzC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;YAC/B,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAE1B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACjD,OAAO,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;YAC5C,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5B,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB;QAC5C,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,101 @@
1
+ import { Readable } from "stream";
2
+ /** Request sent from the main thread to the zip worker. */
3
+ export type ZipRequest = {
4
+ id: number;
5
+ cmd: "beginFile";
6
+ path: string;
7
+ password?: string;
8
+ } | {
9
+ id: number;
10
+ cmd: "beginStream";
11
+ password?: string;
12
+ } | {
13
+ id: number;
14
+ cmd: "addBuffer";
15
+ entryName: string;
16
+ data: Uint8Array;
17
+ } | {
18
+ id: number;
19
+ cmd: "addLocalFile";
20
+ entryName: string;
21
+ localPath: string;
22
+ } | {
23
+ id: number;
24
+ cmd: "addDirectory";
25
+ entryName: string;
26
+ } | {
27
+ id: number;
28
+ cmd: "beginEntry";
29
+ entryName: string;
30
+ } | {
31
+ id: number;
32
+ cmd: "entryChunk";
33
+ data: Uint8Array;
34
+ } | {
35
+ id: number;
36
+ cmd: "endEntry";
37
+ } | {
38
+ id: number;
39
+ cmd: "finish";
40
+ };
41
+ /** Reply sent from the zip worker back to the main thread. */
42
+ export type ZipResponse = {
43
+ id: number;
44
+ ok: true;
45
+ result?: any;
46
+ } | {
47
+ id: number;
48
+ ok: false;
49
+ error: string;
50
+ };
51
+ /**
52
+ * Builds a zip file, one entry at a time, on a worker thread.
53
+ *
54
+ * `finish` completes the archive and shuts the worker down; the builder
55
+ * cannot be used afterwards.
56
+ */
57
+ export declare class ZipBuilder {
58
+ private worker;
59
+ private closed;
60
+ /** set when the archive is streamed to the caller rather than to a file */
61
+ readonly stream?: Readable;
62
+ private constructor();
63
+ private static begin;
64
+ /**
65
+ * Build an archive at a path on disk. It is written where it belongs -
66
+ * writing it elsewhere and moving it would fail across filesystems.
67
+ *
68
+ * @param password if non-empty, entries are encrypted with the traditional
69
+ * zip password scheme, as the system `zip -P` did
70
+ */
71
+ static toFile(path: string, password?: string): Promise<ZipBuilder>;
72
+ /**
73
+ * Build an archive into a readable stream, for destinations written over
74
+ * the network (S3, SFTP) or straight to a browser, so that no copy is made
75
+ * on the local disk. Read `stream` while adding entries: the archive is
76
+ * produced as it is consumed.
77
+ */
78
+ static toStream(password?: string): Promise<ZipBuilder>;
79
+ /** Add an entry from content held in memory */
80
+ addBuffer(entryName: string, data: Buffer): Promise<void>;
81
+ /** Add an entry from a file on disk. The worker streams it. */
82
+ addLocalFile(entryName: string, localPath: string): Promise<void>;
83
+ /**
84
+ * Add an entry from a stream of content produced in the main thread, for
85
+ * content too large to want as one buffer - a table dump, say. Each chunk
86
+ * is acknowledged before the next is sent, so the producer runs no faster
87
+ * than the archive is written.
88
+ */
89
+ addStream(entryName: string, source: Readable): Promise<void>;
90
+ /** Add a directory entry. A trailing slash is added if missing. */
91
+ addDirectory(entryName: string): Promise<void>;
92
+ /** Complete the archive and close the worker */
93
+ finish(): Promise<void>;
94
+ /**
95
+ * Abandon a half-built archive and close the worker. Any consumer of
96
+ * `stream` is failed too, so a partial archive is never mistaken for a
97
+ * complete one.
98
+ */
99
+ discard(cause?: any): Promise<void>;
100
+ }
101
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../models/zip.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAe,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE/C,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAClB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACrE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAElC,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAgH7C;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAE3B,OAAO;mBAKc,KAAK;IAgB1B;;;;;;OAMG;WACU,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAMzE;;;;;OAKG;WACU,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQ7D,+CAA+C;IACzC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D,+DAA+D;IACzD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;;;;OAKG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,mEAAmE;IAC7D,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,gDAAgD;IAC1C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAW7B;;;;OAIG;IACG,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ1C"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Building a zip file on a worker thread.
3
+ *
4
+ * Zipping is CPU-bound, so doing it on the main thread would block the event
5
+ * loop for the whole duration of a backup, which is why this used to shell
6
+ * out to the system `zip` executable. A worker thread gives the same
7
+ * non-blocking behaviour without depending on anything being installed on the
8
+ * host. (Reading is a different matter - see zip-extract.ts.)
9
+ *
10
+ * The archive is streamed, never assembled in memory: entries are compressed
11
+ * and written out as they are added (see zip-writer.ts), so a backup of a
12
+ * file store far larger than RAM works. Content generated in the main thread
13
+ * (pack.json, table dumps, config) is handed over a buffer at a time, while
14
+ * files already on disk are only named - the worker streams them itself.
15
+ *
16
+ * @category saltcorn-admin-models
17
+ * @module models/zip
18
+ */
19
+ import { Worker } from "worker_threads";
20
+ import { PassThrough } from "stream";
21
+ const workerURL = new URL("./zip-worker.js", import.meta.url);
22
+ /**
23
+ * A worker thread running zip-worker.js, with a promise-per-message
24
+ * request/response protocol on top of it.
25
+ */
26
+ class ZipWorker {
27
+ constructor() {
28
+ this.seq = 0;
29
+ this.pending = new Map();
30
+ this.worker = new Worker(workerURL);
31
+ this.worker.on("message", (msg) => {
32
+ if (msg?.type === "chunk")
33
+ return this.takeChunk(msg.data);
34
+ if (msg?.type === "chunkEnd")
35
+ return this.sink?.end();
36
+ const waiter = this.pending.get(msg.id);
37
+ if (!waiter)
38
+ return;
39
+ this.pending.delete(msg.id);
40
+ if (msg.ok)
41
+ waiter.resolve(msg.result);
42
+ else
43
+ waiter.reject(new Error(msg.error));
44
+ });
45
+ this.worker.on("error", (e) => this.fail(e));
46
+ this.worker.on("exit", (code) => {
47
+ if (this.pending.size)
48
+ this.fail(new Error(`zip worker stopped with exit code ${code}`));
49
+ });
50
+ }
51
+ /**
52
+ * Take a chunk of the archive and acknowledge it once the consumer has
53
+ * room for more. The worker sends the next chunk only after the
54
+ * acknowledgement, so a slow upload slows the whole pipeline down rather
55
+ * than filling memory.
56
+ */
57
+ takeChunk(data) {
58
+ const sink = this.sink;
59
+ if (!sink || sink.destroyed)
60
+ return this.abandon(new Error("Zip output stream was closed"));
61
+ const ack = () => this.worker.postMessage({ cmd: "chunkAck" });
62
+ if (sink.write(Buffer.from(data.buffer, data.byteOffset, data.byteLength)))
63
+ ack();
64
+ else
65
+ sink.once("drain", ack);
66
+ }
67
+ fail(e) {
68
+ this.dead = e;
69
+ for (const waiter of this.pending.values())
70
+ waiter.reject(e);
71
+ this.pending.clear();
72
+ this.sink?.destroy(e);
73
+ }
74
+ /**
75
+ * The output went away - a failed upload, a browser that closed the
76
+ * connection. Stop the worker rather than leaving it blocked forever on an
77
+ * acknowledgement that is never coming.
78
+ */
79
+ abandon(e) {
80
+ if (this.dead)
81
+ return;
82
+ this.fail(e);
83
+ this.worker.terminate();
84
+ }
85
+ /**
86
+ * Send a request and wait for its reply.
87
+ *
88
+ * Content buffers are copied, not transferred. Transferring would save the
89
+ * copy, but the buffer belongs to whoever passed it in: a producer that
90
+ * fills and reuses one buffer - which a Readable is free to do - would find
91
+ * it detached under it, and would go on writing zero-length chunks with no
92
+ * error anywhere. The copy is a memcpy against a deflate; it does not show.
93
+ */
94
+ send(req) {
95
+ if (this.dead)
96
+ return Promise.reject(this.dead);
97
+ const id = ++this.seq;
98
+ const message = { ...req, id };
99
+ return new Promise((resolve, reject) => {
100
+ this.pending.set(id, { resolve, reject });
101
+ this.worker.postMessage(message);
102
+ });
103
+ }
104
+ /** Start collecting the archive bytes the worker sends us */
105
+ openSink() {
106
+ const sink = new PassThrough();
107
+ // a consumer that fails takes the sink down with it; keep a listener of
108
+ // our own so that never becomes an unhandled error event, and stop
109
+ // producing bytes nobody is going to read
110
+ sink.on("error", (e) => this.abandon(e));
111
+ this.sink = sink;
112
+ return sink;
113
+ }
114
+ async close() {
115
+ await this.worker.terminate();
116
+ }
117
+ }
118
+ /**
119
+ * Builds a zip file, one entry at a time, on a worker thread.
120
+ *
121
+ * `finish` completes the archive and shuts the worker down; the builder
122
+ * cannot be used afterwards.
123
+ */
124
+ export class ZipBuilder {
125
+ constructor(worker, stream) {
126
+ this.closed = false;
127
+ this.worker = worker;
128
+ this.stream = stream;
129
+ }
130
+ static async begin(start, stream) {
131
+ const worker = new ZipWorker();
132
+ const readable = stream?.(worker);
133
+ const builder = new ZipBuilder(worker, readable);
134
+ try {
135
+ await start(worker);
136
+ }
137
+ catch (e) {
138
+ await builder.discard(e);
139
+ throw e;
140
+ }
141
+ return builder;
142
+ }
143
+ /**
144
+ * Build an archive at a path on disk. It is written where it belongs -
145
+ * writing it elsewhere and moving it would fail across filesystems.
146
+ *
147
+ * @param password if non-empty, entries are encrypted with the traditional
148
+ * zip password scheme, as the system `zip -P` did
149
+ */
150
+ static async toFile(path, password) {
151
+ return await ZipBuilder.begin((worker) => worker.send({ cmd: "beginFile", path, password: password || undefined }));
152
+ }
153
+ /**
154
+ * Build an archive into a readable stream, for destinations written over
155
+ * the network (S3, SFTP) or straight to a browser, so that no copy is made
156
+ * on the local disk. Read `stream` while adding entries: the archive is
157
+ * produced as it is consumed.
158
+ */
159
+ static async toStream(password) {
160
+ return await ZipBuilder.begin((worker) => worker.send({ cmd: "beginStream", password: password || undefined }), (worker) => worker.openSink());
161
+ }
162
+ /** Add an entry from content held in memory */
163
+ async addBuffer(entryName, data) {
164
+ await this.worker.send({ cmd: "addBuffer", entryName, data });
165
+ }
166
+ /** Add an entry from a file on disk. The worker streams it. */
167
+ async addLocalFile(entryName, localPath) {
168
+ await this.worker.send({ cmd: "addLocalFile", entryName, localPath });
169
+ }
170
+ /**
171
+ * Add an entry from a stream of content produced in the main thread, for
172
+ * content too large to want as one buffer - a table dump, say. Each chunk
173
+ * is acknowledged before the next is sent, so the producer runs no faster
174
+ * than the archive is written.
175
+ */
176
+ async addStream(entryName, source) {
177
+ await this.worker.send({ cmd: "beginEntry", entryName });
178
+ for await (const chunk of source)
179
+ await this.worker.send({ cmd: "entryChunk", data: chunk });
180
+ await this.worker.send({ cmd: "endEntry" });
181
+ }
182
+ /** Add a directory entry. A trailing slash is added if missing. */
183
+ async addDirectory(entryName) {
184
+ await this.worker.send({ cmd: "addDirectory", entryName });
185
+ }
186
+ /** Complete the archive and close the worker */
187
+ async finish() {
188
+ try {
189
+ await this.worker.send({ cmd: "finish" });
190
+ }
191
+ catch (e) {
192
+ await this.discard(e);
193
+ throw e;
194
+ }
195
+ this.closed = true;
196
+ await this.worker.close();
197
+ }
198
+ /**
199
+ * Abandon a half-built archive and close the worker. Any consumer of
200
+ * `stream` is failed too, so a partial archive is never mistaken for a
201
+ * complete one.
202
+ */
203
+ async discard(cause) {
204
+ if (this.closed)
205
+ return;
206
+ this.closed = true;
207
+ this.stream?.destroy(cause instanceof Error ? cause : new Error("Zip archive abandoned"));
208
+ await this.worker.close();
209
+ }
210
+ }
211
+ //# sourceMappingURL=zip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../models/zip.ts"],"names":[],"mappings":"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"}