@atproto/common 0.0.0-spaces-alpha-20260818021221

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 (48) hide show
  1. package/CHANGELOG.md +439 -0
  2. package/LICENSE.txt +7 -0
  3. package/README.md +15 -0
  4. package/dist/buffers.d.ts +3 -0
  5. package/dist/buffers.d.ts.map +1 -0
  6. package/dist/buffers.js +10 -0
  7. package/dist/buffers.js.map +1 -0
  8. package/dist/car.d.ts +40 -0
  9. package/dist/car.d.ts.map +1 -0
  10. package/dist/car.js +267 -0
  11. package/dist/car.js.map +1 -0
  12. package/dist/dates.d.ts +2 -0
  13. package/dist/dates.d.ts.map +1 -0
  14. package/dist/dates.js +19 -0
  15. package/dist/dates.js.map +1 -0
  16. package/dist/env.d.ts +5 -0
  17. package/dist/env.d.ts.map +1 -0
  18. package/dist/env.js +26 -0
  19. package/dist/env.js.map +1 -0
  20. package/dist/fs.d.ts +5 -0
  21. package/dist/fs.d.ts.map +1 -0
  22. package/dist/fs.js +46 -0
  23. package/dist/fs.js.map +1 -0
  24. package/dist/index.d.ts +12 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +12 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/ipld-multi.d.ts +6 -0
  29. package/dist/ipld-multi.d.ts.map +1 -0
  30. package/dist/ipld-multi.js +8 -0
  31. package/dist/ipld-multi.js.map +1 -0
  32. package/dist/ipld.d.ts +52 -0
  33. package/dist/ipld.d.ts.map +1 -0
  34. package/dist/ipld.js +111 -0
  35. package/dist/ipld.js.map +1 -0
  36. package/dist/logger.d.ts +16 -0
  37. package/dist/logger.d.ts.map +1 -0
  38. package/dist/logger.js +31 -0
  39. package/dist/logger.js.map +1 -0
  40. package/dist/obfuscate.d.ts +9 -0
  41. package/dist/obfuscate.d.ts.map +1 -0
  42. package/dist/obfuscate.js +85 -0
  43. package/dist/obfuscate.js.map +1 -0
  44. package/dist/streams.d.ts +32 -0
  45. package/dist/streams.d.ts.map +1 -0
  46. package/dist/streams.js +190 -0
  47. package/dist/streams.js.map +1 -0
  48. package/package.json +46 -0
