@starkeep/protocol-primitives 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,594 @@
1
+ // src/identifiers/types.ts
2
+ function createStarkeepId(value) {
3
+ return value;
4
+ }
5
+ function isStarkeepId(value) {
6
+ return typeof value === "string" && value.length === 26;
7
+ }
8
+
9
+ // src/identifiers/ulid.ts
10
+ import { ulid, monotonicFactory } from "ulidx";
11
+ var monotonic = monotonicFactory();
12
+ function generateId() {
13
+ return createStarkeepId(monotonic());
14
+ }
15
+ function generateIdAt(timestamp) {
16
+ return createStarkeepId(ulid(timestamp));
17
+ }
18
+
19
+ // src/hlc/clock.ts
20
+ function createHLCClock(options) {
21
+ const { nodeId, wallClockFunction = Date.now, initialState, onTick } = options;
22
+ let lastWallTime = initialState?.wallTime ?? 0;
23
+ let lastCounter = initialState?.counter ?? 0;
24
+ function emit() {
25
+ if (onTick) onTick({ wallTime: lastWallTime, counter: lastCounter });
26
+ }
27
+ function now() {
28
+ const physicalTime = wallClockFunction();
29
+ if (physicalTime > lastWallTime) {
30
+ lastWallTime = physicalTime;
31
+ lastCounter = 0;
32
+ } else {
33
+ lastCounter++;
34
+ }
35
+ emit();
36
+ return { wallTime: lastWallTime, counter: lastCounter, nodeId };
37
+ }
38
+ function send() {
39
+ return now();
40
+ }
41
+ function receive(remote) {
42
+ const physicalTime = wallClockFunction();
43
+ if (physicalTime > lastWallTime && physicalTime > remote.wallTime) {
44
+ lastWallTime = physicalTime;
45
+ lastCounter = 0;
46
+ } else if (remote.wallTime > lastWallTime) {
47
+ lastWallTime = remote.wallTime;
48
+ lastCounter = remote.counter + 1;
49
+ } else if (lastWallTime === remote.wallTime) {
50
+ lastCounter = Math.max(lastCounter, remote.counter) + 1;
51
+ } else {
52
+ lastCounter++;
53
+ }
54
+ emit();
55
+ return { wallTime: lastWallTime, counter: lastCounter, nodeId };
56
+ }
57
+ return { now, send, receive };
58
+ }
59
+
60
+ // src/hlc/compare.ts
61
+ var ZERO_HLC = { wallTime: 0, counter: 0, nodeId: "" };
62
+ function compareHLC(a, b) {
63
+ if (a.wallTime < b.wallTime) return -1;
64
+ if (a.wallTime > b.wallTime) return 1;
65
+ if (a.counter < b.counter) return -1;
66
+ if (a.counter > b.counter) return 1;
67
+ if (a.nodeId < b.nodeId) return -1;
68
+ if (a.nodeId > b.nodeId) return 1;
69
+ return 0;
70
+ }
71
+ function maxHLC(a, b) {
72
+ return compareHLC(a, b) >= 0 ? a : b;
73
+ }
74
+
75
+ // src/hlc/serialize.ts
76
+ var SEPARATOR = ":";
77
+ function serializeHLC(timestamp) {
78
+ const wallTimeHex = timestamp.wallTime.toString(16).padStart(12, "0");
79
+ const counterHex = timestamp.counter.toString(16).padStart(4, "0");
80
+ return `${wallTimeHex}${SEPARATOR}${counterHex}${SEPARATOR}${timestamp.nodeId}`;
81
+ }
82
+ function deserializeHLC(serializedString) {
83
+ const parts = serializedString.split(SEPARATOR);
84
+ if (parts.length !== 3) {
85
+ throw new Error(`Invalid HLC timestamp string: ${serializedString}`);
86
+ }
87
+ return {
88
+ wallTime: parseInt(parts[0], 16),
89
+ counter: parseInt(parts[1], 16),
90
+ nodeId: parts[2]
91
+ };
92
+ }
93
+
94
+ // src/records/builders.ts
95
+ function createDataRecord(input, clock) {
96
+ const now = clock.now();
97
+ return {
98
+ id: generateId(),
99
+ kind: "data",
100
+ type: input.type,
101
+ createdAt: now,
102
+ updatedAt: now,
103
+ ownerId: input.ownerId,
104
+ deletedAt: null,
105
+ version: 1,
106
+ contentHash: input.contentHash,
107
+ objectStorageKey: input.objectStorageKey,
108
+ mimeType: input.mimeType,
109
+ sizeBytes: input.sizeBytes,
110
+ originalFilename: input.originalFilename ?? null,
111
+ originAppId: input.originAppId,
112
+ parentId: input.parentId ?? null
113
+ };
114
+ }
115
+
116
+ // src/schema/registry.ts
117
+ function createTypeRegistry() {
118
+ const types = /* @__PURE__ */ new Map();
119
+ return {
120
+ register(definition) {
121
+ const key = `${definition.namespace}:${definition.name}`;
122
+ if (types.has(key)) {
123
+ throw new Error(`Type "${key}" is already registered`);
124
+ }
125
+ types.set(key, definition);
126
+ },
127
+ get(namespace, name) {
128
+ return types.get(`${namespace}:${name}`);
129
+ },
130
+ getByKey(key) {
131
+ return types.get(key);
132
+ },
133
+ has(namespace, name) {
134
+ return types.has(`${namespace}:${name}`);
135
+ },
136
+ list() {
137
+ return Array.from(types.values());
138
+ }
139
+ };
140
+ }
141
+
142
+ // src/schema/validator.ts
143
+ import * as v from "valibot";
144
+ var hlcTimestampSchema = v.object({
145
+ wallTime: v.pipe(v.number(), v.integer(), v.minValue(0)),
146
+ counter: v.pipe(v.number(), v.integer(), v.minValue(0)),
147
+ nodeId: v.pipe(v.string(), v.minLength(1))
148
+ });
149
+ var baseRecordSchema = v.object({
150
+ id: v.pipe(v.string(), v.length(26)),
151
+ type: v.pipe(v.string(), v.minLength(1)),
152
+ createdAt: hlcTimestampSchema,
153
+ updatedAt: hlcTimestampSchema,
154
+ ownerId: v.pipe(v.string(), v.minLength(1)),
155
+ deletedAt: v.nullable(hlcTimestampSchema),
156
+ version: v.pipe(v.number(), v.integer(), v.minValue(1))
157
+ });
158
+ var dataRecordSchema = v.object({
159
+ ...baseRecordSchema.entries,
160
+ kind: v.literal("data"),
161
+ contentHash: v.pipe(v.string(), v.minLength(1)),
162
+ objectStorageKey: v.pipe(v.string(), v.minLength(1)),
163
+ mimeType: v.pipe(v.string(), v.minLength(1)),
164
+ sizeBytes: v.pipe(v.number(), v.integer(), v.minValue(0)),
165
+ originalFilename: v.nullable(v.string()),
166
+ originAppId: v.pipe(v.string(), v.minLength(1)),
167
+ parentId: v.nullable(v.string())
168
+ });
169
+ function validateDataRecord(data) {
170
+ return v.safeParse(dataRecordSchema, data);
171
+ }
172
+
173
+ // src/types/errors.ts
174
+ var StarkeepError = class extends Error {
175
+ constructor(message, code, cause) {
176
+ super(message);
177
+ this.code = code;
178
+ this.cause = cause;
179
+ this.name = "StarkeepError";
180
+ }
181
+ };
182
+ var ValidationError = class extends StarkeepError {
183
+ constructor(message, cause) {
184
+ super(message, "VALIDATION_ERROR", cause);
185
+ this.name = "ValidationError";
186
+ }
187
+ };
188
+ var NotFoundError = class extends StarkeepError {
189
+ constructor(entity, id) {
190
+ super(`${entity} not found: ${id}`, "NOT_FOUND");
191
+ this.name = "NotFoundError";
192
+ }
193
+ };
194
+ var ConflictError = class extends StarkeepError {
195
+ constructor(message) {
196
+ super(message, "CONFLICT");
197
+ this.name = "ConflictError";
198
+ }
199
+ };
200
+
201
+ // src/types/common.ts
202
+ function ok(value) {
203
+ return { ok: true, value };
204
+ }
205
+ function err(error) {
206
+ return { ok: false, error };
207
+ }
208
+
209
+ // src/types/core-types.ts
210
+ var IMAGE_METADATA_COLUMNS = [
211
+ { name: "width", type: "integer" },
212
+ { name: "height", type: "integer" },
213
+ { name: "color_space", type: "text" },
214
+ { name: "orientation", type: "integer" },
215
+ { name: "captured_at", type: "timestamp" },
216
+ { name: "camera_make", type: "text" },
217
+ { name: "camera_model", type: "text" },
218
+ { name: "lens_model", type: "text" },
219
+ { name: "f_number", type: "real" },
220
+ { name: "exposure_time", type: "text" },
221
+ { name: "iso", type: "integer" },
222
+ { name: "focal_length_mm", type: "real" },
223
+ { name: "gps_lat", type: "real" },
224
+ { name: "gps_lon", type: "real" }
225
+ ];
226
+ var VIDEO_METADATA_COLUMNS = [
227
+ { name: "width", type: "integer" },
228
+ { name: "height", type: "integer" },
229
+ { name: "duration_ms", type: "bigint" },
230
+ { name: "frame_rate", type: "real" },
231
+ { name: "video_codec", type: "text" },
232
+ { name: "audio_codec", type: "text" },
233
+ { name: "bitrate", type: "bigint" },
234
+ { name: "captured_at", type: "timestamp" },
235
+ { name: "gps_lat", type: "real" },
236
+ { name: "gps_lon", type: "real" }
237
+ ];
238
+ var AUDIO_METADATA_COLUMNS = [
239
+ { name: "duration_ms", type: "bigint" },
240
+ { name: "sample_rate", type: "integer" },
241
+ { name: "channels", type: "integer" },
242
+ { name: "bitrate", type: "bigint" },
243
+ { name: "codec", type: "text" },
244
+ { name: "title", type: "text" },
245
+ { name: "artist", type: "text" },
246
+ { name: "album", type: "text" },
247
+ { name: "track_number", type: "integer" },
248
+ { name: "year", type: "integer" },
249
+ { name: "genre", type: "text" }
250
+ ];
251
+ var DOCUMENT_METADATA_COLUMNS = [
252
+ { name: "page_count", type: "integer" },
253
+ { name: "word_count", type: "integer" },
254
+ { name: "author", type: "text" },
255
+ { name: "title", type: "text" },
256
+ { name: "created_at", type: "timestamp" },
257
+ { name: "modified_at", type: "timestamp" },
258
+ { name: "language", type: "text" }
259
+ ];
260
+ var TEXT_METADATA_COLUMNS = [
261
+ { name: "line_count", type: "integer" },
262
+ { name: "encoding", type: "text" }
263
+ ];
264
+ var CODE_METADATA_COLUMNS = [
265
+ { name: "line_count", type: "integer" },
266
+ { name: "encoding", type: "text" }
267
+ ];
268
+ var FONT_METADATA_COLUMNS = [
269
+ { name: "family", type: "text" },
270
+ { name: "subfamily", type: "text" },
271
+ { name: "weight", type: "integer" },
272
+ { name: "style", type: "text" },
273
+ { name: "format", type: "text" }
274
+ ];
275
+ var ARCHIVE_METADATA_COLUMNS = [
276
+ { name: "entry_count", type: "integer" },
277
+ { name: "uncompressed_bytes", type: "bigint" },
278
+ { name: "compression", type: "text" }
279
+ ];
280
+ var DATA_METADATA_COLUMNS = [
281
+ { name: "row_count", type: "bigint" },
282
+ { name: "column_count", type: "integer" },
283
+ { name: "schema_json", type: "text" }
284
+ ];
285
+ var MODEL3D_METADATA_COLUMNS = [
286
+ { name: "vertex_count", type: "bigint" },
287
+ { name: "face_count", type: "bigint" },
288
+ { name: "has_textures", type: "boolean" },
289
+ { name: "has_animation", type: "boolean" }
290
+ ];
291
+ var CATEGORIES = [
292
+ { id: "image", description: "Raster and vector still images. Bytes in object storage; metadata holds dimensions, capture time, EXIF, orientation.", metadataColumns: IMAGE_METADATA_COLUMNS },
293
+ { id: "video", description: "Moving-picture containers.", metadataColumns: VIDEO_METADATA_COLUMNS },
294
+ { id: "audio", description: "Sound-only containers.", metadataColumns: AUDIO_METADATA_COLUMNS },
295
+ { id: "document", description: "Office-suite and structured documents meant for human reading (incl. markdown, html, spreadsheets).", metadataColumns: DOCUMENT_METADATA_COLUMNS },
296
+ { id: "text", description: "Plain-text formats: prose, config, structured serialization.", metadataColumns: TEXT_METADATA_COLUMNS },
297
+ { id: "code", description: "Programming-language source files.", metadataColumns: CODE_METADATA_COLUMNS },
298
+ { id: "font", description: "Typeface files.", metadataColumns: FONT_METADATA_COLUMNS },
299
+ { id: "archive", description: "Compressed bundles.", metadataColumns: ARCHIVE_METADATA_COLUMNS },
300
+ { id: "data", description: "Tabular / columnar / embedded-DB data files.", metadataColumns: DATA_METADATA_COLUMNS },
301
+ { id: "model3d", description: "3D meshes and scenes.", metadataColumns: MODEL3D_METADATA_COLUMNS },
302
+ { id: "other", description: "Terminal catch-all for unmapped or extension-less files. Drive-only; no metadata table; no installable-app grants.", metadataColumns: [] }
303
+ ];
304
+ var EXTENSIONS = {
305
+ // image
306
+ jpg: "image",
307
+ jpeg: "image",
308
+ png: "image",
309
+ gif: "image",
310
+ webp: "image",
311
+ heic: "image",
312
+ heif: "image",
313
+ avif: "image",
314
+ bmp: "image",
315
+ tiff: "image",
316
+ tif: "image",
317
+ svg: "image",
318
+ ico: "image",
319
+ // video
320
+ mp4: "video",
321
+ mov: "video",
322
+ m4v: "video",
323
+ avi: "video",
324
+ mkv: "video",
325
+ webm: "video",
326
+ mpg: "video",
327
+ mpeg: "video",
328
+ wmv: "video",
329
+ flv: "video",
330
+ // audio
331
+ mp3: "audio",
332
+ wav: "audio",
333
+ flac: "audio",
334
+ aac: "audio",
335
+ ogg: "audio",
336
+ oga: "audio",
337
+ opus: "audio",
338
+ m4a: "audio",
339
+ aiff: "audio",
340
+ wma: "audio",
341
+ // document
342
+ pdf: "document",
343
+ md: "document",
344
+ markdown: "document",
345
+ html: "document",
346
+ htm: "document",
347
+ doc: "document",
348
+ docx: "document",
349
+ xls: "document",
350
+ xlsx: "document",
351
+ ppt: "document",
352
+ pptx: "document",
353
+ odt: "document",
354
+ ods: "document",
355
+ odp: "document",
356
+ rtf: "document",
357
+ epub: "document",
358
+ pages: "document",
359
+ numbers: "document",
360
+ key: "document",
361
+ // text
362
+ txt: "text",
363
+ log: "text",
364
+ env: "text",
365
+ json: "text",
366
+ jsonc: "text",
367
+ xml: "text",
368
+ yaml: "text",
369
+ yml: "text",
370
+ toml: "text",
371
+ ini: "text",
372
+ conf: "text",
373
+ tex: "text",
374
+ rst: "text",
375
+ adoc: "text",
376
+ // code
377
+ js: "code",
378
+ mjs: "code",
379
+ cjs: "code",
380
+ ts: "code",
381
+ tsx: "code",
382
+ jsx: "code",
383
+ py: "code",
384
+ rb: "code",
385
+ go: "code",
386
+ rs: "code",
387
+ java: "code",
388
+ kt: "code",
389
+ swift: "code",
390
+ c: "code",
391
+ h: "code",
392
+ cpp: "code",
393
+ hpp: "code",
394
+ cs: "code",
395
+ php: "code",
396
+ sh: "code",
397
+ bash: "code",
398
+ zsh: "code",
399
+ fish: "code",
400
+ ps1: "code",
401
+ lua: "code",
402
+ r: "code",
403
+ sql: "code",
404
+ css: "code",
405
+ scss: "code",
406
+ sass: "code",
407
+ less: "code",
408
+ vue: "code",
409
+ svelte: "code",
410
+ dockerfile: "code",
411
+ gitignore: "code",
412
+ gitattributes: "code",
413
+ // font
414
+ ttf: "font",
415
+ otf: "font",
416
+ woff: "font",
417
+ woff2: "font",
418
+ eot: "font",
419
+ // archive
420
+ zip: "archive",
421
+ tar: "archive",
422
+ gz: "archive",
423
+ tgz: "archive",
424
+ bz2: "archive",
425
+ tbz2: "archive",
426
+ xz: "archive",
427
+ txz: "archive",
428
+ "7z": "archive",
429
+ rar: "archive",
430
+ zst: "archive",
431
+ // data
432
+ csv: "data",
433
+ tsv: "data",
434
+ parquet: "data",
435
+ arrow: "data",
436
+ feather: "data",
437
+ sqlite: "data",
438
+ sqlite3: "data",
439
+ db: "data",
440
+ jsonl: "data",
441
+ ndjson: "data",
442
+ hdf5: "data",
443
+ h5: "data",
444
+ orc: "data",
445
+ // model3d
446
+ obj: "model3d",
447
+ stl: "model3d",
448
+ gltf: "model3d",
449
+ glb: "model3d",
450
+ fbx: "model3d",
451
+ dae: "model3d",
452
+ "3ds": "model3d",
453
+ blend: "model3d",
454
+ ply: "model3d",
455
+ usd: "model3d",
456
+ usdz: "model3d"
457
+ };
458
+ var CATEGORY_IDS = CATEGORIES.map((c) => c.id);
459
+ var APP_GRANTABLE_CATEGORIES = CATEGORY_IDS.filter(
460
+ (c) => c !== "other"
461
+ );
462
+ var KNOWN_EXTENSIONS = new Set(Object.keys(EXTENSIONS));
463
+ function categoryOf(ext) {
464
+ const normalized = ext.toLowerCase().replace(/^\./, "");
465
+ return EXTENSIONS[normalized] ?? "other";
466
+ }
467
+ function getCategory(id) {
468
+ return CATEGORIES.find((c) => c.id === id);
469
+ }
470
+ function isCategoryId(id) {
471
+ return CATEGORIES.some((c) => c.id === id);
472
+ }
473
+ function pgColumnType(t) {
474
+ switch (t) {
475
+ case "integer":
476
+ return "integer";
477
+ case "bigint":
478
+ return "bigint";
479
+ case "real":
480
+ return "double precision";
481
+ case "text":
482
+ return "text";
483
+ case "timestamp":
484
+ return "timestamptz";
485
+ case "boolean":
486
+ return "boolean";
487
+ }
488
+ }
489
+ function sqliteColumnType(t) {
490
+ switch (t) {
491
+ case "integer":
492
+ return "INTEGER";
493
+ case "bigint":
494
+ return "INTEGER";
495
+ case "real":
496
+ return "REAL";
497
+ case "text":
498
+ return "TEXT";
499
+ case "timestamp":
500
+ return "TEXT";
501
+ case "boolean":
502
+ return "INTEGER";
503
+ }
504
+ }
505
+ function pgMetadataDdl(c) {
506
+ const cols = [
507
+ ` record_id text PRIMARY KEY`,
508
+ ...c.metadataColumns.map((col) => {
509
+ const nullSuffix = col.nullable === false ? " NOT NULL" : "";
510
+ return ` ${col.name} ${pgColumnType(col.type)}${nullSuffix}`;
511
+ })
512
+ ];
513
+ return `CREATE TABLE IF NOT EXISTS ${pgMetadataTableName(c.id)} (
514
+ ${cols.join(",\n")}
515
+ )`;
516
+ }
517
+ function sqliteMetadataDdl(c) {
518
+ const cols = [
519
+ ` record_id TEXT PRIMARY KEY`,
520
+ ...c.metadataColumns.map((col) => {
521
+ const nullSuffix = col.nullable === false ? " NOT NULL" : "";
522
+ return ` ${col.name} ${sqliteColumnType(col.type)}${nullSuffix}`;
523
+ })
524
+ ];
525
+ return `CREATE TABLE IF NOT EXISTS ${sqliteMetadataTableName(c.id)} (
526
+ ${cols.join(",\n")}
527
+ )`;
528
+ }
529
+ function sqliteMetadataTableName(typeOrCategory) {
530
+ const category = isCategoryId(typeOrCategory) ? typeOrCategory : categoryOf(typeOrCategory);
531
+ return `shared_record_${category}_metadata`;
532
+ }
533
+ function pgMetadataTableName(typeOrCategory) {
534
+ const category = isCategoryId(typeOrCategory) ? typeOrCategory : categoryOf(typeOrCategory);
535
+ return `shared.record_${category}_metadata`;
536
+ }
537
+
538
+ // src/storage/object-keys.ts
539
+ function dataRecordObjectKey(typeOrExt, contentHash) {
540
+ const shard = contentHash.slice(0, 2);
541
+ return `shared/${categoryOf(typeOrExt)}/${shard}/${contentHash}`;
542
+ }
543
+ function appSyncableObjectKey(appId, subKey) {
544
+ if (!appId || /[/\s]/.test(appId)) {
545
+ throw new Error(`appSyncableObjectKey: invalid appId ${JSON.stringify(appId)}`);
546
+ }
547
+ const prefix = `apps/${appId}/syncable/`;
548
+ const relative = subKey.startsWith(prefix) ? subKey.slice(prefix.length) : subKey;
549
+ if (relative.startsWith("/")) {
550
+ throw new Error(`appSyncableObjectKey: subKey must not start with "/" (got ${JSON.stringify(subKey)})`);
551
+ }
552
+ const segments = relative.split("/");
553
+ if (segments.some((s) => s === "..")) {
554
+ throw new Error(`appSyncableObjectKey: subKey must not contain ".." (got ${JSON.stringify(subKey)})`);
555
+ }
556
+ return `${prefix}${relative}`;
557
+ }
558
+ export {
559
+ APP_GRANTABLE_CATEGORIES,
560
+ CATEGORIES,
561
+ CATEGORY_IDS,
562
+ ConflictError,
563
+ EXTENSIONS,
564
+ KNOWN_EXTENSIONS,
565
+ NotFoundError,
566
+ StarkeepError,
567
+ ValidationError,
568
+ ZERO_HLC,
569
+ appSyncableObjectKey,
570
+ categoryOf,
571
+ compareHLC,
572
+ createDataRecord,
573
+ createHLCClock,
574
+ createStarkeepId,
575
+ createTypeRegistry,
576
+ dataRecordObjectKey,
577
+ dataRecordSchema,
578
+ deserializeHLC,
579
+ err,
580
+ generateId,
581
+ generateIdAt,
582
+ getCategory,
583
+ isCategoryId,
584
+ isStarkeepId,
585
+ maxHLC,
586
+ ok,
587
+ pgMetadataDdl,
588
+ pgMetadataTableName,
589
+ serializeHLC,
590
+ sqliteMetadataDdl,
591
+ sqliteMetadataTableName,
592
+ validateDataRecord
593
+ };
594
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/identifiers/types.ts","../src/identifiers/ulid.ts","../src/hlc/clock.ts","../src/hlc/compare.ts","../src/hlc/serialize.ts","../src/records/builders.ts","../src/schema/registry.ts","../src/schema/validator.ts","../src/types/errors.ts","../src/types/common.ts","../src/types/core-types.ts","../src/storage/object-keys.ts"],"sourcesContent":["export type StarkeepId = string & { readonly __brand: unique symbol };\n\nexport function createStarkeepId(value: string): StarkeepId {\n return value as StarkeepId;\n}\n\nexport function isStarkeepId(value: unknown): value is StarkeepId {\n return typeof value === \"string\" && value.length === 26;\n}\n","import { ulid, monotonicFactory } from \"ulidx\";\nimport type { StarkeepId } from \"./types.js\";\nimport { createStarkeepId } from \"./types.js\";\n\nconst monotonic = monotonicFactory();\n\nexport function generateId(): StarkeepId {\n return createStarkeepId(monotonic());\n}\n\nexport function generateIdAt(timestamp: number): StarkeepId {\n return createStarkeepId(ulid(timestamp));\n}\n","import type { HLCClock, HLCTimestamp } from \"./types.js\";\n\nexport interface ClockState {\n wallTime: number;\n counter: number;\n}\n\nexport interface ClockOptions {\n nodeId: string;\n wallClockFunction?: () => number;\n /**\n * Pre-seed the clock from persisted state so a post-restart HLC never\n * emits a timestamp earlier than one the node already sent.\n */\n initialState?: ClockState;\n /**\n * Invoked on every state change. Callers typically debounce and persist\n * to a SyncStateStore.\n */\n onTick?: (state: ClockState) => void;\n}\n\nexport function createHLCClock(options: ClockOptions): HLCClock {\n const { nodeId, wallClockFunction = Date.now, initialState, onTick } = options;\n\n let lastWallTime = initialState?.wallTime ?? 0;\n let lastCounter = initialState?.counter ?? 0;\n\n function emit(): void {\n if (onTick) onTick({ wallTime: lastWallTime, counter: lastCounter });\n }\n\n function now(): HLCTimestamp {\n const physicalTime = wallClockFunction();\n if (physicalTime > lastWallTime) {\n lastWallTime = physicalTime;\n lastCounter = 0;\n } else {\n lastCounter++;\n }\n emit();\n return { wallTime: lastWallTime, counter: lastCounter, nodeId };\n }\n\n function send(): HLCTimestamp {\n return now();\n }\n\n function receive(remote: HLCTimestamp): HLCTimestamp {\n const physicalTime = wallClockFunction();\n if (physicalTime > lastWallTime && physicalTime > remote.wallTime) {\n lastWallTime = physicalTime;\n lastCounter = 0;\n } else if (remote.wallTime > lastWallTime) {\n lastWallTime = remote.wallTime;\n lastCounter = remote.counter + 1;\n } else if (lastWallTime === remote.wallTime) {\n lastCounter = Math.max(lastCounter, remote.counter) + 1;\n } else {\n lastCounter++;\n }\n emit();\n return { wallTime: lastWallTime, counter: lastCounter, nodeId };\n }\n\n return { now, send, receive };\n}\n","import type { HLCTimestamp } from \"./types.js\";\n\n/** Identity element for HLC ordering. Useful as a default watermark / \"never seen\". */\nexport const ZERO_HLC: HLCTimestamp = { wallTime: 0, counter: 0, nodeId: \"\" };\n\nexport function compareHLC(a: HLCTimestamp, b: HLCTimestamp): -1 | 0 | 1 {\n if (a.wallTime < b.wallTime) return -1;\n if (a.wallTime > b.wallTime) return 1;\n if (a.counter < b.counter) return -1;\n if (a.counter > b.counter) return 1;\n if (a.nodeId < b.nodeId) return -1;\n if (a.nodeId > b.nodeId) return 1;\n return 0;\n}\n\nexport function maxHLC(a: HLCTimestamp, b: HLCTimestamp): HLCTimestamp {\n return compareHLC(a, b) >= 0 ? a : b;\n}\n","import type { HLCTimestamp } from \"./types.js\";\n\nconst SEPARATOR = \":\";\n\nexport function serializeHLC(timestamp: HLCTimestamp): string {\n const wallTimeHex = timestamp.wallTime.toString(16).padStart(12, \"0\");\n const counterHex = timestamp.counter.toString(16).padStart(4, \"0\");\n return `${wallTimeHex}${SEPARATOR}${counterHex}${SEPARATOR}${timestamp.nodeId}`;\n}\n\nexport function deserializeHLC(serializedString: string): HLCTimestamp {\n const parts = serializedString.split(SEPARATOR);\n if (parts.length !== 3) {\n throw new Error(`Invalid HLC timestamp string: ${serializedString}`);\n }\n return {\n wallTime: parseInt(parts[0], 16),\n counter: parseInt(parts[1], 16),\n nodeId: parts[2],\n };\n}\n","import type { StarkeepId } from \"../identifiers/types.js\";\nimport type { HLCClock } from \"../hlc/types.js\";\nimport { generateId } from \"../identifiers/ulid.js\";\nimport { type DataRecord } from \"./types.js\";\n\nexport interface CreateDataRecordInput {\n type: string;\n ownerId: string;\n originAppId: string;\n contentHash: string;\n objectStorageKey: string;\n mimeType: string;\n sizeBytes: number;\n originalFilename?: string | null;\n parentId?: StarkeepId | null;\n}\n\nexport function createDataRecord(input: CreateDataRecordInput, clock: HLCClock): DataRecord {\n const now = clock.now();\n return {\n id: generateId(),\n kind: \"data\",\n type: input.type,\n createdAt: now,\n updatedAt: now,\n ownerId: input.ownerId,\n deletedAt: null,\n version: 1,\n contentHash: input.contentHash,\n objectStorageKey: input.objectStorageKey,\n mimeType: input.mimeType,\n sizeBytes: input.sizeBytes,\n originalFilename: input.originalFilename ?? null,\n originAppId: input.originAppId,\n parentId: input.parentId ?? null,\n };\n}\n","import type * as v from \"valibot\";\n\nexport interface TypeDefinition {\n name: string;\n namespace: string;\n schema: v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>;\n}\n\nexport interface TypeRegistry {\n register(definition: TypeDefinition): void;\n get(namespace: string, name: string): TypeDefinition | undefined;\n getByKey(key: string): TypeDefinition | undefined;\n has(namespace: string, name: string): boolean;\n list(): TypeDefinition[];\n}\n\nexport function createTypeRegistry(): TypeRegistry {\n const types = new Map<string, TypeDefinition>();\n\n return {\n register(definition: TypeDefinition): void {\n const key = `${definition.namespace}:${definition.name}`;\n if (types.has(key)) {\n throw new Error(`Type \"${key}\" is already registered`);\n }\n types.set(key, definition);\n },\n\n get(namespace: string, name: string): TypeDefinition | undefined {\n return types.get(`${namespace}:${name}`);\n },\n\n getByKey(key: string): TypeDefinition | undefined {\n return types.get(key);\n },\n\n has(namespace: string, name: string): boolean {\n return types.has(`${namespace}:${name}`);\n },\n\n list(): TypeDefinition[] {\n return Array.from(types.values());\n },\n };\n}\n","import * as v from \"valibot\";\n\nconst hlcTimestampSchema = v.object({\n wallTime: v.pipe(v.number(), v.integer(), v.minValue(0)),\n counter: v.pipe(v.number(), v.integer(), v.minValue(0)),\n nodeId: v.pipe(v.string(), v.minLength(1)),\n});\n\nconst baseRecordSchema = v.object({\n id: v.pipe(v.string(), v.length(26)),\n type: v.pipe(v.string(), v.minLength(1)),\n createdAt: hlcTimestampSchema,\n updatedAt: hlcTimestampSchema,\n ownerId: v.pipe(v.string(), v.minLength(1)),\n deletedAt: v.nullable(hlcTimestampSchema),\n version: v.pipe(v.number(), v.integer(), v.minValue(1)),\n});\n\nexport const dataRecordSchema = v.object({\n ...baseRecordSchema.entries,\n kind: v.literal(\"data\"),\n contentHash: v.pipe(v.string(), v.minLength(1)),\n objectStorageKey: v.pipe(v.string(), v.minLength(1)),\n mimeType: v.pipe(v.string(), v.minLength(1)),\n sizeBytes: v.pipe(v.number(), v.integer(), v.minValue(0)),\n originalFilename: v.nullable(v.string()),\n originAppId: v.pipe(v.string(), v.minLength(1)),\n parentId: v.nullable(v.string()),\n});\n\nexport function validateDataRecord(data: unknown) {\n return v.safeParse(dataRecordSchema, data);\n}\n","export class StarkeepError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"StarkeepError\";\n }\n}\n\nexport class ValidationError extends StarkeepError {\n constructor(message: string, cause?: unknown) {\n super(message, \"VALIDATION_ERROR\", cause);\n this.name = \"ValidationError\";\n }\n}\n\nexport class NotFoundError extends StarkeepError {\n constructor(entity: string, id: string) {\n super(`${entity} not found: ${id}`, \"NOT_FOUND\");\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ConflictError extends StarkeepError {\n constructor(message: string) {\n super(message, \"CONFLICT\");\n this.name = \"ConflictError\";\n }\n}\n","export type Result<T, E = Error> =\n | { ok: true; value: T }\n | { ok: false; error: E };\n\nexport function ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\nexport function err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\nexport interface PaginationOptions {\n limit: number;\n cursor?: string;\n}\n\nexport interface PaginatedResult<T> {\n items: T[];\n nextCursor: string | null;\n hasMore: boolean;\n}\n","/**\n * Single source of truth for Starkeep's shared core type system.\n *\n * Two registries derived from one place:\n * - EXTENSIONS: lowercase file extension → mapped Category. Identification is\n * by extension; MIME is never authoritative.\n * - CATEGORIES: the user-facing organizational layer (mobile-style: Images,\n * Videos, Documents…). Each mapped category owns one metadata table holding\n * cross-format properties derivable from the file bytes.\n *\n * A record's `type` is the lowercase extension verbatim (e.g. \"jpg\", \"md\",\n * \"xyz\"), even when the extension is unmapped. Its category is derived:\n * `category = EXTENSIONS[ext] ?? \"other\"`. `other` is the terminal catch-all\n * for unmapped / extension-less files — Drive-only, no metadata table, and no\n * installable app can ever be granted it (apps may only declare extensions that\n * are present in EXTENSIONS, and the unmapped set IS the `other` set).\n *\n * Every relevant system — manifest validation, IAM emission, DSQL schema-init,\n * SQLite bootstrap, object-key construction, and the local data-server's access\n * path — derives its view from the registries below. Adding an extension or a\n * metadata column is a one-file edit here. There is no runtime registration\n * path — apps cannot register new types or extend metadata columns.\n */\n\nexport type LogicalColumnType =\n | \"integer\"\n | \"bigint\"\n | \"real\"\n | \"text\"\n | \"timestamp\"\n | \"boolean\";\n\nexport interface CoreTypeMetadataColumn {\n name: string;\n type: LogicalColumnType;\n /** Defaults to true. Set explicitly when the column must be NOT NULL. */\n nullable?: boolean;\n}\n\n/** The fixed set of categories. `other` is the terminal catch-all (last). */\nexport type Category =\n | \"image\"\n | \"video\"\n | \"audio\"\n | \"document\"\n | \"text\"\n | \"code\"\n | \"font\"\n | \"archive\"\n | \"data\"\n | \"model3d\"\n | \"other\";\n\nexport interface CategoryDef {\n id: Category;\n description: string;\n /** Cross-format metadata columns. Empty for `other` (no metadata table). */\n metadataColumns: CoreTypeMetadataColumn[];\n}\n\nconst IMAGE_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"width\", type: \"integer\" },\n { name: \"height\", type: \"integer\" },\n { name: \"color_space\", type: \"text\" },\n { name: \"orientation\", type: \"integer\" },\n { name: \"captured_at\", type: \"timestamp\" },\n { name: \"camera_make\", type: \"text\" },\n { name: \"camera_model\", type: \"text\" },\n { name: \"lens_model\", type: \"text\" },\n { name: \"f_number\", type: \"real\" },\n { name: \"exposure_time\", type: \"text\" },\n { name: \"iso\", type: \"integer\" },\n { name: \"focal_length_mm\", type: \"real\" },\n { name: \"gps_lat\", type: \"real\" },\n { name: \"gps_lon\", type: \"real\" },\n];\n\nconst VIDEO_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"width\", type: \"integer\" },\n { name: \"height\", type: \"integer\" },\n { name: \"duration_ms\", type: \"bigint\" },\n { name: \"frame_rate\", type: \"real\" },\n { name: \"video_codec\", type: \"text\" },\n { name: \"audio_codec\", type: \"text\" },\n { name: \"bitrate\", type: \"bigint\" },\n { name: \"captured_at\", type: \"timestamp\" },\n { name: \"gps_lat\", type: \"real\" },\n { name: \"gps_lon\", type: \"real\" },\n];\n\nconst AUDIO_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"duration_ms\", type: \"bigint\" },\n { name: \"sample_rate\", type: \"integer\" },\n { name: \"channels\", type: \"integer\" },\n { name: \"bitrate\", type: \"bigint\" },\n { name: \"codec\", type: \"text\" },\n { name: \"title\", type: \"text\" },\n { name: \"artist\", type: \"text\" },\n { name: \"album\", type: \"text\" },\n { name: \"track_number\", type: \"integer\" },\n { name: \"year\", type: \"integer\" },\n { name: \"genre\", type: \"text\" },\n];\n\nconst DOCUMENT_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"page_count\", type: \"integer\" },\n { name: \"word_count\", type: \"integer\" },\n { name: \"author\", type: \"text\" },\n { name: \"title\", type: \"text\" },\n { name: \"created_at\", type: \"timestamp\" },\n { name: \"modified_at\", type: \"timestamp\" },\n { name: \"language\", type: \"text\" },\n];\n\nconst TEXT_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"line_count\", type: \"integer\" },\n { name: \"encoding\", type: \"text\" },\n];\n\nconst CODE_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"line_count\", type: \"integer\" },\n { name: \"encoding\", type: \"text\" },\n];\n\nconst FONT_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"family\", type: \"text\" },\n { name: \"subfamily\", type: \"text\" },\n { name: \"weight\", type: \"integer\" },\n { name: \"style\", type: \"text\" },\n { name: \"format\", type: \"text\" },\n];\n\nconst ARCHIVE_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"entry_count\", type: \"integer\" },\n { name: \"uncompressed_bytes\", type: \"bigint\" },\n { name: \"compression\", type: \"text\" },\n];\n\nconst DATA_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"row_count\", type: \"bigint\" },\n { name: \"column_count\", type: \"integer\" },\n { name: \"schema_json\", type: \"text\" },\n];\n\nconst MODEL3D_METADATA_COLUMNS: CoreTypeMetadataColumn[] = [\n { name: \"vertex_count\", type: \"bigint\" },\n { name: \"face_count\", type: \"bigint\" },\n { name: \"has_textures\", type: \"boolean\" },\n { name: \"has_animation\", type: \"boolean\" },\n];\n\nexport const CATEGORIES: readonly CategoryDef[] = [\n { id: \"image\", description: \"Raster and vector still images. Bytes in object storage; metadata holds dimensions, capture time, EXIF, orientation.\", metadataColumns: IMAGE_METADATA_COLUMNS },\n { id: \"video\", description: \"Moving-picture containers.\", metadataColumns: VIDEO_METADATA_COLUMNS },\n { id: \"audio\", description: \"Sound-only containers.\", metadataColumns: AUDIO_METADATA_COLUMNS },\n { id: \"document\", description: \"Office-suite and structured documents meant for human reading (incl. markdown, html, spreadsheets).\", metadataColumns: DOCUMENT_METADATA_COLUMNS },\n { id: \"text\", description: \"Plain-text formats: prose, config, structured serialization.\", metadataColumns: TEXT_METADATA_COLUMNS },\n { id: \"code\", description: \"Programming-language source files.\", metadataColumns: CODE_METADATA_COLUMNS },\n { id: \"font\", description: \"Typeface files.\", metadataColumns: FONT_METADATA_COLUMNS },\n { id: \"archive\", description: \"Compressed bundles.\", metadataColumns: ARCHIVE_METADATA_COLUMNS },\n { id: \"data\", description: \"Tabular / columnar / embedded-DB data files.\", metadataColumns: DATA_METADATA_COLUMNS },\n { id: \"model3d\", description: \"3D meshes and scenes.\", metadataColumns: MODEL3D_METADATA_COLUMNS },\n { id: \"other\", description: \"Terminal catch-all for unmapped or extension-less files. Drive-only; no metadata table; no installable-app grants.\", metadataColumns: [] },\n];\n\n/**\n * Extension (lowercase, no dot) → mapped category. `other` is NEVER a value\n * here — it is exclusively the `?? \"other\"` fallback in `categoryOf`, which is\n * why no app can ever declare an `other` extension.\n */\nexport const EXTENSIONS: Readonly<Record<string, Exclude<Category, \"other\">>> = {\n // image\n jpg: \"image\", jpeg: \"image\", png: \"image\", gif: \"image\", webp: \"image\",\n heic: \"image\", heif: \"image\", avif: \"image\", bmp: \"image\", tiff: \"image\",\n tif: \"image\", svg: \"image\", ico: \"image\",\n // video\n mp4: \"video\", mov: \"video\", m4v: \"video\", avi: \"video\", mkv: \"video\",\n webm: \"video\", mpg: \"video\", mpeg: \"video\", wmv: \"video\", flv: \"video\",\n // audio\n mp3: \"audio\", wav: \"audio\", flac: \"audio\", aac: \"audio\", ogg: \"audio\",\n oga: \"audio\", opus: \"audio\", m4a: \"audio\", aiff: \"audio\", wma: \"audio\",\n // document\n pdf: \"document\", md: \"document\", markdown: \"document\", html: \"document\",\n htm: \"document\", doc: \"document\", docx: \"document\", xls: \"document\",\n xlsx: \"document\", ppt: \"document\", pptx: \"document\", odt: \"document\",\n ods: \"document\", odp: \"document\", rtf: \"document\", epub: \"document\",\n pages: \"document\", numbers: \"document\", key: \"document\",\n // text\n txt: \"text\", log: \"text\", env: \"text\", json: \"text\", jsonc: \"text\",\n xml: \"text\", yaml: \"text\", yml: \"text\", toml: \"text\", ini: \"text\",\n conf: \"text\", tex: \"text\", rst: \"text\", adoc: \"text\",\n // code\n js: \"code\", mjs: \"code\", cjs: \"code\", ts: \"code\", tsx: \"code\", jsx: \"code\",\n py: \"code\", rb: \"code\", go: \"code\", rs: \"code\", java: \"code\", kt: \"code\",\n swift: \"code\", c: \"code\", h: \"code\", cpp: \"code\", hpp: \"code\", cs: \"code\",\n php: \"code\", sh: \"code\", bash: \"code\", zsh: \"code\", fish: \"code\",\n ps1: \"code\", lua: \"code\", r: \"code\", sql: \"code\", css: \"code\", scss: \"code\",\n sass: \"code\", less: \"code\", vue: \"code\", svelte: \"code\",\n dockerfile: \"code\", gitignore: \"code\", gitattributes: \"code\",\n // font\n ttf: \"font\", otf: \"font\", woff: \"font\", woff2: \"font\", eot: \"font\",\n // archive\n zip: \"archive\", tar: \"archive\", gz: \"archive\", tgz: \"archive\",\n bz2: \"archive\", tbz2: \"archive\", xz: \"archive\", txz: \"archive\",\n \"7z\": \"archive\", rar: \"archive\", zst: \"archive\",\n // data\n csv: \"data\", tsv: \"data\", parquet: \"data\", arrow: \"data\", feather: \"data\",\n sqlite: \"data\", sqlite3: \"data\", db: \"data\", jsonl: \"data\", ndjson: \"data\",\n hdf5: \"data\", h5: \"data\", orc: \"data\",\n // model3d\n obj: \"model3d\", stl: \"model3d\", gltf: \"model3d\", glb: \"model3d\",\n fbx: \"model3d\", dae: \"model3d\", \"3ds\": \"model3d\", blend: \"model3d\",\n ply: \"model3d\", usd: \"model3d\", usdz: \"model3d\",\n};\n\nexport const CATEGORY_IDS: readonly Category[] = CATEGORIES.map((c) => c.id);\n\n/**\n * Categories an installable app may be granted — every category a real\n * extension can map to, i.e. all categories EXCEPT `other`. Drive's all-access\n * (`fileAccessAll`) covers `other` as well, via its `shared/*` IAM ceiling.\n */\nexport const APP_GRANTABLE_CATEGORIES: readonly Category[] = CATEGORY_IDS.filter(\n (c) => c !== \"other\",\n);\n\n/** The set of known (mapped) extensions. */\nexport const KNOWN_EXTENSIONS: ReadonlySet<string> = new Set(Object.keys(EXTENSIONS));\n\n/**\n * Derived category for a record's extension/type. Unmapped or empty → \"other\".\n * Accepts the extension with or without a leading dot, any case.\n */\nexport function categoryOf(ext: string): Category {\n const normalized = ext.toLowerCase().replace(/^\\./, \"\");\n return EXTENSIONS[normalized] ?? \"other\";\n}\n\nexport function getCategory(id: string): CategoryDef | undefined {\n return CATEGORIES.find((c) => c.id === id);\n}\n\nexport function isCategoryId(id: string): id is Category {\n return CATEGORIES.some((c) => c.id === id);\n}\n\nfunction pgColumnType(t: LogicalColumnType): string {\n switch (t) {\n case \"integer\": return \"integer\";\n case \"bigint\": return \"bigint\";\n case \"real\": return \"double precision\";\n case \"text\": return \"text\";\n case \"timestamp\": return \"timestamptz\";\n case \"boolean\": return \"boolean\";\n }\n}\n\nfunction sqliteColumnType(t: LogicalColumnType): string {\n switch (t) {\n case \"integer\": return \"INTEGER\";\n case \"bigint\": return \"INTEGER\";\n case \"real\": return \"REAL\";\n case \"text\": return \"TEXT\";\n case \"timestamp\": return \"TEXT\";\n case \"boolean\": return \"INTEGER\";\n }\n}\n\n/**\n * Emits a `CREATE TABLE IF NOT EXISTS shared.record_<category>_metadata`\n * statement for DSQL. Single non-PL/pgSQL statement, no FK constraints — see\n * `dsql-schema-init.ts` for the DSQL surface caveats. Callers must skip the\n * `other` category (no metadata table).\n */\nexport function pgMetadataDdl(c: CategoryDef): string {\n const cols = [\n ` record_id text PRIMARY KEY`,\n ...c.metadataColumns.map((col) => {\n const nullSuffix = col.nullable === false ? \" NOT NULL\" : \"\";\n return ` ${col.name} ${pgColumnType(col.type)}${nullSuffix}`;\n }),\n ];\n return `CREATE TABLE IF NOT EXISTS ${pgMetadataTableName(c.id)} (\\n${cols.join(\",\\n\")}\\n )`;\n}\n\n/**\n * Emits a `CREATE TABLE IF NOT EXISTS shared_record_<category>_metadata`\n * statement for the local SQLite bootstrap. Callers must skip the `other`\n * category (no metadata table).\n */\nexport function sqliteMetadataDdl(c: CategoryDef): string {\n const cols = [\n ` record_id TEXT PRIMARY KEY`,\n ...c.metadataColumns.map((col) => {\n const nullSuffix = col.nullable === false ? \" NOT NULL\" : \"\";\n return ` ${col.name} ${sqliteColumnType(col.type)}${nullSuffix}`;\n }),\n ];\n return `CREATE TABLE IF NOT EXISTS ${sqliteMetadataTableName(c.id)} (\\n${cols.join(\",\\n\")}\\n )`;\n}\n\n/**\n * Returns the SQLite metadata table name for a record's type/extension or a\n * category id. The category is derived when an extension is passed, so storage\n * adapters that hold only `record.type` route to the correct per-category\n * table. Passing the literal `\"other\"` (or an unmapped extension) yields the\n * `other` table name, which is never created — callers must not write metadata\n * for `other` records.\n */\nexport function sqliteMetadataTableName(typeOrCategory: string): string {\n const category = isCategoryId(typeOrCategory) ? typeOrCategory : categoryOf(typeOrCategory);\n return `shared_record_${category}_metadata`;\n}\n\n/** DSQL/Postgres counterpart of {@link sqliteMetadataTableName}. */\nexport function pgMetadataTableName(typeOrCategory: string): string {\n const category = isCategoryId(typeOrCategory) ? typeOrCategory : categoryOf(typeOrCategory);\n return `shared.record_${category}_metadata`;\n}\n","// Object-storage key construction. Single source of truth for both the\n// local SDK and the cloud Lambda handler so the two stay aligned.\n//\n// Two namespaces:\n// shared/<category>/<2-char>/<hash> data record blobs, bucketed by the\n// derived category (image, document, …,\n// other). Governed by the per-app\n// access path + the per-category IAM\n// ceiling (shared/<category>/* per\n// granted category; Drive gets shared/*).\n// apps/<appId>/syncable/<...> app-specific syncable files, owned by\n// the named app, synced as a unit with\n// the rest of that app's syncable data\n//\n// The prefix is determined by what is being stored, NOT by who is writing it.\n// A `kind:\"data\"` record blob always lives under `shared/<category>/...`, even\n// when an app with `readwrite` access produced it — that's how a different app\n// with read access to the same category can resolve the key under its own IAM\n// grants, and it keeps the prefix set bounded (~11) so `other`/unmapped files\n// are enumerable. The system does not provide an app-private non-syncable\n// namespace; apps that want such storage handle it themselves.\n\nimport { categoryOf } from \"../types/core-types.js\";\n\n// `typeOrExt` is the record's `type` (lowercase extension). The category is\n// derived here so the key stays category-bucketed and unmapped/extension-less\n// records land under `shared/other/...`.\nexport function dataRecordObjectKey(typeOrExt: string, contentHash: string): string {\n const shard = contentHash.slice(0, 2);\n return `shared/${categoryOf(typeOrExt)}/${shard}/${contentHash}`;\n}\n\n// Build the canonical object key for an app's syncable file. `subKey` is the\n// app-relative path under apps/<appId>/syncable/. Idempotent if the caller\n// already passed a fully qualified key. Rejects keys that would escape the\n// namespace (`..` segments, absolute paths).\nexport function appSyncableObjectKey(appId: string, subKey: string): string {\n if (!appId || /[/\\s]/.test(appId)) {\n throw new Error(`appSyncableObjectKey: invalid appId ${JSON.stringify(appId)}`);\n }\n const prefix = `apps/${appId}/syncable/`;\n const relative = subKey.startsWith(prefix) ? subKey.slice(prefix.length) : subKey;\n if (relative.startsWith(\"/\")) {\n throw new Error(`appSyncableObjectKey: subKey must not start with \"/\" (got ${JSON.stringify(subKey)})`);\n }\n const segments = relative.split(\"/\");\n if (segments.some((s) => s === \"..\")) {\n throw new Error(`appSyncableObjectKey: subKey must not contain \"..\" (got ${JSON.stringify(subKey)})`);\n }\n return `${prefix}${relative}`;\n}\n"],"mappings":";AAEO,SAAS,iBAAiB,OAA2B;AAC1D,SAAO;AACT;AAEO,SAAS,aAAa,OAAqC;AAChE,SAAO,OAAO,UAAU,YAAY,MAAM,WAAW;AACvD;;;ACRA,SAAS,MAAM,wBAAwB;AAIvC,IAAM,YAAY,iBAAiB;AAE5B,SAAS,aAAyB;AACvC,SAAO,iBAAiB,UAAU,CAAC;AACrC;AAEO,SAAS,aAAa,WAA+B;AAC1D,SAAO,iBAAiB,KAAK,SAAS,CAAC;AACzC;;;ACUO,SAAS,eAAe,SAAiC;AAC9D,QAAM,EAAE,QAAQ,oBAAoB,KAAK,KAAK,cAAc,OAAO,IAAI;AAEvE,MAAI,eAAe,cAAc,YAAY;AAC7C,MAAI,cAAc,cAAc,WAAW;AAE3C,WAAS,OAAa;AACpB,QAAI,OAAQ,QAAO,EAAE,UAAU,cAAc,SAAS,YAAY,CAAC;AAAA,EACrE;AAEA,WAAS,MAAoB;AAC3B,UAAM,eAAe,kBAAkB;AACvC,QAAI,eAAe,cAAc;AAC/B,qBAAe;AACf,oBAAc;AAAA,IAChB,OAAO;AACL;AAAA,IACF;AACA,SAAK;AACL,WAAO,EAAE,UAAU,cAAc,SAAS,aAAa,OAAO;AAAA,EAChE;AAEA,WAAS,OAAqB;AAC5B,WAAO,IAAI;AAAA,EACb;AAEA,WAAS,QAAQ,QAAoC;AACnD,UAAM,eAAe,kBAAkB;AACvC,QAAI,eAAe,gBAAgB,eAAe,OAAO,UAAU;AACjE,qBAAe;AACf,oBAAc;AAAA,IAChB,WAAW,OAAO,WAAW,cAAc;AACzC,qBAAe,OAAO;AACtB,oBAAc,OAAO,UAAU;AAAA,IACjC,WAAW,iBAAiB,OAAO,UAAU;AAC3C,oBAAc,KAAK,IAAI,aAAa,OAAO,OAAO,IAAI;AAAA,IACxD,OAAO;AACL;AAAA,IACF;AACA,SAAK;AACL,WAAO,EAAE,UAAU,cAAc,SAAS,aAAa,OAAO;AAAA,EAChE;AAEA,SAAO,EAAE,KAAK,MAAM,QAAQ;AAC9B;;;AC/DO,IAAM,WAAyB,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG;AAErE,SAAS,WAAW,GAAiB,GAA6B;AACvE,MAAI,EAAE,WAAW,EAAE,SAAU,QAAO;AACpC,MAAI,EAAE,WAAW,EAAE,SAAU,QAAO;AACpC,MAAI,EAAE,UAAU,EAAE,QAAS,QAAO;AAClC,MAAI,EAAE,UAAU,EAAE,QAAS,QAAO;AAClC,MAAI,EAAE,SAAS,EAAE,OAAQ,QAAO;AAChC,MAAI,EAAE,SAAS,EAAE,OAAQ,QAAO;AAChC,SAAO;AACT;AAEO,SAAS,OAAO,GAAiB,GAA+B;AACrE,SAAO,WAAW,GAAG,CAAC,KAAK,IAAI,IAAI;AACrC;;;ACfA,IAAM,YAAY;AAEX,SAAS,aAAa,WAAiC;AAC5D,QAAM,cAAc,UAAU,SAAS,SAAS,EAAE,EAAE,SAAS,IAAI,GAAG;AACpE,QAAM,aAAa,UAAU,QAAQ,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACjE,SAAO,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,MAAM;AAC/E;AAEO,SAAS,eAAe,kBAAwC;AACrE,QAAM,QAAQ,iBAAiB,MAAM,SAAS;AAC9C,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,iCAAiC,gBAAgB,EAAE;AAAA,EACrE;AACA,SAAO;AAAA,IACL,UAAU,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC/B,SAAS,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC9B,QAAQ,MAAM,CAAC;AAAA,EACjB;AACF;;;ACHO,SAAS,iBAAiB,OAA8B,OAA6B;AAC1F,QAAM,MAAM,MAAM,IAAI;AACtB,SAAO;AAAA,IACL,IAAI,WAAW;AAAA,IACf,MAAM;AAAA,IACN,MAAM,MAAM;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,IACX,SAAS;AAAA,IACT,aAAa,MAAM;AAAA,IACnB,kBAAkB,MAAM;AAAA,IACxB,UAAU,MAAM;AAAA,IAChB,WAAW,MAAM;AAAA,IACjB,kBAAkB,MAAM,oBAAoB;AAAA,IAC5C,aAAa,MAAM;AAAA,IACnB,UAAU,MAAM,YAAY;AAAA,EAC9B;AACF;;;ACpBO,SAAS,qBAAmC;AACjD,QAAM,QAAQ,oBAAI,IAA4B;AAE9C,SAAO;AAAA,IACL,SAAS,YAAkC;AACzC,YAAM,MAAM,GAAG,WAAW,SAAS,IAAI,WAAW,IAAI;AACtD,UAAI,MAAM,IAAI,GAAG,GAAG;AAClB,cAAM,IAAI,MAAM,SAAS,GAAG,yBAAyB;AAAA,MACvD;AACA,YAAM,IAAI,KAAK,UAAU;AAAA,IAC3B;AAAA,IAEA,IAAI,WAAmB,MAA0C;AAC/D,aAAO,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,EAAE;AAAA,IACzC;AAAA,IAEA,SAAS,KAAyC;AAChD,aAAO,MAAM,IAAI,GAAG;AAAA,IACtB;AAAA,IAEA,IAAI,WAAmB,MAAuB;AAC5C,aAAO,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,EAAE;AAAA,IACzC;AAAA,IAEA,OAAyB;AACvB,aAAO,MAAM,KAAK,MAAM,OAAO,CAAC;AAAA,IAClC;AAAA,EACF;AACF;;;AC5CA,YAAY,OAAO;AAEnB,IAAM,qBAAuB,SAAO;AAAA,EAClC,UAAY,OAAO,SAAO,GAAK,UAAQ,GAAK,WAAS,CAAC,CAAC;AAAA,EACvD,SAAW,OAAO,SAAO,GAAK,UAAQ,GAAK,WAAS,CAAC,CAAC;AAAA,EACtD,QAAU,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAC3C,CAAC;AAED,IAAM,mBAAqB,SAAO;AAAA,EAChC,IAAM,OAAO,SAAO,GAAK,SAAO,EAAE,CAAC;AAAA,EACnC,MAAQ,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EACvC,WAAW;AAAA,EACX,WAAW;AAAA,EACX,SAAW,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EAC1C,WAAa,WAAS,kBAAkB;AAAA,EACxC,SAAW,OAAO,SAAO,GAAK,UAAQ,GAAK,WAAS,CAAC,CAAC;AACxD,CAAC;AAEM,IAAM,mBAAqB,SAAO;AAAA,EACvC,GAAG,iBAAiB;AAAA,EACpB,MAAQ,UAAQ,MAAM;AAAA,EACtB,aAAe,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EAC9C,kBAAoB,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EACnD,UAAY,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EAC3C,WAAa,OAAO,SAAO,GAAK,UAAQ,GAAK,WAAS,CAAC,CAAC;AAAA,EACxD,kBAAoB,WAAW,SAAO,CAAC;AAAA,EACvC,aAAe,OAAO,SAAO,GAAK,YAAU,CAAC,CAAC;AAAA,EAC9C,UAAY,WAAW,SAAO,CAAC;AACjC,CAAC;AAEM,SAAS,mBAAmB,MAAe;AAChD,SAAS,YAAU,kBAAkB,IAAI;AAC3C;;;AChCO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YACE,SACgB,MACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,cAA8B,cAAc;AAAA,EACjD,YAAY,SAAiB,OAAiB;AAC5C,UAAM,SAAS,oBAAoB,KAAK;AACxC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,gBAAN,cAA4B,cAAc;AAAA,EAC/C,YAAY,QAAgB,IAAY;AACtC,UAAM,GAAG,MAAM,eAAe,EAAE,IAAI,WAAW;AAC/C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,gBAAN,cAA4B,cAAc;AAAA,EAC/C,YAAY,SAAiB;AAC3B,UAAM,SAAS,UAAU;AACzB,SAAK,OAAO;AAAA,EACd;AACF;;;AC1BO,SAAS,GAAM,OAA4B;AAChD,SAAO,EAAE,IAAI,MAAM,MAAM;AAC3B;AAEO,SAAS,IAAO,OAA4B;AACjD,SAAO,EAAE,IAAI,OAAO,MAAM;AAC5B;;;ACkDA,IAAM,yBAAmD;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,EACjC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,EAClC,EAAE,MAAM,eAAe,MAAM,OAAO;AAAA,EACpC,EAAE,MAAM,eAAe,MAAM,UAAU;AAAA,EACvC,EAAE,MAAM,eAAe,MAAM,YAAY;AAAA,EACzC,EAAE,MAAM,eAAe,MAAM,OAAO;AAAA,EACpC,EAAE,MAAM,gBAAgB,MAAM,OAAO;AAAA,EACrC,EAAE,MAAM,cAAc,MAAM,OAAO;AAAA,EACnC,EAAE,MAAM,YAAY,MAAM,OAAO;AAAA,EACjC,EAAE,MAAM,iBAAiB,MAAM,OAAO;AAAA,EACtC,EAAE,MAAM,OAAO,MAAM,UAAU;AAAA,EAC/B,EAAE,MAAM,mBAAmB,MAAM,OAAO;AAAA,EACxC,EAAE,MAAM,WAAW,MAAM,OAAO;AAAA,EAChC,EAAE,MAAM,WAAW,MAAM,OAAO;AAClC;AAEA,IAAM,yBAAmD;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,EACjC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,EAClC,EAAE,MAAM,eAAe,MAAM,SAAS;AAAA,EACtC,EAAE,MAAM,cAAc,MAAM,OAAO;AAAA,EACnC,EAAE,MAAM,eAAe,MAAM,OAAO;AAAA,EACpC,EAAE,MAAM,eAAe,MAAM,OAAO;AAAA,EACpC,EAAE,MAAM,WAAW,MAAM,SAAS;AAAA,EAClC,EAAE,MAAM,eAAe,MAAM,YAAY;AAAA,EACzC,EAAE,MAAM,WAAW,MAAM,OAAO;AAAA,EAChC,EAAE,MAAM,WAAW,MAAM,OAAO;AAClC;AAEA,IAAM,yBAAmD;AAAA,EACvD,EAAE,MAAM,eAAe,MAAM,SAAS;AAAA,EACtC,EAAE,MAAM,eAAe,MAAM,UAAU;AAAA,EACvC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,EACpC,EAAE,MAAM,WAAW,MAAM,SAAS;AAAA,EAClC,EAAE,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9B,EAAE,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9B,EAAE,MAAM,UAAU,MAAM,OAAO;AAAA,EAC/B,EAAE,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9B,EAAE,MAAM,gBAAgB,MAAM,UAAU;AAAA,EACxC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,EAChC,EAAE,MAAM,SAAS,MAAM,OAAO;AAChC;AAEA,IAAM,4BAAsD;AAAA,EAC1D,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,EACtC,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,EACtC,EAAE,MAAM,UAAU,MAAM,OAAO;AAAA,EAC/B,EAAE,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9B,EAAE,MAAM,cAAc,MAAM,YAAY;AAAA,EACxC,EAAE,MAAM,eAAe,MAAM,YAAY;AAAA,EACzC,EAAE,MAAM,YAAY,MAAM,OAAO;AACnC;AAEA,IAAM,wBAAkD;AAAA,EACtD,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,EACtC,EAAE,MAAM,YAAY,MAAM,OAAO;AACnC;AAEA,IAAM,wBAAkD;AAAA,EACtD,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,EACtC,EAAE,MAAM,YAAY,MAAM,OAAO;AACnC;AAEA,IAAM,wBAAkD;AAAA,EACtD,EAAE,MAAM,UAAU,MAAM,OAAO;AAAA,EAC/B,EAAE,MAAM,aAAa,MAAM,OAAO;AAAA,EAClC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,EAClC,EAAE,MAAM,SAAS,MAAM,OAAO;AAAA,EAC9B,EAAE,MAAM,UAAU,MAAM,OAAO;AACjC;AAEA,IAAM,2BAAqD;AAAA,EACzD,EAAE,MAAM,eAAe,MAAM,UAAU;AAAA,EACvC,EAAE,MAAM,sBAAsB,MAAM,SAAS;AAAA,EAC7C,EAAE,MAAM,eAAe,MAAM,OAAO;AACtC;AAEA,IAAM,wBAAkD;AAAA,EACtD,EAAE,MAAM,aAAa,MAAM,SAAS;AAAA,EACpC,EAAE,MAAM,gBAAgB,MAAM,UAAU;AAAA,EACxC,EAAE,MAAM,eAAe,MAAM,OAAO;AACtC;AAEA,IAAM,2BAAqD;AAAA,EACzD,EAAE,MAAM,gBAAgB,MAAM,SAAS;AAAA,EACvC,EAAE,MAAM,cAAc,MAAM,SAAS;AAAA,EACrC,EAAE,MAAM,gBAAgB,MAAM,UAAU;AAAA,EACxC,EAAE,MAAM,iBAAiB,MAAM,UAAU;AAC3C;AAEO,IAAM,aAAqC;AAAA,EAChD,EAAE,IAAI,SAAS,aAAa,wHAAwH,iBAAiB,uBAAuB;AAAA,EAC5L,EAAE,IAAI,SAAS,aAAa,8BAA8B,iBAAiB,uBAAuB;AAAA,EAClG,EAAE,IAAI,SAAS,aAAa,0BAA0B,iBAAiB,uBAAuB;AAAA,EAC9F,EAAE,IAAI,YAAY,aAAa,uGAAuG,iBAAiB,0BAA0B;AAAA,EACjL,EAAE,IAAI,QAAQ,aAAa,gEAAgE,iBAAiB,sBAAsB;AAAA,EAClI,EAAE,IAAI,QAAQ,aAAa,sCAAsC,iBAAiB,sBAAsB;AAAA,EACxG,EAAE,IAAI,QAAQ,aAAa,mBAAmB,iBAAiB,sBAAsB;AAAA,EACrF,EAAE,IAAI,WAAW,aAAa,uBAAuB,iBAAiB,yBAAyB;AAAA,EAC/F,EAAE,IAAI,QAAQ,aAAa,gDAAgD,iBAAiB,sBAAsB;AAAA,EAClH,EAAE,IAAI,WAAW,aAAa,yBAAyB,iBAAiB,yBAAyB;AAAA,EACjG,EAAE,IAAI,SAAS,aAAa,sHAAsH,iBAAiB,CAAC,EAAE;AACxK;AAOO,IAAM,aAAmE;AAAA;AAAA,EAE9E,KAAK;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,MAAM;AAAA,EAC/D,MAAM;AAAA,EAAS,MAAM;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,MAAM;AAAA,EACjE,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA;AAAA,EAEjC,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA,EAC7D,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA;AAAA,EAE/D,KAAK;AAAA,EAAS,KAAK;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,KAAK;AAAA,EAC9D,KAAK;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA,EAAS,MAAM;AAAA,EAAS,KAAK;AAAA;AAAA,EAE/D,KAAK;AAAA,EAAY,IAAI;AAAA,EAAY,UAAU;AAAA,EAAY,MAAM;AAAA,EAC7D,KAAK;AAAA,EAAY,KAAK;AAAA,EAAY,MAAM;AAAA,EAAY,KAAK;AAAA,EACzD,MAAM;AAAA,EAAY,KAAK;AAAA,EAAY,MAAM;AAAA,EAAY,KAAK;AAAA,EAC1D,KAAK;AAAA,EAAY,KAAK;AAAA,EAAY,KAAK;AAAA,EAAY,MAAM;AAAA,EACzD,OAAO;AAAA,EAAY,SAAS;AAAA,EAAY,KAAK;AAAA;AAAA,EAE7C,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA,EAAQ,OAAO;AAAA,EAC5D,KAAK;AAAA,EAAQ,MAAM;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA,EAAQ,KAAK;AAAA,EAC3D,MAAM;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA;AAAA,EAE9C,IAAI;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,IAAI;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EACpE,IAAI;AAAA,EAAQ,IAAI;AAAA,EAAQ,IAAI;AAAA,EAAQ,IAAI;AAAA,EAAQ,MAAM;AAAA,EAAQ,IAAI;AAAA,EAClE,OAAO;AAAA,EAAQ,GAAG;AAAA,EAAQ,GAAG;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,IAAI;AAAA,EACnE,KAAK;AAAA,EAAQ,IAAI;AAAA,EAAQ,MAAM;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA,EAC1D,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,GAAG;AAAA,EAAQ,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA,EACrE,MAAM;AAAA,EAAQ,MAAM;AAAA,EAAQ,KAAK;AAAA,EAAQ,QAAQ;AAAA,EACjD,YAAY;AAAA,EAAQ,WAAW;AAAA,EAAQ,eAAe;AAAA;AAAA,EAEtD,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,MAAM;AAAA,EAAQ,OAAO;AAAA,EAAQ,KAAK;AAAA;AAAA,EAE5D,KAAK;AAAA,EAAW,KAAK;AAAA,EAAW,IAAI;AAAA,EAAW,KAAK;AAAA,EACpD,KAAK;AAAA,EAAW,MAAM;AAAA,EAAW,IAAI;AAAA,EAAW,KAAK;AAAA,EACrD,MAAM;AAAA,EAAW,KAAK;AAAA,EAAW,KAAK;AAAA;AAAA,EAEtC,KAAK;AAAA,EAAQ,KAAK;AAAA,EAAQ,SAAS;AAAA,EAAQ,OAAO;AAAA,EAAQ,SAAS;AAAA,EACnE,QAAQ;AAAA,EAAQ,SAAS;AAAA,EAAQ,IAAI;AAAA,EAAQ,OAAO;AAAA,EAAQ,QAAQ;AAAA,EACpE,MAAM;AAAA,EAAQ,IAAI;AAAA,EAAQ,KAAK;AAAA;AAAA,EAE/B,KAAK;AAAA,EAAW,KAAK;AAAA,EAAW,MAAM;AAAA,EAAW,KAAK;AAAA,EACtD,KAAK;AAAA,EAAW,KAAK;AAAA,EAAW,OAAO;AAAA,EAAW,OAAO;AAAA,EACzD,KAAK;AAAA,EAAW,KAAK;AAAA,EAAW,MAAM;AACxC;AAEO,IAAM,eAAoC,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAOpE,IAAM,2BAAgD,aAAa;AAAA,EACxE,CAAC,MAAM,MAAM;AACf;AAGO,IAAM,mBAAwC,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC;AAM7E,SAAS,WAAW,KAAuB;AAChD,QAAM,aAAa,IAAI,YAAY,EAAE,QAAQ,OAAO,EAAE;AACtD,SAAO,WAAW,UAAU,KAAK;AACnC;AAEO,SAAS,YAAY,IAAqC;AAC/D,SAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3C;AAEO,SAAS,aAAa,IAA4B;AACvD,SAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3C;AAEA,SAAS,aAAa,GAA8B;AAClD,UAAQ,GAAG;AAAA,IACT,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAW,aAAO;AAAA,EACzB;AACF;AAEA,SAAS,iBAAiB,GAA8B;AACtD,UAAQ,GAAG;AAAA,IACT,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAW,aAAO;AAAA,EACzB;AACF;AAQO,SAAS,cAAc,GAAwB;AACpD,QAAM,OAAO;AAAA,IACX;AAAA,IACA,GAAG,EAAE,gBAAgB,IAAI,CAAC,QAAQ;AAChC,YAAM,aAAa,IAAI,aAAa,QAAQ,cAAc;AAC1D,aAAO,YAAY,IAAI,IAAI,IAAI,aAAa,IAAI,IAAI,CAAC,GAAG,UAAU;AAAA,IACpE,CAAC;AAAA,EACH;AACA,SAAO,8BAA8B,oBAAoB,EAAE,EAAE,CAAC;AAAA,EAAO,KAAK,KAAK,KAAK,CAAC;AAAA;AACvF;AAOO,SAAS,kBAAkB,GAAwB;AACxD,QAAM,OAAO;AAAA,IACX;AAAA,IACA,GAAG,EAAE,gBAAgB,IAAI,CAAC,QAAQ;AAChC,YAAM,aAAa,IAAI,aAAa,QAAQ,cAAc;AAC1D,aAAO,SAAS,IAAI,IAAI,IAAI,iBAAiB,IAAI,IAAI,CAAC,GAAG,UAAU;AAAA,IACrE,CAAC;AAAA,EACH;AACA,SAAO,8BAA8B,wBAAwB,EAAE,EAAE,CAAC;AAAA,EAAO,KAAK,KAAK,KAAK,CAAC;AAAA;AAC3F;AAUO,SAAS,wBAAwB,gBAAgC;AACtE,QAAM,WAAW,aAAa,cAAc,IAAI,iBAAiB,WAAW,cAAc;AAC1F,SAAO,iBAAiB,QAAQ;AAClC;AAGO,SAAS,oBAAoB,gBAAgC;AAClE,QAAM,WAAW,aAAa,cAAc,IAAI,iBAAiB,WAAW,cAAc;AAC1F,SAAO,iBAAiB,QAAQ;AAClC;;;ACnSO,SAAS,oBAAoB,WAAmB,aAA6B;AAClF,QAAM,QAAQ,YAAY,MAAM,GAAG,CAAC;AACpC,SAAO,UAAU,WAAW,SAAS,CAAC,IAAI,KAAK,IAAI,WAAW;AAChE;AAMO,SAAS,qBAAqB,OAAe,QAAwB;AAC1E,MAAI,CAAC,SAAS,QAAQ,KAAK,KAAK,GAAG;AACjC,UAAM,IAAI,MAAM,uCAAuC,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,EAChF;AACA,QAAM,SAAS,QAAQ,KAAK;AAC5B,QAAM,WAAW,OAAO,WAAW,MAAM,IAAI,OAAO,MAAM,OAAO,MAAM,IAAI;AAC3E,MAAI,SAAS,WAAW,GAAG,GAAG;AAC5B,UAAM,IAAI,MAAM,6DAA6D,KAAK,UAAU,MAAM,CAAC,GAAG;AAAA,EACxG;AACA,QAAM,WAAW,SAAS,MAAM,GAAG;AACnC,MAAI,SAAS,KAAK,CAAC,MAAM,MAAM,IAAI,GAAG;AACpC,UAAM,IAAI,MAAM,2DAA2D,KAAK,UAAU,MAAM,CAAC,GAAG;AAAA,EACtG;AACA,SAAO,GAAG,MAAM,GAAG,QAAQ;AAC7B;","names":[]}