package/dist/car.js ADDED
@@ -0,0 +1,267 @@
1
+ import { setImmediate } from 'node:timers/promises';
2
+ import varint from 'varint';
3
+ import * as cbor from '@atproto/lex-cbor';
4
+ import { decodeCid, ifCid, isCidForBytes } from '@atproto/lex-data';
5
+ export const encodeCarHeader = (roots) => {
6
+ const header = new Uint8Array(cbor.encode({
7
+ version: 1,
8
+ roots: roots == null ? [] : Array.isArray(roots) ? roots : [roots],
9
+ }));
10
+ return concat(new Uint8Array(varint.encode(header.byteLength)), header);
11
+ };
12
+ export const encodeCarBlock = (block) => concat(new Uint8Array(varint.encode(block.cid.bytes.byteLength + block.bytes.byteLength)), block.cid.bytes, block.bytes);
13
+ /**
14
+ * Write a CAR v1 stream. Most callers have a single root; permissioned repos
15
+ * declare two (a commit and an index), so roots is a list.
16
+ */
17
+ export async function* writeCarStream(roots, blocks) {
18
+ yield encodeCarHeader(roots);
19
+ for await (const block of blocks) {
20
+ yield encodeCarBlock(block);
21
+ }
22
+ }
23
+ const concat = (...parts) => {
24
+ let size = 0;
25
+ for (const part of parts)
26
+ size += part.byteLength;
27
+ const out = new Uint8Array(size);
28
+ let offset = 0;
29
+ for (const part of parts) {
30
+ out.set(part, offset);
31
+ offset += part.byteLength;
32
+ }
33
+ return out;
34
+ };
35
+ export const readCarStream = async (car, opts) => {
36
+ return readCarReader(new BufferedReader(car), opts);
37
+ };
38
+ export const readCarBytes = async (bytes, opts) => {
39
+ return readCarReader(new Ui8Reader(bytes), opts);
40
+ };
41
+ export const readCarReader = async (reader, opts) => {
42
+ try {
43
+ const headerSize = await readVarint(reader);
44
+ if (headerSize === null) {
45
+ throw new Error('Could not parse CAR header');
46
+ }
47
+ const headerBytes = await reader.read(headerSize);
48
+ const header = cbor.decode(headerBytes);
49
+ if (header === null || typeof header !== 'object') {
50
+ throw new Error('Could not parse CAR header');
51
+ }
52
+ const { version, roots } = header;
53
+ if (version !== 1) {
54
+ throw new Error('Could not parse CAR header');
55
+ }
56
+ if (!Array.isArray(roots)) {
57
+ throw new Error('Could not parse CAR header');
58
+ }
59
+ return {
60
+ roots: roots.map((root) => {
61
+ const cid = ifCid(root);
62
+ if (!cid)
63
+ throw new Error('Could not parse CAR header');
64
+ return cid;
65
+ }),
66
+ blocks: readCarBlocksIter(reader, opts),
67
+ };
68
+ }
69
+ catch (err) {
70
+ await reader.close();
71
+ throw err;
72
+ }
73
+ };
74
+ const readCarBlocksIter = (reader, opts) => {
75
+ let generator = readCarBlocksIterGenerator(reader);
76
+ if (!opts?.skipCidVerification) {
77
+ generator = verifyIncomingCarBlocks(generator);
78
+ }
79
+ return Object.assign(generator, {
80
+ async dump() {
81
+ // try/finally to ensure that reader.close is called even if blocks.return throws.
82
+ try {
83
+ // Prevent the iterator from being started after this method is called.
84
+ await generator.return();
85
+ }
86
+ finally {
87
+ // @NOTE the "finally" block of the async generator won't be called
88
+ // if the iteration was never started so we need to manually close here.
89
+ await reader.close();
90
+ }
91
+ },
92
+ });
93
+ };
94
+ async function* readCarBlocksIterGenerator(reader) {
95
+ let blocks = 0;
96
+ try {
97
+ while (!reader.isDone) {
98
+ const blockSize = await readVarint(reader);
99
+ if (blockSize === null) {
100
+ break;
101
+ }
102
+ const blockBytes = await reader.read(blockSize);
103
+ const cid = decodeCid(blockBytes.subarray(0, 36));
104
+ const bytes = blockBytes.subarray(36);
105
+ yield { cid, bytes };
106
+ // yield to the event loop every 25 blocks
107
+ // in the case the incoming CAR is synchronous, this can end up jamming up the thread
108
+ blocks++;
109
+ if (blocks % 25 === 0) {
110
+ await setImmediate();
111
+ }
112
+ }
113
+ }
114
+ finally {
115
+ await reader.close();
116
+ }
117
+ }
118
+ export async function* verifyIncomingCarBlocks(car) {
119
+ for await (const block of car) {
120
+ if (!(await isCidForBytes(block.cid, block.bytes))) {
121
+ throw new Error(`Not a valid CID for bytes (${block.cid.toString()})`);
122
+ }
123
+ yield block;
124
+ }
125
+ }
126
+ const readVarint = async (reader) => {
127
+ let done = false;
128
+ const bytes = [];
129
+ while (!done) {
130
+ const byte = await reader.read(1);
131
+ if (byte.byteLength === 0) {
132
+ if (bytes.length > 0) {
133
+ throw new Error('could not parse varint');
134
+ }
135
+ else {
136
+ return null;
137
+ }
138
+ }
139
+ bytes.push(byte);
140
+ if (byte[0] < 128) {
141
+ done = true;
142
+ }
143
+ }
144
+ const concatted = Buffer.concat(bytes);
145
+ return varint.decode(concatted);
146
+ };
147
+ class Ui8Reader {
148
+ constructor(bytes) {
149
+ this.bytes = bytes;
150
+ this.idx = 0;
151
+ this.isDone = false;
152
+ }
153
+ async read(bytesToRead) {
154
+ const value = this.bytes.subarray(this.idx, this.idx + bytesToRead);
155
+ this.idx += bytesToRead;
156
+ if (this.idx >= this.bytes.length) {
157
+ this.isDone = true;
158
+ }
159
+ return value;
160
+ }
161
+ async close() { }
162
+ }
163
+ /**
164
+ * This code was optimized for performance. See
165
+ * {@link https://github.com/bluesky-social/atproto/pull/4729 #4729} for more details
166
+ * and benchmarks.
167
+ */
168
+ class BufferedReader {
169
+ constructor(stream) {
170
+ this.isDone = false;
171
+ /** fifo list of chunks to consume */
172
+ this.chunks = [];
173
+ this.iterator =
174
+ Symbol.asyncIterator in stream
175
+ ? stream[Symbol.asyncIterator]()
176
+ : stream[Symbol.iterator]();
177
+ }
178
+ /** Number of bytes currently buffered and available for reading */
179
+ get bufferedByteLength() {
180
+ let total = 0;
181
+ for (let i = 0; i < this.chunks.length; i++) {
182
+ total += this.chunks[i].byteLength;
183
+ }
184
+ return total;
185
+ }
186
+ /**
187
+ * @note concurrent reads are **NOT** supported by the current implementation
188
+ * and would require call to readUntilBuffered to be using a fifo lock for
189
+ * read()s to be processed in fifo order.
190
+ */
191
+ async read(bytesToRead) {
192
+ const bytesNeeded = bytesToRead - this.bufferedByteLength;
193
+ if (bytesNeeded > 0 && !this.isDone) {
194
+ await this.readUntilBuffered(bytesNeeded);
195
+ }
196
+ const resultLength = Math.min(bytesToRead, this.bufferedByteLength);
197
+ if (resultLength <= 0)
198
+ return new Uint8Array();
199
+ const firstChunk = this.consumeChunk(resultLength);
200
+ if (firstChunk.byteLength === resultLength) {
201
+ // If the data consumed from the first chunk contains all we need, return
202
+ // it as-is. This allows to avoid any copy operation.
203
+ return firstChunk;
204
+ }
205
+ // The first chunk does not have all the data we need. We have to copy
206
+ // multiple chunks into a larger buffer
207
+ const result = new Uint8Array(resultLength);
208
+ let resultWriteIndex = 0;
209
+ // Copy the first chunk into the result buffer
210
+ result.set(firstChunk, resultWriteIndex);
211
+ resultWriteIndex += firstChunk.byteLength;
212
+ // Copy more chunks as needed (we use do-while because we *know* we need
213
+ // more than one chunk)
214
+ do {
215
+ const missingLength = resultLength - resultWriteIndex;
216
+ const currentChunk = this.consumeChunk(missingLength);
217
+ result.set(currentChunk, resultWriteIndex);
218
+ resultWriteIndex += currentChunk.byteLength;
219
+ } while (resultWriteIndex < resultLength);
220
+ return result;
221
+ }
222
+ async readUntilBuffered(bytesNeeded) {
223
+ let bytesRead = 0;
224
+ while (bytesRead < bytesNeeded) {
225
+ const next = await this.iterator.next();
226
+ if (next.done) {
227
+ this.isDone = true;
228
+ break;
229
+ }
230
+ else {
231
+ this.chunks.push(next.value);
232
+ bytesRead += next.value.byteLength;
233
+ }
234
+ }
235
+ return bytesRead;
236
+ }
237
+ consumeChunk(bytesToConsume) {
238
+ const firstChunk = this.chunks[0];
239
+ if (bytesToConsume < firstChunk.byteLength) {
240
+ // return a sub-view of the data being read and replace the first chunk
241
+ // with a sub-view that does not contain that data.
242
+ // @NOTE for some reason, subarray() revealed to be 7-8% slower in NodeJS
243
+ // benchmarks.
244
+ // this.chunks[0] = firstChunk.subarray(bytesToConsume)
245
+ // return firstChunk.subarray(0, bytesToConsume)
246
+ this.chunks[0] = new Uint8Array(firstChunk.buffer, firstChunk.byteOffset + bytesToConsume, firstChunk.byteLength - bytesToConsume);
247
+ return new Uint8Array(firstChunk.buffer, firstChunk.byteOffset, bytesToConsume);
248
+ }
249
+ else {
250
+ // First chunk is being read in full, discard it
251
+ this.chunks.shift();
252
+ return firstChunk;
253
+ }
254
+ }
255
+ async close() {
256
+ try {
257
+ if (!this.isDone && this.iterator.return) {
258
+ await this.iterator.return();
259
+ }
260
+ }
261
+ finally {
262
+ this.isDone = true;
263
+ this.chunks.length = 0;
264
+ }
265
+ }
266
+ }
267
+ //# sourceMappingURL=car.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"car.js","sourceRoot":"","sources":["../src/car.ts"],"names":[],"mappings":"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","sourcesContent":["import { setImmediate } from 'node:timers/promises'\nimport varint from 'varint'\nimport * as cbor from '@atproto/lex-cbor'\nimport { type Cid, decodeCid, ifCid, isCidForBytes } from '@atproto/lex-data'\n\nexport type CarBlock = {\n cid: Cid\n bytes: Uint8Array\n}\n\nexport const encodeCarHeader = (\n roots: Cid | readonly Cid[] | null,\n): Uint8Array => {\n const header = new Uint8Array(\n cbor.encode({\n version: 1,\n roots: roots == null ? [] : Array.isArray(roots) ? roots : [roots],\n }),\n )\n return concat(new Uint8Array(varint.encode(header.byteLength)), header)\n}\n\nexport const encodeCarBlock = (block: CarBlock): Uint8Array =>\n concat(\n new Uint8Array(\n varint.encode(block.cid.bytes.byteLength + block.bytes.byteLength),\n ),\n block.cid.bytes,\n block.bytes,\n )\n\n/**\n * Write a CAR v1 stream. Most callers have a single root; permissioned repos\n * declare two (a commit and an index), so roots is a list.\n */\nexport async function* writeCarStream(\n roots: Cid | readonly Cid[] | null,\n blocks: AsyncIterable<CarBlock> | Iterable<CarBlock>,\n): AsyncIterable<Uint8Array> {\n yield encodeCarHeader(roots)\n for await (const block of blocks) {\n yield encodeCarBlock(block)\n }\n}\n\nconst concat = (...parts: Uint8Array[]): Uint8Array => {\n let size = 0\n for (const part of parts) size += part.byteLength\n const out = new Uint8Array(size)\n let offset = 0\n for (const part of parts) {\n out.set(part, offset)\n offset += part.byteLength\n }\n return out\n}\n\nexport type ReadCarOptions = {\n /**\n * When true, does not verify CID-to-content mapping within CAR.\n */\n skipCidVerification?: boolean\n}\n\nexport type CarBlockIterable = AsyncGenerator<CarBlock, void, unknown> & {\n dump: () => Promise<void>\n}\n\nexport const readCarStream = async (\n car: Iterable<Uint8Array> | AsyncIterable<Uint8Array>,\n opts?: ReadCarOptions,\n): Promise<{\n roots: Cid[]\n blocks: CarBlockIterable\n}> => {\n return readCarReader(new BufferedReader(car), opts)\n}\n\nexport const readCarBytes = async (\n bytes: Uint8Array,\n opts?: ReadCarOptions,\n): Promise<{\n roots: Cid[]\n blocks: CarBlockIterable\n}> => {\n return readCarReader(new Ui8Reader(bytes), opts)\n}\n\nexport const readCarReader = async (\n reader: BytesReader,\n opts?: ReadCarOptions,\n): Promise<{\n roots: Cid[]\n blocks: CarBlockIterable\n}> => {\n try {\n const headerSize = await readVarint(reader)\n if (headerSize === null) {\n throw new Error('Could not parse CAR header')\n }\n const headerBytes = await reader.read(headerSize)\n const header = cbor.decode(headerBytes)\n if (header === null || typeof header !== 'object') {\n throw new Error('Could not parse CAR header')\n }\n const { version, roots } = header as {\n version?: unknown\n roots?: unknown\n }\n if (version !== 1) {\n throw new Error('Could not parse CAR header')\n }\n if (!Array.isArray(roots)) {\n throw new Error('Could not parse CAR header')\n }\n return {\n roots: roots.map((root) => {\n const cid = ifCid(root)\n if (!cid) throw new Error('Could not parse CAR header')\n return cid\n }),\n blocks: readCarBlocksIter(reader, opts),\n }\n } catch (err) {\n await reader.close()\n throw err\n }\n}\n\nconst readCarBlocksIter = (\n reader: BytesReader,\n opts?: ReadCarOptions,\n): CarBlockIterable => {\n let generator = readCarBlocksIterGenerator(reader)\n if (!opts?.skipCidVerification) {\n generator = verifyIncomingCarBlocks(generator)\n }\n return Object.assign(generator, {\n async dump() {\n // try/finally to ensure that reader.close is called even if blocks.return throws.\n try {\n // Prevent the iterator from being started after this method is called.\n await generator.return()\n } finally {\n // @NOTE the \"finally\" block of the async generator won't be called\n // if the iteration was never started so we need to manually close here.\n await reader.close()\n }\n },\n })\n}\n\nasync function* readCarBlocksIterGenerator(\n reader: BytesReader,\n): AsyncGenerator<CarBlock, void, unknown> {\n let blocks = 0\n try {\n while (!reader.isDone) {\n const blockSize = await readVarint(reader)\n if (blockSize === null) {\n break\n }\n const blockBytes = await reader.read(blockSize)\n const cid = decodeCid(blockBytes.subarray(0, 36))\n const bytes = blockBytes.subarray(36)\n yield { cid, bytes }\n\n // yield to the event loop every 25 blocks\n // in the case the incoming CAR is synchronous, this can end up jamming up the thread\n blocks++\n if (blocks % 25 === 0) {\n await setImmediate()\n }\n }\n } finally {\n await reader.close()\n }\n}\n\nexport async function* verifyIncomingCarBlocks(\n car: AsyncIterable<CarBlock>,\n): AsyncGenerator<CarBlock, void, unknown> {\n for await (const block of car) {\n if (!(await isCidForBytes(block.cid, block.bytes))) {\n throw new Error(`Not a valid CID for bytes (${block.cid.toString()})`)\n }\n yield block\n }\n}\n\nconst readVarint = async (reader: BytesReader): Promise<number | null> => {\n let done = false\n const bytes: Uint8Array[] = []\n while (!done) {\n const byte = await reader.read(1)\n if (byte.byteLength === 0) {\n if (bytes.length > 0) {\n throw new Error('could not parse varint')\n } else {\n return null\n }\n }\n bytes.push(byte)\n if (byte[0] < 128) {\n done = true\n }\n }\n const concatted = Buffer.concat(bytes)\n return varint.decode(concatted)\n}\n\nexport interface BytesReader {\n isDone: boolean\n read(bytesToRead: number): Promise<Uint8Array>\n close(): Promise<void>\n}\n\nclass Ui8Reader implements BytesReader {\n idx = 0\n isDone = false\n\n constructor(public bytes: Uint8Array) {}\n\n async read(bytesToRead: number): Promise<Uint8Array> {\n const value = this.bytes.subarray(this.idx, this.idx + bytesToRead)\n this.idx += bytesToRead\n if (this.idx >= this.bytes.length) {\n this.isDone = true\n }\n return value\n }\n\n async close(): Promise<void> {}\n}\n\n/**\n * This code was optimized for performance. See\n * {@link https://github.com/bluesky-social/atproto/pull/4729 #4729} for more details\n * and benchmarks.\n */\nclass BufferedReader implements BytesReader {\n iterator: Iterator<Uint8Array> | AsyncIterator<Uint8Array>\n isDone = false\n\n /** fifo list of chunks to consume */\n private chunks: Uint8Array[] = []\n\n constructor(stream: Iterable<Uint8Array> | AsyncIterable<Uint8Array>) {\n this.iterator =\n Symbol.asyncIterator in stream\n ? stream[Symbol.asyncIterator]()\n : stream[Symbol.iterator]()\n }\n\n /** Number of bytes currently buffered and available for reading */\n get bufferedByteLength() {\n let total = 0\n for (let i = 0; i < this.chunks.length; i++) {\n total += this.chunks[i].byteLength\n }\n return total\n }\n\n /**\n * @note concurrent reads are **NOT** supported by the current implementation\n * and would require call to readUntilBuffered to be using a fifo lock for\n * read()s to be processed in fifo order.\n */\n async read(bytesToRead: number): Promise<Uint8Array> {\n const bytesNeeded = bytesToRead - this.bufferedByteLength\n if (bytesNeeded > 0 && !this.isDone) {\n await this.readUntilBuffered(bytesNeeded)\n }\n\n const resultLength = Math.min(bytesToRead, this.bufferedByteLength)\n if (resultLength <= 0) return new Uint8Array()\n\n const firstChunk = this.consumeChunk(resultLength)\n if (firstChunk.byteLength === resultLength) {\n // If the data consumed from the first chunk contains all we need, return\n // it as-is. This allows to avoid any copy operation.\n return firstChunk\n }\n\n // The first chunk does not have all the data we need. We have to copy\n // multiple chunks into a larger buffer\n const result = new Uint8Array(resultLength)\n let resultWriteIndex = 0\n\n // Copy the first chunk into the result buffer\n result.set(firstChunk, resultWriteIndex)\n resultWriteIndex += firstChunk.byteLength\n\n // Copy more chunks as needed (we use do-while because we *know* we need\n // more than one chunk)\n do {\n const missingLength = resultLength - resultWriteIndex\n const currentChunk = this.consumeChunk(missingLength)\n\n result.set(currentChunk, resultWriteIndex)\n resultWriteIndex += currentChunk.byteLength\n } while (resultWriteIndex < resultLength)\n\n return result\n }\n\n private async readUntilBuffered(bytesNeeded: number) {\n let bytesRead = 0\n while (bytesRead < bytesNeeded) {\n const next = await this.iterator.next()\n if (next.done) {\n this.isDone = true\n break\n } else {\n this.chunks.push(next.value)\n bytesRead += next.value.byteLength\n }\n }\n return bytesRead\n }\n\n private consumeChunk(bytesToConsume: number) {\n const firstChunk = this.chunks[0]!\n if (bytesToConsume < firstChunk.byteLength) {\n // return a sub-view of the data being read and replace the first chunk\n // with a sub-view that does not contain that data.\n\n // @NOTE for some reason, subarray() revealed to be 7-8% slower in NodeJS\n // benchmarks.\n\n // this.chunks[0] = firstChunk.subarray(bytesToConsume)\n // return firstChunk.subarray(0, bytesToConsume)\n\n this.chunks[0] = new Uint8Array(\n firstChunk.buffer,\n firstChunk.byteOffset + bytesToConsume,\n firstChunk.byteLength - bytesToConsume,\n )\n return new Uint8Array(\n firstChunk.buffer,\n firstChunk.byteOffset,\n bytesToConsume,\n )\n } else {\n // First chunk is being read in full, discard it\n this.chunks.shift()\n return firstChunk\n }\n }\n\n async close(): Promise<void> {\n try {\n if (!this.isDone && this.iterator.return) {\n await this.iterator.return()\n }\n } finally {\n this.isDone = true\n this.chunks.length = 0\n }\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function toSimplifiedISOSafe(dateStr: string): string;
2
+ //# sourceMappingURL=dates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,UAiBlD"}
package/dist/dates.js ADDED
@@ -0,0 +1,19 @@
1
+ // Normalize date strings to simplified ISO so that the lexical sort preserves temporal sort.
2
+ // Rather than failing on an invalid date format, returns valid unix epoch.
3
+ export function toSimplifiedISOSafe(dateStr) {
4
+ const date = new Date(dateStr);
5
+ if (isNaN(date.getTime())) {
6
+ return new Date(0).toISOString();
7
+ }
8
+ const iso = date.toISOString();
9
+ // Date.toISOString() always returns `YYYY-MM-DDTHH:mm:ss.sssZ` or
10
+ // `±YYYYYY-MM-DDTHH:mm:ss.sssZ`
11
+ // (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
12
+ // However, the leading `±` and 6 digit year can break lexical sorting, so we
13
+ // need to catch those cases and return a safe value.
14
+ if (iso.startsWith('-') || iso.startsWith('+')) {
15
+ return new Date(0).toISOString();
16
+ }
17
+ return iso; // YYYY-MM-DDTHH:mm:ss.sssZ
18
+ }
19
+ //# sourceMappingURL=dates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dates.js","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IAClC,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;IAE9B,kEAAkE;IAClE,gCAAgC;IAChC,sGAAsG;IACtG,6EAA6E;IAC7E,qDAAqD;IACrD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IAClC,CAAC;IAED,OAAO,GAAG,CAAA,CAAC,2BAA2B;AACxC,CAAC","sourcesContent":["// Normalize date strings to simplified ISO so that the lexical sort preserves temporal sort.\n// Rather than failing on an invalid date format, returns valid unix epoch.\nexport function toSimplifiedISOSafe(dateStr: string) {\n const date = new Date(dateStr)\n if (isNaN(date.getTime())) {\n return new Date(0).toISOString()\n }\n const iso = date.toISOString()\n\n // Date.toISOString() always returns `YYYY-MM-DDTHH:mm:ss.sssZ` or\n // `±YYYYYY-MM-DDTHH:mm:ss.sssZ`\n // (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)\n // However, the leading `±` and 6 digit year can break lexical sorting, so we\n // need to catch those cases and return a safe value.\n if (iso.startsWith('-') || iso.startsWith('+')) {\n return new Date(0).toISOString()\n }\n\n return iso // YYYY-MM-DDTHH:mm:ss.sssZ\n}\n"]}
package/dist/env.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare const envInt: (name: string) => number | undefined;
2
+ export declare const envStr: (name: string) => string | undefined;
3
+ export declare const envBool: (name: string) => boolean | undefined;
4
+ export declare const envList: (name: string) => string[];
5
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,SAAU,MAAM,KAAG,MAAM,GAAG,SAG9C,CAAA;AAED,eAAO,MAAM,MAAM,SAAU,MAAM,KAAG,MAAM,GAAG,SAI9C,CAAA;AAED,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,OAAO,GAAG,SAKhD,CAAA;AAED,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,MAAM,EAI5C,CAAA"}
package/dist/env.js ADDED
@@ -0,0 +1,26 @@
1
+ import { parseIntWithFallback } from '@atproto/common-web';
2
+ export const envInt = (name) => {
3
+ const str = process.env[name];
4
+ return parseIntWithFallback(str, undefined);
5
+ };
6
+ export const envStr = (name) => {
7
+ const str = process.env[name];
8
+ if (str === undefined || str.length === 0)
9
+ return undefined;
10
+ return str;
11
+ };
12
+ export const envBool = (name) => {
13
+ const str = process.env[name];
14
+ if (str === 'true' || str === '1')
15
+ return true;
16
+ if (str === 'false' || str === '0')
17
+ return false;
18
+ return undefined;
19
+ };
20
+ export const envList = (name) => {
21
+ const str = process.env[name];
22
+ if (str === undefined || str.length === 0)
23
+ return [];
24
+ return str.split(',');
25
+ };
26
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAE1D,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAsB,EAAE;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,OAAO,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAsB,EAAE;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3D,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAuB,EAAE;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,IAAI,CAAA;IAC9C,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,KAAK,CAAA;IAChD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAY,EAAE;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACpD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACvB,CAAC,CAAA","sourcesContent":["import { parseIntWithFallback } from '@atproto/common-web'\n\nexport const envInt = (name: string): number | undefined => {\n const str = process.env[name]\n return parseIntWithFallback(str, undefined)\n}\n\nexport const envStr = (name: string): string | undefined => {\n const str = process.env[name]\n if (str === undefined || str.length === 0) return undefined\n return str\n}\n\nexport const envBool = (name: string): boolean | undefined => {\n const str = process.env[name]\n if (str === 'true' || str === '1') return true\n if (str === 'false' || str === '0') return false\n return undefined\n}\n\nexport const envList = (name: string): string[] => {\n const str = process.env[name]\n if (str === undefined || str.length === 0) return []\n return str.split(',')\n}\n"]}
package/dist/fs.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare const fileExists: (location: string) => Promise<boolean>;
2
+ export declare const readIfExists: (filepath: string) => Promise<Uint8Array | undefined>;
3
+ export declare const rmIfExists: (filepath: string, recursive?: boolean) => Promise<void>;
4
+ export declare const renameIfExists: (oldPath: string, newPath: string) => Promise<void>;
5
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,aAAoB,MAAM,KAAG,OAAO,CAAC,OAAO,CAUlE,CAAA;AAED,eAAO,MAAM,YAAY,aACb,MAAM,KACf,OAAO,CAAC,UAAU,GAAG,SAAS,CAShC,CAAA;AAED,eAAO,MAAM,UAAU,aACX,MAAM,0BAEf,OAAO,CAAC,IAAI,CAOd,CAAA;AAED,eAAO,MAAM,cAAc,YAChB,MAAM,WACN,MAAM,KACd,OAAO,CAAC,IAAI,CASd,CAAA"}
package/dist/fs.js ADDED
@@ -0,0 +1,46 @@
1
+ import { constants } from 'node:fs';
2
+ import fs from 'node:fs/promises';
3
+ import { isErrnoException } from '@atproto/common-web';
4
+ export const fileExists = async (location) => {
5
+ try {
6
+ await fs.access(location, constants.F_OK);
7
+ return true;
8
+ }
9
+ catch (err) {
10
+ if (isErrnoException(err) && err.code === 'ENOENT') {
11
+ return false;
12
+ }
13
+ throw err;
14
+ }
15
+ };
16
+ export const readIfExists = async (filepath) => {
17
+ try {
18
+ return await fs.readFile(filepath);
19
+ }
20
+ catch (err) {
21
+ if (isErrnoException(err) && err.code === 'ENOENT') {
22
+ return;
23
+ }
24
+ throw err;
25
+ }
26
+ };
27
+ export const rmIfExists = async (filepath, recursive = false) => {
28
+ await fs.rm(filepath, {
29
+ force: true, // ignore errors if the file/directory does not exist
30
+ recursive,
31
+ maxRetries: 5,
32
+ retryDelay: 50,
33
+ });
34
+ };
35
+ export const renameIfExists = async (oldPath, newPath) => {
36
+ try {
37
+ await fs.rename(oldPath, newPath);
38
+ }
39
+ catch (err) {
40
+ if (isErrnoException(err) && err.code === 'ENOENT') {
41
+ return;
42
+ }
43
+ throw err;
44
+ }
45
+ };
46
+ //# sourceMappingURL=fs.js.map
package/dist/fs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEtD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,QAAgB,EAAoB,EAAE;IACrE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;QACzC,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,QAAgB,EACiB,EAAE;IACnC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,OAAM;QACR,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,QAAgB,EAChB,SAAS,GAAG,KAAK,EACF,EAAE;IACjB,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE;QACpB,KAAK,EAAE,IAAI,EAAE,qDAAqD;QAClE,SAAS;QACT,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,EAAE;KACf,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,OAAe,EACf,OAAe,EACA,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,OAAM;QACR,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC,CAAA","sourcesContent":["import { constants } from 'node:fs'\nimport fs from 'node:fs/promises'\nimport { isErrnoException } from '@atproto/common-web'\n\nexport const fileExists = async (location: string): Promise<boolean> => {\n try {\n await fs.access(location, constants.F_OK)\n return true\n } catch (err) {\n if (isErrnoException(err) && err.code === 'ENOENT') {\n return false\n }\n throw err\n }\n}\n\nexport const readIfExists = async (\n filepath: string,\n): Promise<Uint8Array | undefined> => {\n try {\n return await fs.readFile(filepath)\n } catch (err) {\n if (isErrnoException(err) && err.code === 'ENOENT') {\n return\n }\n throw err\n }\n}\n\nexport const rmIfExists = async (\n filepath: string,\n recursive = false,\n): Promise<void> => {\n await fs.rm(filepath, {\n force: true, // ignore errors if the file/directory does not exist\n recursive,\n maxRetries: 5,\n retryDelay: 50,\n })\n}\n\nexport const renameIfExists = async (\n oldPath: string,\n newPath: string,\n): Promise<void> => {\n try {\n await fs.rename(oldPath, newPath)\n } catch (err) {\n if (isErrnoException(err) && err.code === 'ENOENT') {\n return\n }\n throw err\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ export * from '@atproto/common-web';
2
+ export * from './buffers.js';
3
+ export * from './car.js';
4
+ export * from './dates.js';
5
+ export * from './env.js';
6
+ export * from './fs.js';
7
+ export * from './ipld.js';
8
+ export * from './ipld-multi.js';
9
+ export * from './logger.js';
10
+ export * from './obfuscate.js';
11
+ export * from './streams.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from '@atproto/common-web';
2
+ export * from './buffers.js';
3
+ export * from './car.js';
4
+ export * from './dates.js';
5
+ export * from './env.js';
6
+ export * from './fs.js';
7
+ export * from './ipld.js';
8
+ export * from './ipld-multi.js';
9
+ export * from './logger.js';
10
+ export * from './obfuscate.js';
11
+ export * from './streams.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA","sourcesContent":["export * from '@atproto/common-web'\nexport * from './buffers.js'\nexport * from './car.js'\nexport * from './dates.js'\nexport * from './env.js'\nexport * from './fs.js'\nexport * from './ipld.js'\nexport * from './ipld-multi.js'\nexport * from './logger.js'\nexport * from './obfuscate.js'\nexport * from './streams.js'\n"]}
@@ -0,0 +1,6 @@
1
+ import type { LexValue } from '@atproto/lex-data';
2
+ /**
3
+ * @deprecated Use {@link decodeAll} from `@atproto/lex-cbor` instead.
4
+ */
5
+ export declare function cborDecodeMulti(encoded: Uint8Array): LexValue[];
6
+ //# sourceMappingURL=ipld-multi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipld-multi.d.ts","sourceRoot":"","sources":["../src/ipld-multi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,QAAQ,EAAE,CAE/D"}
@@ -0,0 +1,8 @@
1
+ import { decodeAll } from '@atproto/lex-cbor';
2
+ /**
3
+ * @deprecated Use {@link decodeAll} from `@atproto/lex-cbor` instead.
4
+ */
5
+ export function cborDecodeMulti(encoded) {
6
+ return Array.from(decodeAll(encoded));
7
+ }
8
+ //# sourceMappingURL=ipld-multi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipld-multi.js","sourceRoot":"","sources":["../src/ipld-multi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAG7C;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAmB;IACjD,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;AACvC,CAAC","sourcesContent":["import { decodeAll } from '@atproto/lex-cbor'\nimport type { LexValue } from '@atproto/lex-data'\n\n/**\n * @deprecated Use {@link decodeAll} from `@atproto/lex-cbor` instead.\n */\nexport function cborDecodeMulti(encoded: Uint8Array): LexValue[] {\n return Array.from(decodeAll(encoded))\n}\n"]}
package/dist/ipld.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Transform } from 'node:stream';
2
+ import type { BlockView, ByteView } from 'multiformats/block/interface';
3
+ import { type CID, type Cid } from '@atproto/lex-data';
4
+ /**
5
+ * @deprecated Use {@link encode} from `@atproto/lex-cbor` instead.
6
+ */
7
+ declare const cborEncodeLegacy: <T = unknown>(data: T) => ByteView<T>;
8
+ export { cborEncodeLegacy as cborEncode };
9
+ /**
10
+ * @deprecated Use {@link decode} from `@atproto/lex-cbor` instead.
11
+ */
12
+ declare const cborDecodeLegacy: <T = unknown>(bytes: ByteView<T>) => T;
13
+ export { cborDecodeLegacy as cborDecode };
14
+ /**
15
+ * @deprecated Use {@link encode} and {@link cidForCbor} from `@atproto/lex-cbor` instead.
16
+ */
17
+ export declare function dataToCborBlock<T>(value: T): Promise<BlockView<T, 0x71, 0x12, 1>>;
18
+ /**
19
+ * @deprecated Use {@link cidForLex} from `@atproto/lex-cbor` instead.
20
+ */
21
+ declare function cidForCborLegacy(data: unknown): Promise<CID>;
22
+ export { cidForCborLegacy as cidForCbor };
23
+ /**
24
+ * @deprecated Use {@link validateCidString} from '@atproto/lex-data' instead.
25
+ */
26
+ export declare function isValidCid(cidStr: string): Promise<boolean>;
27
+ /**
28
+ * @deprecated Use {@link decode} from `@atproto/lex-cbor`, and {@link isTypedLexMap} from `@atproto/lex-data` instead.
29
+ */
30
+ export declare function cborBytesToRecord(bytes: Uint8Array): Record<string, unknown>;
31
+ /**
32
+ * @deprecated Use {@link isCidForBytes} from `@atproto/lex-cbor` instead.
33
+ */
34
+ export declare function verifyCidForBytes(cid: Cid, bytes: Uint8Array): Promise<void>;
35
+ /**
36
+ * @deprecated Use {@link cidForRawHash} from `@atproto/lex-cbor` instead.
37
+ */
38
+ export declare function sha256RawToCid(hash: Uint8Array): CID;
39
+ /**
40
+ * @deprecated Use {@link decodeCid} from `@atproto/lex-cbor` instead.
41
+ */
42
+ export declare function parseCidFromBytes(bytes: Uint8Array): CID;
43
+ export declare class VerifyCidTransform extends Transform {
44
+ cid: Cid;
45
+ constructor(cid: Cid);
46
+ }
47
+ export declare class VerifyCidError extends Error {
48
+ expected: Cid;
49
+ actual: Cid;
50
+ constructor(expected: Cid, actual: Cid);
51
+ }
52
+ //# sourceMappingURL=ipld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipld.d.ts","sourceRoot":"","sources":["../src/ipld.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAGvE,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,GAAG,EAUT,MAAM,mBAAmB,CAAA;AAE1B;;GAEG;AACH,QAAA,MAAM,gBAAgB,EAAa,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;AACxE,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,CAAA;AAEzC;;GAEG;AACH,QAAA,MAAM,gBAAgB,EAAa,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;AACzE,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,CAAA;AAEzC;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,KAAK,EAAE,CAAC,GACP,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAUtC;AAED;;GAEG;AACH,iBAAe,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAE3D;AACD,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,CAAA;AAEzC;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAK5E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,GAAG,CAEpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAExD;AAED,qBAAa,kBAAmB,SAAQ,SAAS;IAC5B,GAAG,EAAE,GAAG;IAA3B,YAAmB,GAAG,EAAE,GAAG,EAoB1B;CACF;AAKD,qBAAa,cAAe,SAAQ,KAAK;IAE9B,QAAQ,EAAE,GAAG;IACb,MAAM,EAAE,GAAG;IAFpB,YACS,QAAQ,EAAE,GAAG,EACb,MAAM,EAAE,GAAG,EAGnB;CACF"}