@asaidimu/anansi 1.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/index.js ADDED
@@ -0,0 +1,3170 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/types/migrations.ts
8
+ var migrations_exports = {};
9
+
10
+ // src/types/persistence.ts
11
+ var persistence_exports = {};
12
+
13
+ // src/types/registry.ts
14
+ var registry_exports = {};
15
+
16
+ // src/types/schema-definition.ts
17
+ var schema_definition_exports = {};
18
+
19
+ // src/lib/persistence/index.ts
20
+ var persistence_exports2 = {};
21
+ __export(persistence_exports2, {
22
+ default: () => createEphemeralPersistence
23
+ });
24
+ import { createEventBus as createEventBus2 } from "@asaidimu/events";
25
+
26
+ // src/lib/persistence/collection.ts
27
+ import { createEventBus } from "@asaidimu/events";
28
+ import {
29
+ createMatcher,
30
+ createPaginator,
31
+ createProjector,
32
+ createSorter
33
+ } from "@asaidimu/query";
34
+
35
+ // src/tools/patch.ts
36
+ var patch_exports = {};
37
+ __export(patch_exports, {
38
+ JsonPatchError: () => JsonPatchError,
39
+ applyPatch: () => applyPatch,
40
+ createPatch: () => createPatch,
41
+ normalizePath: () => normalizePath,
42
+ schemaChangeToPatch: () => schemaChangeToPatch
43
+ });
44
+ var JsonPatchError = class extends Error {
45
+ constructor(message, operation) {
46
+ super(message);
47
+ this.operation = operation;
48
+ this.name = "JsonPatchError";
49
+ }
50
+ };
51
+ function parseJsonPointer(path) {
52
+ const normalized = normalizePath(path);
53
+ if (normalized === "") return [];
54
+ return normalized.substring(1).split("/").map(unescapeJsonPointer);
55
+ }
56
+ function normalizePath(path) {
57
+ if (path === "" || path === "/") return "";
58
+ if (path.startsWith("/")) {
59
+ return "/" + path.substring(1).split("/").map(escapeJsonPointer).join("/");
60
+ }
61
+ return "/" + path.split(".").map(escapeJsonPointer).join("/");
62
+ }
63
+ function escapeJsonPointer(part) {
64
+ return part.replace(/~/g, "~0").replace(/\//g, "~1");
65
+ }
66
+ function unescapeJsonPointer(part) {
67
+ return part.replace(/~1/g, "/").replace(/~0/g, "~");
68
+ }
69
+ var pathCache = /* @__PURE__ */ new Map();
70
+ function navigateTo(obj, parts) {
71
+ let current = obj;
72
+ for (const part of parts) {
73
+ if (current === null || typeof current !== "object") {
74
+ throw new JsonPatchError(`Invalid path - parent not found at ${part}`);
75
+ }
76
+ if (Array.isArray(current)) {
77
+ const index = part === "-" ? current.length : parseInt(part);
78
+ if (isNaN(index) || index < 0 || index > current.length) {
79
+ throw new JsonPatchError(`Invalid array index: ${part}`);
80
+ }
81
+ current = current[index];
82
+ } else {
83
+ if (!current.hasOwnProperty(part)) {
84
+ throw new JsonPatchError(`Property ${part} not found`);
85
+ }
86
+ current = current[part];
87
+ }
88
+ }
89
+ return current;
90
+ }
91
+ function getValueAtPath(obj, path) {
92
+ const parts = pathCache.get(path) || parseJsonPointer(path);
93
+ pathCache.set(path, parts);
94
+ if (parts.length === 0) return obj;
95
+ const parent = navigateTo(obj, parts.slice(0, -1));
96
+ const key = parts[parts.length - 1];
97
+ if (Array.isArray(parent)) {
98
+ const index = parseInt(key);
99
+ if (isNaN(index) || index < 0 || index >= parent.length) {
100
+ throw new JsonPatchError(`Invalid array index: ${key}`);
101
+ }
102
+ return parent[index];
103
+ }
104
+ return parent[key];
105
+ }
106
+ function applyRemoveValue(obj, path, value) {
107
+ const parts = pathCache.get(path) || parseJsonPointer(path);
108
+ pathCache.set(path, parts);
109
+ const parent = navigateTo(obj, parts.slice(0, -1));
110
+ const key = parts[parts.length - 1];
111
+ if (Array.isArray(parent)) {
112
+ parent.splice(0, parent.length, ...parent.filter((item) => item !== value));
113
+ } else {
114
+ if (parent[key] === value) {
115
+ delete parent[key];
116
+ }
117
+ }
118
+ return obj;
119
+ }
120
+ function applyAdd(obj, path, value) {
121
+ const parts = pathCache.get(path) || parseJsonPointer(path);
122
+ pathCache.set(path, parts);
123
+ if (parts.length === 0) return value;
124
+ const parentPath = parts.slice(0, -1);
125
+ const key = parts[parts.length - 1];
126
+ const parent = navigateTo(obj, parentPath);
127
+ if (Array.isArray(parent)) {
128
+ if (key === "-") {
129
+ parent.push(value);
130
+ } else {
131
+ const index = parseInt(key);
132
+ if (index < 0 || index > parent.length) {
133
+ throw new JsonPatchError(`Invalid array index: ${key}`);
134
+ }
135
+ parent.splice(index, 0, value);
136
+ }
137
+ } else {
138
+ parent[key] = value;
139
+ }
140
+ return obj;
141
+ }
142
+ function applyRemove(obj, path) {
143
+ const parts = pathCache.get(path) || parseJsonPointer(path);
144
+ pathCache.set(path, parts);
145
+ if (parts.length === 0) return void 0;
146
+ const parent = navigateTo(obj, parts.slice(0, -1));
147
+ const key = parts[parts.length - 1];
148
+ if (Array.isArray(parent)) {
149
+ const index = parseInt(key);
150
+ parent.splice(index, 1);
151
+ } else {
152
+ delete parent[key];
153
+ }
154
+ return obj;
155
+ }
156
+ function applyPatch(target, patches) {
157
+ let result = JSON.parse(JSON.stringify(target));
158
+ for (const patch of patches) {
159
+ try {
160
+ switch (patch.op) {
161
+ case "add":
162
+ result = applyAdd(result, patch.path, patch.value);
163
+ break;
164
+ case "remove":
165
+ result = applyRemove(result, patch.path);
166
+ break;
167
+ case "removeValue":
168
+ result = applyRemoveValue(result, patch.path, patch.value);
169
+ break;
170
+ case "replace":
171
+ result = applyAdd(
172
+ applyRemove(result, patch.path),
173
+ patch.path,
174
+ patch.value
175
+ );
176
+ break;
177
+ case "copy": {
178
+ const value = getValueAtPath(result, patch.from);
179
+ result = applyAdd(
180
+ result,
181
+ patch.path,
182
+ JSON.parse(JSON.stringify(value))
183
+ );
184
+ break;
185
+ }
186
+ case "move": {
187
+ const value = getValueAtPath(result, patch.from);
188
+ result = applyAdd(result, patch.path, value);
189
+ result = applyRemove(result, patch.from);
190
+ break;
191
+ }
192
+ case "test": {
193
+ const actual = getValueAtPath(result, patch.path);
194
+ if (JSON.stringify(actual) !== JSON.stringify(patch.value)) {
195
+ throw new JsonPatchError("Test operation failed");
196
+ }
197
+ break;
198
+ }
199
+ default:
200
+ throw new JsonPatchError(
201
+ `Unsupported operation: ${patch.op}`
202
+ );
203
+ }
204
+ } catch (error) {
205
+ if (error instanceof JsonPatchError) {
206
+ error.operation = patch;
207
+ }
208
+ throw error;
209
+ }
210
+ }
211
+ return result;
212
+ }
213
+ function createPatch(oldObj, newObj) {
214
+ const patches = [];
215
+ generatePatches(oldObj, newObj, "", patches);
216
+ return patches;
217
+ }
218
+ function generatePatches(oldObj, newObj, path, patches) {
219
+ if (oldObj === newObj) return;
220
+ if (typeof oldObj !== typeof newObj || Array.isArray(oldObj) !== Array.isArray(newObj)) {
221
+ patches.push({ op: "replace", path, value: newObj });
222
+ return;
223
+ }
224
+ if (typeof oldObj === "object" && oldObj !== null) {
225
+ if (Array.isArray(oldObj)) {
226
+ handleArrays(oldObj, newObj, path, patches);
227
+ } else {
228
+ handleObjects(oldObj, newObj, path, patches);
229
+ }
230
+ } else if (oldObj !== newObj) {
231
+ patches.push({ op: "replace", path, value: newObj });
232
+ }
233
+ }
234
+ function handleArrays(oldArr, newArr, path, patches) {
235
+ const maxLen = Math.max(oldArr.length, newArr.length);
236
+ for (let i = 0; i < maxLen; i++) {
237
+ const currentPath = `${path}/${i}`;
238
+ if (i >= oldArr.length) {
239
+ patches.push({ op: "add", path: `${path}/-`, value: newArr[i] });
240
+ } else if (i >= newArr.length) {
241
+ patches.push({ op: "remove", path: currentPath });
242
+ } else {
243
+ generatePatches(oldArr[i], newArr[i], currentPath, patches);
244
+ }
245
+ }
246
+ }
247
+ function handleObjects(oldObj, newObj, path, patches) {
248
+ const seen = /* @__PURE__ */ new Set();
249
+ const oldKeys = Object.keys(oldObj);
250
+ const newKeys = Object.keys(newObj);
251
+ for (const key of oldKeys) {
252
+ const escapedKey = escapeJsonPointer(key);
253
+ const currentPath = path ? `${path}/${escapedKey}` : `/${escapedKey}`;
254
+ if (!newObj.hasOwnProperty(key)) {
255
+ patches.push({ op: "remove", path: currentPath });
256
+ } else {
257
+ generatePatches(
258
+ oldObj[key],
259
+ newObj[key],
260
+ currentPath,
261
+ patches
262
+ );
263
+ seen.add(key);
264
+ }
265
+ }
266
+ for (const key of newKeys) {
267
+ if (!seen.has(key)) {
268
+ const escapedKey = escapeJsonPointer(key);
269
+ const currentPath = path ? `${path}/${escapedKey}` : `/${escapedKey}`;
270
+ patches.push({
271
+ op: "add",
272
+ path: currentPath,
273
+ value: newObj[key]
274
+ });
275
+ }
276
+ }
277
+ }
278
+ function schemaChangeToPatch(change, schema) {
279
+ const patches = [];
280
+ switch (change.type) {
281
+ case "addField":
282
+ patches.push({
283
+ op: "add",
284
+ path: `/fields/${change.name}`,
285
+ value: change.definition
286
+ });
287
+ break;
288
+ case "removeField":
289
+ patches.push({
290
+ op: "remove",
291
+ path: `/fields/${change.name}`
292
+ });
293
+ break;
294
+ case "modifyField": {
295
+ const fieldPath = `/fields/${change.name}`;
296
+ Object.entries(change.changes).forEach(([key, value]) => {
297
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
298
+ patches.push({
299
+ op: "replace",
300
+ path: `${fieldPath}/${key}`,
301
+ value
302
+ });
303
+ } else {
304
+ patches.push({
305
+ op: "replace",
306
+ path: `${fieldPath}/${key}`,
307
+ value
308
+ });
309
+ }
310
+ });
311
+ break;
312
+ }
313
+ case "deprecateField":
314
+ patches.push({
315
+ op: "add",
316
+ path: `/fields/${change.name}/deprecated`,
317
+ value: true
318
+ });
319
+ break;
320
+ case "addIndex":
321
+ if (!schema.indexes) {
322
+ patches.push({
323
+ op: "add",
324
+ path: "/indexes",
325
+ value: []
326
+ });
327
+ }
328
+ patches.push({
329
+ op: "add",
330
+ path: "/indexes/-",
331
+ value: change.definition
332
+ });
333
+ break;
334
+ case "removeIndex": {
335
+ const indexIndex = schema.indexes?.findIndex(
336
+ (idx) => idx.name === change.name
337
+ );
338
+ if (indexIndex !== void 0 && indexIndex >= 0) {
339
+ patches.push({
340
+ op: "remove",
341
+ path: `/indexes/${indexIndex}`
342
+ });
343
+ }
344
+ break;
345
+ }
346
+ case "modifyIndex": {
347
+ const indexIndex = schema.indexes?.findIndex(
348
+ (idx) => idx.name === change.name
349
+ );
350
+ if (indexIndex !== void 0 && indexIndex >= 0) {
351
+ Object.entries(change.changes).forEach(([key, value]) => {
352
+ patches.push({
353
+ op: "replace",
354
+ path: `/indexes/${indexIndex}/${key}`,
355
+ value
356
+ });
357
+ });
358
+ }
359
+ break;
360
+ }
361
+ case "addConstraint":
362
+ if (!schema.constraints) {
363
+ patches.push({
364
+ op: "add",
365
+ path: "/constraints",
366
+ value: []
367
+ });
368
+ }
369
+ if (Array.isArray(change.constraint)) {
370
+ change.constraint.forEach((constraint) => {
371
+ patches.push({
372
+ op: "add",
373
+ path: "/constraints/-",
374
+ value: constraint
375
+ });
376
+ });
377
+ } else {
378
+ patches.push({
379
+ op: "add",
380
+ path: "/constraints/-",
381
+ value: change.constraint
382
+ });
383
+ }
384
+ break;
385
+ case "removeConstraint": {
386
+ const constraintIndex = schema.constraints?.findIndex(
387
+ (c) => Array.isArray(c) ? c.some((rule) => rule.name === change.name) : c.name === change.name
388
+ );
389
+ if (constraintIndex !== void 0 && constraintIndex >= 0) {
390
+ patches.push({
391
+ op: "remove",
392
+ path: `/constraints/${constraintIndex}`
393
+ });
394
+ }
395
+ break;
396
+ }
397
+ case "modifyConstraint": {
398
+ const constraintPath = findConstraintPath(schema, change.name);
399
+ if (constraintPath) {
400
+ Object.entries(change.changes).forEach(([key, value]) => {
401
+ patches.push({
402
+ op: "replace",
403
+ path: `${constraintPath}/${key}`,
404
+ value
405
+ });
406
+ });
407
+ }
408
+ break;
409
+ }
410
+ }
411
+ return patches;
412
+ }
413
+ function findConstraintPath(schema, name) {
414
+ if (!schema.constraints) return null;
415
+ for (let i = 0; i < schema.constraints.length; i++) {
416
+ const constraint = schema.constraints[i];
417
+ if (constraint.name === name) {
418
+ return `/constraints/${i}`;
419
+ }
420
+ if (isConstraintGroup(constraint)) {
421
+ const path = searchRules(constraint.rules, name);
422
+ if (path) {
423
+ return `/constraints/${i}${path}`;
424
+ }
425
+ }
426
+ }
427
+ return null;
428
+ }
429
+ function isConstraintGroup(obj) {
430
+ return obj && "operator" in obj && "rules" in obj;
431
+ }
432
+ function searchRules(rules, name) {
433
+ for (let i = 0; i < rules.length; i++) {
434
+ const rule = rules[i];
435
+ if ("name" in rule && rule.name === name) {
436
+ return `/rules/${i}`;
437
+ }
438
+ if (isConstraintGroup(rule)) {
439
+ const path = searchRules(rule.rules, name);
440
+ if (path) {
441
+ return `/rules/${i}${path}`;
442
+ }
443
+ }
444
+ }
445
+ return null;
446
+ }
447
+
448
+ // src/tools/merge.ts
449
+ var merge_exports = {};
450
+ __export(merge_exports, {
451
+ deepMerge: () => deepMerge
452
+ });
453
+ function deepMerge(target, update) {
454
+ const output = { ...target };
455
+ if (isObject(target) && isObject(update)) {
456
+ Object.keys(update).forEach((key) => {
457
+ if (isObject(update[key])) {
458
+ if (!(key in target)) {
459
+ Object.assign(output, { [key]: update[key] });
460
+ } else {
461
+ output[key] = deepMerge(
462
+ target[key],
463
+ update[key]
464
+ );
465
+ }
466
+ } else {
467
+ Object.assign(output, { [key]: update[key] });
468
+ }
469
+ });
470
+ }
471
+ return output;
472
+ }
473
+ function isObject(item) {
474
+ return item && typeof item === "object" && !Array.isArray(item);
475
+ }
476
+
477
+ // src/tools/validator.ts
478
+ var validator_exports = {};
479
+ __export(validator_exports, {
480
+ createStandardSchemaValidator: () => createStandardSchemaValidator
481
+ });
482
+ function createStandardSchemaValidator(schema, constraintsMap) {
483
+ const validateTypeWithErrors = (value, fieldName, fieldDef, path) => {
484
+ const issues = [];
485
+ switch (fieldDef.type) {
486
+ case "string":
487
+ if (typeof value !== "string") {
488
+ issues.push({
489
+ message: `Expected type string but received ${typeof value}.`,
490
+ path
491
+ });
492
+ }
493
+ break;
494
+ case "number":
495
+ if (typeof value !== "number") {
496
+ issues.push({
497
+ message: `Expected type number but received ${typeof value}.`,
498
+ path
499
+ });
500
+ }
501
+ break;
502
+ case "boolean":
503
+ if (typeof value !== "boolean") {
504
+ issues.push({
505
+ message: `Expected type boolean but received ${typeof value}.`,
506
+ path
507
+ });
508
+ }
509
+ break;
510
+ case "array":
511
+ if (!Array.isArray(value)) {
512
+ issues.push({
513
+ message: `Expected an array but received ${typeof value}.`,
514
+ path
515
+ });
516
+ } else if (!fieldDef.itemsType) {
517
+ issues.push({
518
+ message: `Expected itemsType for array ${fieldName}`,
519
+ path
520
+ });
521
+ } else {
522
+ value.forEach((item, index) => {
523
+ issues.push(
524
+ ...validateTypeWithErrors(
525
+ item,
526
+ `Array: ${fieldName}`,
527
+ {
528
+ type: fieldDef.itemsType,
529
+ nestedSchema: fieldDef.nestedSchema
530
+ },
531
+ [...path, index]
532
+ )
533
+ );
534
+ });
535
+ }
536
+ break;
537
+ case "object":
538
+ if (typeof value !== "object" || value === null) {
539
+ issues.push({
540
+ message: `Expected an object but received ${value === null ? "null" : typeof value}.`,
541
+ path
542
+ });
543
+ } else if (fieldDef.nestedSchema) {
544
+ const nestedSchema = {
545
+ name: fieldDef.description ? `${fieldDef.description}-schema` : "nested-schema",
546
+ version: "1.0",
547
+ fields: fieldDef.nestedSchema
548
+ };
549
+ issues.push(
550
+ ...validateData(
551
+ nestedSchema,
552
+ value,
553
+ path
554
+ )
555
+ );
556
+ }
557
+ break;
558
+ case "dynamic":
559
+ break;
560
+ default:
561
+ issues.push({ message: `Unknown field type: ${fieldDef.type}`, path });
562
+ break;
563
+ }
564
+ return issues;
565
+ };
566
+ const validateFieldConstraints = (fieldName, fieldDef, data, path) => {
567
+ const issues = [];
568
+ if (!fieldDef.constraints) return issues;
569
+ fieldDef.constraints.forEach((constraint) => {
570
+ const predicate = constraintsMap[constraint.predicate];
571
+ if (!predicate) {
572
+ issues.push({
573
+ message: `Missing predicate for constraint: ${constraint.name}`,
574
+ path
575
+ });
576
+ } else {
577
+ const valid = constraint.type === "schema" ? predicate({ data, arguments: constraint.parameters }) : predicate({
578
+ data,
579
+ field: fieldName,
580
+ arguments: constraint.parameters
581
+ });
582
+ if (!valid) {
583
+ issues.push({
584
+ message: `Constraint '${constraint.name}' failed for field '${fieldName}'.`,
585
+ path
586
+ });
587
+ }
588
+ }
589
+ });
590
+ return issues;
591
+ };
592
+ const validateField = (fieldName, fieldDef, value, data, path) => {
593
+ return [
594
+ ...validateTypeWithErrors(value, fieldName, fieldDef, path),
595
+ ...validateFieldConstraints(fieldName, fieldDef, data, path)
596
+ ];
597
+ };
598
+ const evaluateRuleWithErrors = (rule, data, fieldName) => {
599
+ if ("operator" in rule) {
600
+ return applyLogicalOperator(
601
+ rule.operator,
602
+ rule.rules.map((r) => evaluateRuleWithErrors(r, data, fieldName))
603
+ );
604
+ }
605
+ const predicate = constraintsMap[rule.predicate];
606
+ if (!predicate) {
607
+ return false;
608
+ }
609
+ return rule.type === "schema" ? predicate({ data, field: rule.field, arguments: rule.parameters }) : predicate({ data, field: fieldName, arguments: rule.parameters });
610
+ };
611
+ const applyLogicalOperator = (operator, results) => {
612
+ switch (operator) {
613
+ case "and":
614
+ return results.every(Boolean);
615
+ case "or":
616
+ return results.some(Boolean);
617
+ case "not":
618
+ return results.length === 1 ? !results[0] : false;
619
+ case "nor":
620
+ return !results.some(Boolean);
621
+ case "xor":
622
+ return results.filter(Boolean).length === 1;
623
+ default:
624
+ console.error(`Unknown logical operator: ${operator}`);
625
+ return false;
626
+ }
627
+ };
628
+ const ruleToString = (rule) => {
629
+ if ("operator" in rule) {
630
+ return `(${rule.rules.map(ruleToString).join(` ${rule.operator} `)})`;
631
+ }
632
+ return rule.name;
633
+ };
634
+ const validateData = (schemaToValidate, data, path = []) => {
635
+ const issues = [];
636
+ for (const [fieldName, fieldDef] of Object.entries(schemaToValidate.fields)) {
637
+ if (fieldDef.required && data[fieldName] === void 0) {
638
+ issues.push({
639
+ message: `Field '${fieldName}' is required.`,
640
+ path: [...path, fieldName]
641
+ });
642
+ }
643
+ }
644
+ for (const [fieldName, fieldDef] of Object.entries(schemaToValidate.fields)) {
645
+ const value = data[fieldName];
646
+ if (value === void 0) continue;
647
+ issues.push(
648
+ ...validateField(fieldName, fieldDef, value, data, [...path, fieldName])
649
+ );
650
+ }
651
+ if (schemaToValidate.constraints) {
652
+ schemaToValidate.constraints.forEach((rule) => {
653
+ if (!evaluateRuleWithErrors(rule, data)) {
654
+ issues.push({
655
+ message: `Schema constraint failed: ${ruleToString(rule)}`,
656
+ path
657
+ });
658
+ }
659
+ });
660
+ }
661
+ return issues;
662
+ };
663
+ return {
664
+ "~standard": {
665
+ version: 1,
666
+ vendor: "@asaidimu/anansi",
667
+ validate: (value) => {
668
+ if (typeof value !== "object" || value === null) {
669
+ return {
670
+ issues: [{ message: "Value must be a non-null object", path: [] }]
671
+ };
672
+ }
673
+ const issues = validateData(schema, value);
674
+ if (issues.length === 0) {
675
+ return { value };
676
+ }
677
+ return { issues };
678
+ }
679
+ }
680
+ };
681
+ }
682
+
683
+ // src/lib/migration/index.ts
684
+ var migration_exports = {};
685
+ __export(migration_exports, {
686
+ MigrationError: () => MigrationError,
687
+ MigrationErrorCode: () => MigrationErrorCode,
688
+ default: () => MigrationEngine
689
+ });
690
+
691
+ // src/lib/schema/validator.ts
692
+ import { z } from "zod";
693
+
694
+ // src/lib/schema/error.ts
695
+ var SchemaValidationError = class extends Error {
696
+ constructor(message, errors) {
697
+ super(message);
698
+ this.errors = errors;
699
+ this.name = "SchemaValidationError";
700
+ }
701
+ };
702
+
703
+ // src/lib/schema/validator.ts
704
+ var LogicalOperatorSchema = z.enum(["and", "or", "not", "nor", "xor"]);
705
+ var FieldTypeSchema = z.enum(["string", "number", "boolean", "array", "object", "dynamic"]);
706
+ var IndexTypeSchema = z.enum(["normal", "unique", "btree", "hash", "spatial", "fulltext", "gi", "expression", "composite"]);
707
+ var ConstraintParametersSchema = z.custom(() => {
708
+ return true;
709
+ });
710
+ var ConstraintSchema = z.object({
711
+ type: z.string().optional(),
712
+ name: z.string(),
713
+ predicate: z.string().optional(),
714
+ parameters: ConstraintParametersSchema.optional(),
715
+ description: z.string().optional(),
716
+ field: z.string().optional(),
717
+ errorMessage: z.string().optional()
718
+ });
719
+ var ConstraintGroupSchema = z.object({
720
+ operator: LogicalOperatorSchema,
721
+ rules: z.array(z.union([ConstraintSchema, z.lazy(() => ConstraintGroupSchema)]))
722
+ });
723
+ var FieldDefinitionSchema = z.object({
724
+ type: FieldTypeSchema,
725
+ required: z.boolean().optional(),
726
+ constraints: z.array(ConstraintSchema).optional(),
727
+ default: z.any().optional(),
728
+ itemsType: FieldTypeSchema.optional(),
729
+ nestedSchema: z.record(z.lazy(() => FieldDefinitionSchema)).optional(),
730
+ deprecated: z.boolean().optional(),
731
+ reference: z.object({ schema: z.string(), field: z.string() }).optional(),
732
+ description: z.string().optional(),
733
+ unique: z.boolean().optional()
734
+ });
735
+ var PartialIndexConditionSchema = z.object({
736
+ operator: LogicalOperatorSchema,
737
+ field: z.string(),
738
+ value: z.any().optional(),
739
+ conditions: z.array(z.lazy(() => PartialIndexConditionSchema)).optional()
740
+ });
741
+ var IndexDefinitionSchema = z.object({
742
+ fields: z.array(z.string()),
743
+ type: IndexTypeSchema,
744
+ unique: z.boolean().optional(),
745
+ partial: PartialIndexConditionSchema.optional(),
746
+ description: z.string().optional(),
747
+ order: z.enum(["asc", "desc"]).optional(),
748
+ name: z.string().optional()
749
+ });
750
+ var SchemaConstraintSchema = z.array(z.union([ConstraintSchema, ConstraintGroupSchema]));
751
+ var SchemaDefinitionSchema = z.object({
752
+ name: z.string(),
753
+ version: z.string(),
754
+ description: z.string().optional(),
755
+ fields: z.record(FieldDefinitionSchema),
756
+ indexes: z.array(IndexDefinitionSchema).optional(),
757
+ constraints: SchemaConstraintSchema.optional(),
758
+ metadata: z.record(z.any()).optional(),
759
+ dependencies: z.array(z.string()).optional(),
760
+ migrations: z.array(z.any()).optional()
761
+ });
762
+ var SchemaChangeSchema = z.union([
763
+ z.object({ type: z.literal("addField"), name: z.string(), definition: FieldDefinitionSchema }),
764
+ z.object({ type: z.literal("removeField"), name: z.string() }),
765
+ z.object({ type: z.literal("modifyField"), name: z.string(), changes: FieldDefinitionSchema.partial() }),
766
+ z.object({ type: z.literal("addIndex"), definition: IndexDefinitionSchema }),
767
+ z.object({ type: z.literal("removeIndex"), name: z.string() }),
768
+ z.object({ type: z.literal("modifyIndex"), name: z.string(), changes: IndexDefinitionSchema.partial() }),
769
+ z.object({ type: z.literal("addConstraint"), constraint: z.union([ConstraintSchema, ConstraintGroupSchema]) }),
770
+ z.object({ type: z.literal("removeConstraint"), name: z.string() }),
771
+ z.object({ type: z.literal("modifyConstraint"), name: z.string(), changes: ConstraintSchema.partial() }),
772
+ z.object({ type: z.literal("deprecateField"), name: z.string() })
773
+ ]);
774
+ var MigrationSchema = z.object({
775
+ id: z.string(),
776
+ schemaVersion: z.string(),
777
+ changes: z.array(SchemaChangeSchema),
778
+ description: z.string(),
779
+ status: z.enum(["pending", "applied", "failed"]),
780
+ rollback: z.array(SchemaChangeSchema).optional(),
781
+ transform: z.unknown(),
782
+ createdAt: z.string(),
783
+ checksum: z.string().optional()
784
+ });
785
+ function validateMigration(change) {
786
+ try {
787
+ MigrationSchema.parse(change);
788
+ return true;
789
+ } catch (error) {
790
+ throw new SchemaValidationError("Invalid migration definition", error);
791
+ }
792
+ }
793
+ function validateSchemaChange(change) {
794
+ try {
795
+ SchemaChangeSchema.parse(change);
796
+ return true;
797
+ } catch (error) {
798
+ throw new SchemaValidationError("Invalid schema definition", error);
799
+ }
800
+ }
801
+ function validateSchemaDefinition(schema) {
802
+ try {
803
+ SchemaDefinitionSchema.parse(schema);
804
+ return true;
805
+ } catch (error) {
806
+ throw new SchemaValidationError("Invalid schema definition", error);
807
+ }
808
+ }
809
+ var validate = validateSchemaDefinition;
810
+
811
+ // src/tools/crypto.ts
812
+ var crypto_exports = {};
813
+ __export(crypto_exports, {
814
+ generateSHA256Hash: () => generateSHA256Hash
815
+ });
816
+ var generateSHA256Hash = async (input) => {
817
+ if (typeof window !== "undefined" && crypto.subtle) {
818
+ const encoder = new TextEncoder();
819
+ const data = encoder.encode(input);
820
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
821
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
822
+ return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
823
+ } else {
824
+ const { createHash } = await import("crypto");
825
+ return createHash("sha256").update(input).digest("hex");
826
+ }
827
+ };
828
+
829
+ // src/tools/version.ts
830
+ var version_exports = {};
831
+ __export(version_exports, {
832
+ calculateNextVersion: () => calculateNextVersion,
833
+ compareSemanticVersions: () => compareSemanticVersions,
834
+ sortSemanticVars: () => sortSemanticVars
835
+ });
836
+ function parseVersion(version) {
837
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
838
+ if (!match) {
839
+ throw new Error(
840
+ `Invalid version format: ${version}. Expected format: major.minor.patch`
841
+ );
842
+ }
843
+ return {
844
+ major: parseInt(match[1], 10),
845
+ minor: parseInt(match[2], 10),
846
+ patch: parseInt(match[3], 10)
847
+ };
848
+ }
849
+ function determineFieldType(constraint, schema) {
850
+ if (schema && "field" in constraint && constraint.field) {
851
+ const fieldDef = schema.fields[constraint.field];
852
+ if (fieldDef) {
853
+ return fieldDef.type;
854
+ }
855
+ }
856
+ if ("parameters" in constraint) {
857
+ const params = constraint.parameters;
858
+ if (params instanceof RegExp || Array.isArray(params) && typeof params[0] === "string") {
859
+ return "string";
860
+ }
861
+ if (typeof params === "number" || Array.isArray(params) && typeof params[0] === "number") {
862
+ return "number";
863
+ }
864
+ if (typeof params === "boolean") {
865
+ return "boolean";
866
+ }
867
+ if (typeof params === "object" && params !== null) {
868
+ if ("minItems" in params || "maxItems" in params) {
869
+ return "array";
870
+ }
871
+ if ("schema" in params) {
872
+ return "object";
873
+ }
874
+ }
875
+ }
876
+ return void 0;
877
+ }
878
+ function isBreakingFieldChange(changes) {
879
+ if (changes.required === true) return true;
880
+ if (changes.type !== void 0) return true;
881
+ if (changes.itemsType !== void 0) return true;
882
+ if (changes.nestedSchema !== void 0) return true;
883
+ if (changes.reference !== void 0) return true;
884
+ if (changes.unique === true) return true;
885
+ return false;
886
+ }
887
+ function isBreakingConstraintParameters(oldParams, newParams, fieldType) {
888
+ switch (fieldType) {
889
+ case "string":
890
+ if (oldParams instanceof RegExp && newParams instanceof RegExp) {
891
+ return oldParams.source !== newParams.source;
892
+ }
893
+ if (Array.isArray(oldParams) && Array.isArray(newParams)) {
894
+ return newParams.length < oldParams.length || !oldParams.every(
895
+ (val) => newParams.includes(val)
896
+ );
897
+ }
898
+ break;
899
+ case "number":
900
+ if (typeof oldParams === "object" && typeof newParams === "object") {
901
+ if ("precision" in oldParams && "precision" in newParams) {
902
+ return newParams.precision < oldParams.precision || (newParams.scale ?? 0) < (oldParams.scale ?? 0);
903
+ }
904
+ }
905
+ if (Array.isArray(oldParams) && Array.isArray(newParams)) {
906
+ return newParams.length < oldParams.length || !oldParams.every(
907
+ (val) => newParams.includes(val)
908
+ );
909
+ }
910
+ break;
911
+ case "array":
912
+ if (typeof oldParams === "object" && typeof newParams === "object" && "minItems" in oldParams && "maxItems" in oldParams && "minItems" in newParams && "maxItems" in newParams) {
913
+ return newParams.minItems > oldParams.minItems || newParams.maxItems < oldParams.maxItems;
914
+ }
915
+ break;
916
+ case "object":
917
+ if (typeof oldParams === "object" && typeof newParams === "object" && "schema" in oldParams && "schema" in newParams) {
918
+ return Object.keys(newParams.schema).length > Object.keys(oldParams.schema).length;
919
+ }
920
+ break;
921
+ }
922
+ return false;
923
+ }
924
+ function analyzeConstraintGroupChanges(oldGroup, newGroup) {
925
+ const operatorPriority = {
926
+ or: 1,
927
+ xor: 2,
928
+ and: 3,
929
+ not: 4,
930
+ nor: 4
931
+ };
932
+ if (newGroup.operator && operatorPriority[newGroup.operator] > operatorPriority[oldGroup.operator]) {
933
+ return true;
934
+ }
935
+ if (newGroup.rules && newGroup.rules.length > oldGroup.rules.length) {
936
+ return true;
937
+ }
938
+ return false;
939
+ }
940
+ function isBreakingConstraintChange(changes, oldConstraint, schema) {
941
+ if (!oldConstraint) {
942
+ return true;
943
+ }
944
+ if ("rules" in oldConstraint && "rules" in changes) {
945
+ return analyzeConstraintGroupChanges(
946
+ oldConstraint,
947
+ changes
948
+ );
949
+ }
950
+ if ("predicate" in changes && changes.predicate !== void 0) {
951
+ return true;
952
+ }
953
+ if ("parameters" in changes && changes.parameters !== void 0) {
954
+ const fieldType = determineFieldType(
955
+ oldConstraint,
956
+ schema
957
+ );
958
+ if (fieldType) {
959
+ return isBreakingConstraintParameters(
960
+ oldConstraint.parameters,
961
+ changes.parameters,
962
+ fieldType
963
+ );
964
+ }
965
+ return true;
966
+ }
967
+ return false;
968
+ }
969
+ function getChangeImpact(change, currentSchema) {
970
+ switch (change.type) {
971
+ case "removeField":
972
+ case "removeIndex":
973
+ return "major";
974
+ case "modifyField":
975
+ if (isBreakingFieldChange(change.changes)) {
976
+ return "major";
977
+ }
978
+ if (change.changes.deprecated) {
979
+ return "minor";
980
+ }
981
+ return "patch";
982
+ case "modifyIndex":
983
+ if (change.changes.unique !== void 0 || change.changes.fields !== void 0) {
984
+ return "major";
985
+ }
986
+ return "minor";
987
+ case "addConstraint":
988
+ return "major";
989
+ case "removeConstraint":
990
+ return "minor";
991
+ case "modifyConstraint":
992
+ const oldConstraint = currentSchema?.constraints?.find(
993
+ (c) => "name" in c && c.name === change.name
994
+ );
995
+ if (isBreakingConstraintChange(change.changes, oldConstraint, currentSchema)) {
996
+ return "major";
997
+ }
998
+ return "minor";
999
+ case "addField":
1000
+ case "addIndex":
1001
+ case "deprecateField":
1002
+ return "minor";
1003
+ default:
1004
+ throw new Error(`Unhandled change type: ${JSON.stringify(change)}`);
1005
+ }
1006
+ }
1007
+ function validateFieldChanges(changes) {
1008
+ const modifiedFields = /* @__PURE__ */ new Set();
1009
+ const removedFields = /* @__PURE__ */ new Set();
1010
+ const addedFields = /* @__PURE__ */ new Set();
1011
+ const deprecatedFields = /* @__PURE__ */ new Set();
1012
+ for (const change of changes) {
1013
+ switch (change.type) {
1014
+ case "addField":
1015
+ if (removedFields.has(change.name)) {
1016
+ throw new Error(
1017
+ `Cannot add previously removed field: ${change.name}`
1018
+ );
1019
+ }
1020
+ if (modifiedFields.has(change.name)) {
1021
+ throw new Error(`Cannot add already modified field: ${change.name}`);
1022
+ }
1023
+ if (deprecatedFields.has(change.name)) {
1024
+ throw new Error(`Cannot add deprecated field: ${change.name}`);
1025
+ }
1026
+ addedFields.add(change.name);
1027
+ break;
1028
+ case "removeField":
1029
+ if (addedFields.has(change.name)) {
1030
+ throw new Error(`Cannot remove newly added field: ${change.name}`);
1031
+ }
1032
+ if (modifiedFields.has(change.name)) {
1033
+ throw new Error(`Cannot remove modified field: ${change.name}`);
1034
+ }
1035
+ if (deprecatedFields.has(change.name)) {
1036
+ throw new Error(
1037
+ `Cannot remove field that is being deprecated: ${change.name}`
1038
+ );
1039
+ }
1040
+ removedFields.add(change.name);
1041
+ break;
1042
+ case "modifyField":
1043
+ if (removedFields.has(change.name)) {
1044
+ throw new Error(`Cannot modify removed field: ${change.name}`);
1045
+ }
1046
+ if (addedFields.has(change.name)) {
1047
+ throw new Error(`Cannot modify newly added field: ${change.name}`);
1048
+ }
1049
+ if (deprecatedFields.has(change.name)) {
1050
+ throw new Error(
1051
+ `Cannot modify field that is being deprecated: ${change.name}`
1052
+ );
1053
+ }
1054
+ modifiedFields.add(change.name);
1055
+ break;
1056
+ case "deprecateField":
1057
+ if (removedFields.has(change.name)) {
1058
+ throw new Error(`Cannot deprecate removed field: ${change.name}`);
1059
+ }
1060
+ if (addedFields.has(change.name)) {
1061
+ throw new Error(`Cannot deprecate newly added field: ${change.name}`);
1062
+ }
1063
+ if (modifiedFields.has(change.name)) {
1064
+ throw new Error(`Cannot deprecate modified field: ${change.name}`);
1065
+ }
1066
+ deprecatedFields.add(change.name);
1067
+ break;
1068
+ }
1069
+ }
1070
+ }
1071
+ function validateConstraintChanges(changes) {
1072
+ const modifiedConstraints = /* @__PURE__ */ new Set();
1073
+ const removedConstraints = /* @__PURE__ */ new Set();
1074
+ const addedConstraints = /* @__PURE__ */ new Set();
1075
+ for (const change of changes) {
1076
+ switch (change.type) {
1077
+ case "addConstraint":
1078
+ const c = change.constraint;
1079
+ const name = "name" in c ? c.name : c.name;
1080
+ if (removedConstraints.has(name)) {
1081
+ throw new Error(
1082
+ `Cannot add previously removed constraint: ${name}`
1083
+ );
1084
+ }
1085
+ if (modifiedConstraints.has(name)) {
1086
+ throw new Error(`Cannot add already modified constraint: ${name}`);
1087
+ }
1088
+ addedConstraints.add(name);
1089
+ break;
1090
+ case "removeConstraint":
1091
+ if (addedConstraints.has(change.name)) {
1092
+ throw new Error(
1093
+ `Cannot remove newly added constraint: ${change.name}`
1094
+ );
1095
+ }
1096
+ if (modifiedConstraints.has(change.name)) {
1097
+ throw new Error(`Cannot remove modified constraint: ${change.name}`);
1098
+ }
1099
+ removedConstraints.add(change.name);
1100
+ break;
1101
+ case "modifyConstraint":
1102
+ if (removedConstraints.has(change.name)) {
1103
+ throw new Error(`Cannot modify removed constraint: ${change.name}`);
1104
+ }
1105
+ if (addedConstraints.has(change.name)) {
1106
+ throw new Error(
1107
+ `Cannot modify newly added constraint: ${change.name}`
1108
+ );
1109
+ }
1110
+ modifiedConstraints.add(change.name);
1111
+ break;
1112
+ }
1113
+ }
1114
+ }
1115
+ function calculateNextVersion(currentVersion, changes, currentSchema) {
1116
+ if (changes.length === 0) {
1117
+ throw new Error("No changes provided");
1118
+ }
1119
+ validateFieldChanges(changes);
1120
+ validateConstraintChanges(changes);
1121
+ const version = parseVersion(currentVersion);
1122
+ let highestImpact = "patch";
1123
+ for (const change of changes) {
1124
+ const impact = getChangeImpact(change, currentSchema);
1125
+ if (impact === "major") {
1126
+ highestImpact = "major";
1127
+ break;
1128
+ } else if (impact === "minor" && highestImpact === "patch") {
1129
+ highestImpact = "minor";
1130
+ }
1131
+ }
1132
+ switch (highestImpact) {
1133
+ case "major":
1134
+ return `${version.major + 1}.0.0`;
1135
+ case "minor":
1136
+ return `${version.major}.${version.minor + 1}.0`;
1137
+ case "patch":
1138
+ return `${version.major}.${version.minor}.${version.patch + 1}`;
1139
+ }
1140
+ }
1141
+ function compareSemanticVersions(a, b) {
1142
+ const parseVersion2 = (version) => version.split(".").map((part) => parseInt(part, 10) || 0);
1143
+ const [aMajor, aMinor, aPatch] = parseVersion2(a);
1144
+ const [bMajor, bMinor, bPatch] = parseVersion2(b);
1145
+ return aMajor - bMajor || aMinor - bMinor || aPatch - bPatch;
1146
+ }
1147
+ function sortSemanticVars(vars) {
1148
+ return vars.sort(compareSemanticVersions);
1149
+ }
1150
+
1151
+ // src/lib/migration/index.ts
1152
+ var MigrationError = class extends Error {
1153
+ constructor(message, code, migrationId, cause) {
1154
+ super(message);
1155
+ this.code = code;
1156
+ this.migrationId = migrationId;
1157
+ this.cause = cause;
1158
+ this.name = "MigrationError";
1159
+ }
1160
+ };
1161
+ var MigrationErrorCode = /* @__PURE__ */ ((MigrationErrorCode2) => {
1162
+ MigrationErrorCode2["INVALID_SCHEMA"] = "INVALID_SCHEMA";
1163
+ MigrationErrorCode2["INVALID_MIGRATION"] = "INVALID_MIGRATION";
1164
+ MigrationErrorCode2["CHECKSUM_MISMATCH"] = "CHECKSUM_MISMATCH";
1165
+ MigrationErrorCode2["TIMEOUT"] = "TIMEOUT";
1166
+ MigrationErrorCode2["MEMORY_LIMIT"] = "MEMORY_LIMIT";
1167
+ MigrationErrorCode2["CONCURRENT_OPERATION"] = "CONCURRENT_OPERATION";
1168
+ MigrationErrorCode2["TRANSFORM_ERROR"] = "TRANSFORM_ERROR";
1169
+ MigrationErrorCode2["VERSION_NOT_FOUND"] = "VERSION_NOT_FOUND";
1170
+ MigrationErrorCode2["CIRCULAR_DEPENDENCY"] = "CIRCULAR_DEPENDENCY";
1171
+ MigrationErrorCode2["STREAM_ERROR"] = "STREAM_ERROR";
1172
+ MigrationErrorCode2["ROLLBACK_ERROR"] = "ROLLBACK_ERROR";
1173
+ MigrationErrorCode2["MISSING_TRANSFORM"] = "MISSING_TRANSFORM";
1174
+ return MigrationErrorCode2;
1175
+ })(MigrationErrorCode || {});
1176
+ var MigrationEngine = class _MigrationEngine {
1177
+ currentSchema;
1178
+ history = [];
1179
+ migrations = [];
1180
+ isProcessing = false;
1181
+ /**
1182
+ * @constructor
1183
+ * @param {SchemaDefinition} currentSchema - The current schema definition
1184
+ * @param {Array<Migration<any>>} [migrations] - Optional array of migrations
1185
+ */
1186
+ constructor(currentSchema, migrations, history) {
1187
+ try {
1188
+ if (!validateSchemaDefinition(currentSchema)) {
1189
+ throw new MigrationError(
1190
+ "Invalid initial schema",
1191
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */
1192
+ );
1193
+ }
1194
+ this.currentSchema = currentSchema;
1195
+ if (migrations) {
1196
+ if (!migrations.every((migration) => validateMigration(migration))) {
1197
+ throw new MigrationError(
1198
+ "Invalid migration configuration",
1199
+ "INVALID_MIGRATION" /* INVALID_MIGRATION */
1200
+ );
1201
+ }
1202
+ this.migrations = migrations.sort(
1203
+ (a, b) => compareSemanticVersions(a.schemaVersion, b.schemaVersion)
1204
+ );
1205
+ }
1206
+ if (history) {
1207
+ this.history = history.sort(
1208
+ (a, b) => compareSemanticVersions(a.version, b.version)
1209
+ );
1210
+ }
1211
+ } catch (error) {
1212
+ if (error instanceof MigrationError) throw error;
1213
+ throw new MigrationError(
1214
+ "Failed to initialize MigrationEngine",
1215
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1216
+ void 0,
1217
+ error
1218
+ );
1219
+ }
1220
+ }
1221
+ /**
1222
+ * Gets the current state of the migration helper
1223
+ * @returns {Object} Current state containing schema, history, and migrations
1224
+ * @example
1225
+ * ```javascript
1226
+ * const state = migrationEngine.data();
1227
+ * // state contains currentSchema, history, and migrations
1228
+ * ```
1229
+ */
1230
+ data() {
1231
+ const result = {
1232
+ schema: this.currentSchema,
1233
+ history: this.history,
1234
+ migrations: this.migrations
1235
+ };
1236
+ return result;
1237
+ }
1238
+ /**
1239
+ * Generates a SHA-256 checksum for a migration
1240
+ * @private
1241
+ * @param {Omit<Migration<any>, "checksum">} migration - The migration object
1242
+ * @returns {Promise<string>} The generated checksum
1243
+ * @throws {MigrationError} If checksum generation fails
1244
+ */
1245
+ async generateChecksum(migration) {
1246
+ try {
1247
+ const payload = JSON.stringify({
1248
+ id: migration.id,
1249
+ schemaVersion: migration.schemaVersion,
1250
+ changes: migration.changes,
1251
+ description: migration.description,
1252
+ rollback: migration.rollback,
1253
+ createdAt: migration.createdAt
1254
+ });
1255
+ return await generateSHA256Hash(payload);
1256
+ } catch (error) {
1257
+ throw new MigrationError(
1258
+ "Checksum generation failed",
1259
+ "CHECKSUM_MISMATCH" /* CHECKSUM_MISMATCH */,
1260
+ migration.id,
1261
+ error
1262
+ );
1263
+ }
1264
+ }
1265
+ /**
1266
+ * Adds a new migration to the engine
1267
+ * @async
1268
+ * @param {Object} opts - Options for the new migration
1269
+ * @param {SchemaChange<any>[]} opts.changes - Array of schema changes
1270
+ * @param {string} opts.description - Description of the migration
1271
+ * @param {SchemaChange<any>[]} [opts.rollback] - Optional rollback changes
1272
+ * @param {DataTransform<any, any>} [opts.transform] - Optional data transform
1273
+ * @throws {MigrationError} If adding the migration fails
1274
+ */
1275
+ async add(opts) {
1276
+ if (this.isProcessing) {
1277
+ throw new MigrationError(
1278
+ "Concurrent operation",
1279
+ "CONCURRENT_OPERATION" /* CONCURRENT_OPERATION */
1280
+ );
1281
+ }
1282
+ if (!opts.changes?.length) {
1283
+ throw new MigrationError(
1284
+ "Migration must include changes",
1285
+ "INVALID_MIGRATION" /* INVALID_MIGRATION */
1286
+ );
1287
+ }
1288
+ try {
1289
+ opts.changes.forEach((change) => validateSchemaChange(change));
1290
+ } catch (error) {
1291
+ throw new MigrationError(
1292
+ "Invalid schema changes",
1293
+ "INVALID_MIGRATION" /* INVALID_MIGRATION */,
1294
+ void 0,
1295
+ error
1296
+ );
1297
+ }
1298
+ const newMigration = {
1299
+ id: Date.now().toString(),
1300
+ schemaVersion: this.currentSchema.version,
1301
+ changes: opts.changes,
1302
+ description: opts.description,
1303
+ status: "pending",
1304
+ rollback: opts.rollback,
1305
+ transform: opts.transform,
1306
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1307
+ checksum: ""
1308
+ };
1309
+ newMigration.checksum = await this.generateChecksum(newMigration);
1310
+ this.migrations.push(newMigration);
1311
+ }
1312
+ /**
1313
+ * Performs a dry run of the migration
1314
+ * @async
1315
+ * @param {ReadableStream<any>} input - Input data stream
1316
+ * @param {"forward" | "backward"} direction - Direction of migration
1317
+ * @param {version} version - Version to rollback to
1318
+ * @returns {Promise<Object>} Object containing newSchema and dataPreview
1319
+ * @throws {MigrationError} If dry run fails
1320
+ */
1321
+ async dryRun(input, direction, version) {
1322
+ if (this.isProcessing) {
1323
+ throw new MigrationError(
1324
+ "Concurrent operation",
1325
+ "CONCURRENT_OPERATION" /* CONCURRENT_OPERATION */
1326
+ );
1327
+ }
1328
+ try {
1329
+ this.isProcessing = true;
1330
+ const simulatedSchema = { ...this.currentSchema };
1331
+ const relevantMigrations = this.getRelevantMigrations(direction, version);
1332
+ const tempSchema = relevantMigrations.reduce((acc, migration) => {
1333
+ const changes = direction === "forward" ? migration.changes : migration.rollback || [];
1334
+ return this.applySchemaChanges(acc, changes, migration.id);
1335
+ }, simulatedSchema);
1336
+ const previewStream = await _MigrationEngine.processMigrationList(
1337
+ input,
1338
+ direction,
1339
+ relevantMigrations
1340
+ );
1341
+ return { newSchema: tempSchema, dataPreview: previewStream };
1342
+ } catch (error) {
1343
+ if (error instanceof MigrationError) throw error;
1344
+ throw new MigrationError(
1345
+ "Dry run failed",
1346
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1347
+ void 0,
1348
+ error
1349
+ );
1350
+ } finally {
1351
+ this.isProcessing = false;
1352
+ }
1353
+ }
1354
+ /**
1355
+ * Gets relevant migrations based on direction
1356
+ * @private
1357
+ * @param {"forward" | "backward"} direction - Direction of migration
1358
+ * @returns {Array<Migration<any>>} Relevant migrations
1359
+ */
1360
+ getRelevantMigrations(direction, version) {
1361
+ return [...this.migrations].filter((m) => {
1362
+ const dir = direction === "forward" ? "pending" : "applied";
1363
+ const vs = version ? compareSemanticVersions(m.schemaVersion, version) >= 0 : true;
1364
+ return m.status === dir && vs;
1365
+ }).sort(
1366
+ (a, b) => direction === "forward" ? a.id.localeCompare(b.id) : b.id.localeCompare(a.id)
1367
+ );
1368
+ }
1369
+ /**
1370
+ * Applies schema changes to a given schema
1371
+ * @private
1372
+ * @param {SchemaDefinition} schema - The schema to modify
1373
+ * @param {SchemaChange<any>[]} changes - Array of schema changes
1374
+ * @param {string} [migrationId] - ID of the migration
1375
+ * @returns {SchemaDefinition} Modified schema
1376
+ * @throws {MigrationError} If applying changes fails
1377
+ */
1378
+ applySchemaChanges(schema, changes, migrationId) {
1379
+ try {
1380
+ const version = calculateNextVersion(schema.version, changes);
1381
+ const patches = changes.map((change) => {
1382
+ try {
1383
+ return schemaChangeToPatch(change, schema);
1384
+ } catch (error) {
1385
+ throw new MigrationError(
1386
+ "Invalid schema change",
1387
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1388
+ migrationId,
1389
+ error
1390
+ );
1391
+ }
1392
+ });
1393
+ return patches.reduce(
1394
+ (acc, patch) => {
1395
+ try {
1396
+ return applyPatch(acc, patch);
1397
+ } catch (error) {
1398
+ throw new MigrationError(
1399
+ "Failed to apply patch",
1400
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1401
+ migrationId,
1402
+ error
1403
+ );
1404
+ }
1405
+ },
1406
+ { ...schema, version }
1407
+ );
1408
+ } catch (error) {
1409
+ if (error instanceof MigrationError) throw error;
1410
+ throw new MigrationError(
1411
+ "Schema update failed",
1412
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1413
+ migrationId,
1414
+ error
1415
+ );
1416
+ }
1417
+ }
1418
+ /**
1419
+ * Prepares the list of pending migrations for application
1420
+ * @async
1421
+ * @returns {Promise<Array<Migration<any>>} List of pending migrations
1422
+ * @throws {MigrationError} If preparation fails
1423
+ */
1424
+ async prepareMigration() {
1425
+ const pendingMigrations = this.migrations.filter(
1426
+ (m) => m.status === "pending"
1427
+ );
1428
+ await this.validateMigrations(pendingMigrations);
1429
+ return pendingMigrations;
1430
+ }
1431
+ /**
1432
+ * Applies pending migrations
1433
+ * @async
1434
+ * @param {ReadableStream<any>} input - Input data stream
1435
+ * @returns {Promise<ReadableStream<any>>} Transformed data stream
1436
+ * @throws {MigrationError} If migration fails
1437
+ */
1438
+ async migrate(input) {
1439
+ if (this.isProcessing) {
1440
+ throw new MigrationError(
1441
+ "Concurrent operation",
1442
+ "CONCURRENT_OPERATION" /* CONCURRENT_OPERATION */
1443
+ );
1444
+ }
1445
+ const pendingMigrations = await this.prepareMigration();
1446
+ try {
1447
+ this.isProcessing = true;
1448
+ this.transformSchema("forward");
1449
+ const result = await _MigrationEngine.processMigrationList(
1450
+ input,
1451
+ "forward",
1452
+ pendingMigrations
1453
+ );
1454
+ this.markMigrationsApplied(pendingMigrations);
1455
+ return result;
1456
+ } finally {
1457
+ this.isProcessing = false;
1458
+ }
1459
+ }
1460
+ /**
1461
+ * Validates migrations by checking their checksums
1462
+ * @private
1463
+ * @async
1464
+ * @param {Array<Migration<any>>} migrations - Migrations to validate
1465
+ * @throws {MigrationError} If validation fails
1466
+ */
1467
+ async validateMigrations(migrations) {
1468
+ await Promise.all(
1469
+ migrations.map(async (migration) => {
1470
+ const currentChecksum = await this.generateChecksum(migration);
1471
+ if (migration.checksum !== currentChecksum) {
1472
+ throw new MigrationError(
1473
+ "Checksum mismatch",
1474
+ "CHECKSUM_MISMATCH" /* CHECKSUM_MISMATCH */,
1475
+ migration.id
1476
+ );
1477
+ }
1478
+ })
1479
+ );
1480
+ }
1481
+ /**
1482
+ * Marks migrations as applied
1483
+ * @private
1484
+ * @param {Array<Migration<any>>} migrations - Migrations to mark as applied
1485
+ */
1486
+ markMigrationsApplied(migrations) {
1487
+ this.migrations = this.migrations.map(
1488
+ (m) => migrations.some((mm) => mm.id === m.id) ? { ...m, status: "applied" } : m
1489
+ );
1490
+ }
1491
+ /**
1492
+ * Rolls back the last applied migration
1493
+ * @async
1494
+ * @param {ReadableStream<any>} input - Input data stream
1495
+ * @returns {Promise<ReadableStream<any>>} Transformed data stream
1496
+ */
1497
+ async rollback(input) {
1498
+ if (this.isProcessing) {
1499
+ throw new MigrationError(
1500
+ "Concurrent operation",
1501
+ "CONCURRENT_OPERATION" /* CONCURRENT_OPERATION */
1502
+ );
1503
+ }
1504
+ const lastApplied = this.migrations.filter((m) => m.status === "applied").slice(-1)[0];
1505
+ if (!lastApplied) return input;
1506
+ return this.rollbackToVersion(
1507
+ this.history[this.history.length - 1]?.version || this.currentSchema.version,
1508
+ input
1509
+ );
1510
+ }
1511
+ /**
1512
+ * Rolls back to a specific schema version
1513
+ * @async
1514
+ * @param {string} targetVersion - Target schema version
1515
+ * @param {ReadableStream<any>} input - Input data stream
1516
+ * @returns {Promise<ReadableStream<any>>} Transformed data stream
1517
+ * @throws {Error} If target version is not found
1518
+ */
1519
+ async rollbackToVersion(targetVersion, input) {
1520
+ if (this.isProcessing) {
1521
+ throw new MigrationError(
1522
+ "Concurrent operation",
1523
+ "CONCURRENT_OPERATION" /* CONCURRENT_OPERATION */
1524
+ );
1525
+ }
1526
+ try {
1527
+ const versionIndex = this.history.findIndex(
1528
+ (s) => s.version === targetVersion
1529
+ );
1530
+ if (versionIndex === -1) {
1531
+ throw new Error(`Version ${targetVersion} not found in history`);
1532
+ }
1533
+ const migrations = this.migrations.filter(
1534
+ (m) => m.schemaVersion === targetVersion && m.status === "applied"
1535
+ ).sort((a, b) => b.id.localeCompare(a.id));
1536
+ const stepsBack = this.history.length - versionIndex;
1537
+ if (stepsBack < 0) return input;
1538
+ for (let i = 0; i < stepsBack; i++) {
1539
+ this.transformSchema("backward");
1540
+ }
1541
+ const transformedStream = await _MigrationEngine.processMigrationList(
1542
+ input,
1543
+ "backward",
1544
+ migrations
1545
+ );
1546
+ this.migrations = this.migrations.map((m) => {
1547
+ if (m.schemaVersion === targetVersion && m.status === "applied") {
1548
+ return { ...m, status: "pending" };
1549
+ }
1550
+ return m;
1551
+ });
1552
+ return transformedStream;
1553
+ } finally {
1554
+ this.isProcessing = false;
1555
+ }
1556
+ }
1557
+ /**
1558
+ * Processes a list of migrations on a data stream, applying transformations
1559
+ * in the specified direction (forward or backward).
1560
+ *
1561
+ * @static
1562
+ * @async
1563
+ * @param {ReadableStream<any>} input - The input data stream to process
1564
+ * @param {"forward" | "backward"} direction - Direction of migration (either "forward" or "backward")
1565
+ * @param {Array<Migration<any>>} migrations - Array of Migration objects to process
1566
+ * @returns {Promise<ReadableStream<any>>} Transformed data stream
1567
+ * @throws {MigrationError} If any migration processing fails
1568
+ */
1569
+ static async processMigrationList(input, direction, migrations) {
1570
+ const transformEntries = await Promise.all(
1571
+ migrations.map(async (migration) => {
1572
+ try {
1573
+ const transform = await this.resolveTransform(migration, direction);
1574
+ return { migration, transform };
1575
+ } catch (error) {
1576
+ throw new MigrationError(
1577
+ `Failed to resolve transform for migration ${migration.id}`,
1578
+ "TRANSFORM_ERROR" /* TRANSFORM_ERROR */,
1579
+ migration.id,
1580
+ error
1581
+ );
1582
+ }
1583
+ })
1584
+ );
1585
+ const validTransformEntries = transformEntries.filter(
1586
+ (entry) => Boolean(entry.transform)
1587
+ );
1588
+ return validTransformEntries.reduce((stream, { migration, transform }) => {
1589
+ return stream.pipeThrough(
1590
+ new TransformStream({
1591
+ async transform(chunk, controller) {
1592
+ try {
1593
+ const result = await transform(chunk);
1594
+ controller.enqueue(result);
1595
+ } catch (error) {
1596
+ controller.error(
1597
+ new MigrationError(
1598
+ `Data transformation failed for migration ${migration.id}`,
1599
+ "TRANSFORM_ERROR" /* TRANSFORM_ERROR */,
1600
+ migration.id,
1601
+ error
1602
+ )
1603
+ );
1604
+ }
1605
+ }
1606
+ })
1607
+ );
1608
+ }, input);
1609
+ }
1610
+ /**
1611
+ * Resolves the transform function for a given migration in the specified direction.
1612
+ *
1613
+ * @private
1614
+ * @async
1615
+ * @param {Migration<any>} migration - The migration to resolve the transform for
1616
+ * @param {"forward" | "backward"} direction - Direction of migration
1617
+ * @returns {Promise<TransformFunction<any, any>>} Resolved transform function
1618
+ * @throws {MigrationError} If transform resolution fails
1619
+ */
1620
+ static async resolveTransform(migration, direction) {
1621
+ if (!migration.transform) {
1622
+ return null;
1623
+ }
1624
+ if (typeof migration.transform === "string") {
1625
+ if (migration.transform.startsWith("http://") || migration.transform.startsWith("https://")) {
1626
+ return this.resolveRemoteTransform(migration.transform, direction);
1627
+ }
1628
+ return this.resolveLocalTransform(migration.transform, direction);
1629
+ }
1630
+ return migration.transform[direction];
1631
+ }
1632
+ /**
1633
+ * Resolves a transform function from a remote URL.
1634
+ *
1635
+ * @private
1636
+ * @async
1637
+ * @param {string} url - URL of the transform module
1638
+ * @param {"forward" | "backward"} direction - Direction of migration
1639
+ * @returns {Promise<TransformFunction<any, any>>} Resolved transform function
1640
+ * @throws {MigrationError} If resolution fails
1641
+ */
1642
+ static async resolveRemoteTransform(url, direction) {
1643
+ try {
1644
+ const response = await fetch(url);
1645
+ if (!response.ok) {
1646
+ throw new MigrationError(
1647
+ `Failed to fetch transform module: ${url}`,
1648
+ "TRANSFORM_ERROR" /* TRANSFORM_ERROR */,
1649
+ void 0
1650
+ );
1651
+ }
1652
+ const moduleText = await response.text();
1653
+ if (typeof window !== "undefined") {
1654
+ const blob = new Blob([moduleText], {
1655
+ type: "application/javascript"
1656
+ });
1657
+ const url2 = URL.createObjectURL(blob);
1658
+ const module = (await import(url2)).default;
1659
+ return module[direction];
1660
+ } else {
1661
+ const { runInNewContext } = await import("vm");
1662
+ const sandbox = { module: { exports: {} }, console };
1663
+ runInNewContext(moduleText, sandbox, url);
1664
+ return sandbox.module.exports[direction];
1665
+ }
1666
+ } catch (error) {
1667
+ throw new MigrationError(
1668
+ `Failed to load remote transform module: ${url}`,
1669
+ "TRANSFORM_ERROR" /* TRANSFORM_ERROR */,
1670
+ void 0,
1671
+ error
1672
+ );
1673
+ }
1674
+ }
1675
+ /**
1676
+ * Resolves a transform function from a local module path.
1677
+ *
1678
+ * @private
1679
+ * @async
1680
+ * @param {string} path - Local module path
1681
+ * @param {"forward" | "backward"} direction - Direction of migration
1682
+ * @returns {Promise<TransformFunction<any, any>>} Resolved transform function
1683
+ * @throws {MigrationError} If resolution fails
1684
+ */
1685
+ static async resolveLocalTransform(path, direction) {
1686
+ try {
1687
+ const module = await import(path);
1688
+ const dataTransform = module.default;
1689
+ return dataTransform[direction];
1690
+ } catch (error) {
1691
+ throw new MigrationError(
1692
+ `Failed to import local transform module: ${path}`,
1693
+ "TRANSFORM_ERROR" /* TRANSFORM_ERROR */,
1694
+ void 0,
1695
+ error
1696
+ );
1697
+ }
1698
+ }
1699
+ /**
1700
+ * Transforms the schema either forward or backward
1701
+ * @private
1702
+ * @param {"forward" | "backward"} direction - Direction of transformation
1703
+ * @throws {Error} If transformation fails
1704
+ */
1705
+ transformSchema(direction) {
1706
+ try {
1707
+ if (direction === "backward") {
1708
+ const schema = this.history.pop();
1709
+ if (!schema) throw new Error("No previous version");
1710
+ this.currentSchema = schema;
1711
+ return;
1712
+ }
1713
+ const changes = this.migrations.filter((m) => m.status === "pending").flatMap((m) => m.changes);
1714
+ if (!changes.length) return;
1715
+ this.history.push(structuredClone(this.currentSchema));
1716
+ this.currentSchema = changes.reduce(
1717
+ (acc, change) => this.applySchemaChanges(acc, [change]),
1718
+ this.currentSchema
1719
+ );
1720
+ } catch (error) {
1721
+ if (error instanceof MigrationError) throw error;
1722
+ throw new MigrationError(
1723
+ "Schema transformation failed",
1724
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
1725
+ void 0,
1726
+ error
1727
+ );
1728
+ }
1729
+ }
1730
+ };
1731
+
1732
+ // src/lib/schema/helpers.ts
1733
+ var createSchemaMigrationHelper = (schema) => {
1734
+ const migrate = [];
1735
+ const rollback = [];
1736
+ return {
1737
+ /**
1738
+ * Adds a new field to the schema.
1739
+ * @param {string} fieldName - The name of the field to add.
1740
+ * @param {FieldDefinition<any>} fieldDefinition - The definition of the field to add.
1741
+ */
1742
+ addField: (fieldName, fieldDefinition) => {
1743
+ migrate.push({ type: "addField", name: fieldName, definition: fieldDefinition });
1744
+ rollback.push({ type: "removeField", name: fieldName });
1745
+ },
1746
+ /**
1747
+ * Removes a field from the schema.
1748
+ * @param {string} fieldName - The name of the field to remove.
1749
+ */
1750
+ removeField: (fieldName) => {
1751
+ migrate.push({ type: "removeField", name: fieldName });
1752
+ const originalField = schema.fields[fieldName];
1753
+ if (originalField) {
1754
+ rollback.push({ type: "addField", name: fieldName, definition: originalField });
1755
+ }
1756
+ },
1757
+ /**
1758
+ * Modifies an existing field in the schema.
1759
+ * @param {string} fieldName - The name of the field to modify.
1760
+ * @param {Partial<FieldDefinition<any>>} changes - The changes to apply to the field.
1761
+ */
1762
+ modifyField: (fieldName, changes) => {
1763
+ migrate.push({ type: "modifyField", name: fieldName, changes });
1764
+ const originalField = schema.fields[fieldName];
1765
+ rollback.push({ type: "modifyField", name: fieldName, changes: originalField });
1766
+ },
1767
+ /**
1768
+ * Deprecates a field.
1769
+ * @param {string} fieldName - The name of the field to deprecate.
1770
+ */
1771
+ deprecateField: (fieldName) => {
1772
+ migrate.push({ type: "deprecateField", name: fieldName });
1773
+ rollback.push({
1774
+ type: "modifyField",
1775
+ name: fieldName,
1776
+ changes: { deprecated: false }
1777
+ });
1778
+ },
1779
+ /**
1780
+ * Adds a new index to the schema.
1781
+ * @param {IndexDefinition} indexDefinition - The definition of the index to add.
1782
+ */
1783
+ addIndex: (indexDefinition) => {
1784
+ migrate.push({ type: "addIndex", definition: indexDefinition });
1785
+ rollback.push({ type: "removeIndex", name: indexDefinition.name });
1786
+ },
1787
+ /**
1788
+ * Removes an index from the schema.
1789
+ * @param {string} indexName - The name of the index to remove.
1790
+ */
1791
+ removeIndex: (indexName) => {
1792
+ migrate.push({ type: "removeIndex", name: indexName });
1793
+ const originalIndex = schema.indexes?.find((index) => index.name === indexName);
1794
+ if (originalIndex) {
1795
+ rollback.push({ type: "addIndex", definition: originalIndex });
1796
+ }
1797
+ },
1798
+ /**
1799
+ * Modifies an existing index in the schema.
1800
+ * @param {string} indexName - The name of the index to modify.
1801
+ * @param {Partial<IndexDefinition>} changes - The changes to apply to the index.
1802
+ */
1803
+ modifyIndex: (indexName, changes) => {
1804
+ migrate.push({ type: "modifyIndex", name: indexName, changes });
1805
+ const originalIndex = schema.indexes?.find((index) => index.name === indexName);
1806
+ if (originalIndex) {
1807
+ rollback.push({ type: "modifyIndex", name: indexName, changes: originalIndex });
1808
+ }
1809
+ },
1810
+ /**
1811
+ * Adds a new constraint to the schema.
1812
+ * @param {SchemaConstraint<any>} constraint - The constraint to add.
1813
+ */
1814
+ addConstraint: (constraint) => {
1815
+ migrate.push({ type: "addConstraint", constraint });
1816
+ rollback.push({ type: "removeConstraint", name: constraint.name });
1817
+ },
1818
+ /**
1819
+ * Removes a constraint from the schema.
1820
+ * @param {string} constraintName - The name of the constraint to remove.
1821
+ */
1822
+ removeConstraint: (constraintName) => {
1823
+ migrate.push({ type: "removeConstraint", name: constraintName });
1824
+ const originalConstraint = schema.constraints?.find((c) => "name" in c && c.name === constraintName);
1825
+ if (originalConstraint) {
1826
+ rollback.push({ type: "addConstraint", constraint: originalConstraint });
1827
+ }
1828
+ },
1829
+ /**
1830
+ * Modifies an existing constraint in the schema.
1831
+ * @param {string} constraintName - The name of the constraint to modify.
1832
+ * @param {Partial<SchemaConstraint<any>>} changes - The changes to apply to the constraint.
1833
+ */
1834
+ modifyConstraint: (constraintName, changes) => {
1835
+ migrate.push({ type: "modifyConstraint", name: constraintName, changes });
1836
+ const originalConstraint = schema.constraints?.find((c) => "name" in c && c.name === constraintName);
1837
+ if (originalConstraint) {
1838
+ rollback.push({ type: "modifyConstraint", name: constraintName, changes: originalConstraint });
1839
+ }
1840
+ },
1841
+ /**
1842
+ * Returns the migration changes and their corresponding rollback changes.
1843
+ * @returns {Object} An object containing the migrate and rollback changes.
1844
+ */
1845
+ changes: () => ({
1846
+ migrate,
1847
+ rollback
1848
+ })
1849
+ };
1850
+ };
1851
+
1852
+ // src/lib/persistence/collection.ts
1853
+ var EmphemeralCollection = class {
1854
+ definition;
1855
+ // Stores the schema definition for the collection.
1856
+ collectionEventBus;
1857
+ // Event bus for collection-related events.
1858
+ validator;
1859
+ collectionData = [];
1860
+ // Array to store the collection data.
1861
+ predicateMap;
1862
+ // Map of predicate names to their implementations.
1863
+ match;
1864
+ project;
1865
+ sort;
1866
+ paginate;
1867
+ migrator;
1868
+ /**
1869
+ * @constructor
1870
+ * @param {Record<string, Function>} functionMap Map of function names to their implementations.
1871
+ * @param {Record<string, (params: any) => boolean>} predicateMap Map of predicate names to their implementations.
1872
+ */
1873
+ constructor(schema, functionMap, predicateMap) {
1874
+ this.definition = schema;
1875
+ this.collectionEventBus = createEventBus();
1876
+ this.predicateMap = predicateMap;
1877
+ this.validator = createStandardSchemaValidator(schema, predicateMap)["~standard"];
1878
+ this.match = createMatcher(functionMap);
1879
+ this.project = createProjector(functionMap);
1880
+ this.sort = createSorter();
1881
+ this.paginate = createPaginator();
1882
+ this.migrator = new MigrationEngine(schema);
1883
+ }
1884
+ /**
1885
+ * @method schema
1886
+ * @description Returns the schema definition for the collection.
1887
+ * @returns {SchemaDefinition | null} The schema definition, or null if not set.
1888
+ */
1889
+ schema() {
1890
+ return this.definition;
1891
+ }
1892
+ /**
1893
+ * @method create
1894
+ * @description Creates new data in the collection.
1895
+ * @param {{ data: DataType | DataType[] }} The data to create.
1896
+ * @returns {Promise<DataType | DataType[]>} The created data.
1897
+ */
1898
+ async create({ data }) {
1899
+ const dataArray = Array.isArray(data) ? data : [data];
1900
+ const allIssues = dataArray.reduce(
1901
+ (acc, item) => {
1902
+ const validationResult = this.validate(item);
1903
+ if (validationResult.issues) {
1904
+ acc.push(...validationResult.issues);
1905
+ }
1906
+ return acc;
1907
+ },
1908
+ []
1909
+ );
1910
+ if (allIssues.length > 0) {
1911
+ this.emitCollectionEvent("create:failed", {
1912
+ operation: "create",
1913
+ collection: this.definition?.name || "",
1914
+ input: dataArray,
1915
+ type: "create:failed",
1916
+ timestamp: Date.now(),
1917
+ issues: allIssues
1918
+ });
1919
+ throw new Error(`Invalid data: ${JSON.stringify(allIssues)}`);
1920
+ }
1921
+ this.collectionData.push(...dataArray);
1922
+ this.emitCollectionEvent("create:success", {
1923
+ operation: "create",
1924
+ collection: this.definition?.name || "",
1925
+ input: dataArray,
1926
+ output: dataArray,
1927
+ type: "create:success",
1928
+ timestamp: Date.now()
1929
+ });
1930
+ return data;
1931
+ }
1932
+ /**
1933
+ * @method read
1934
+ * @description Reads data from the collection based on the provided query.
1935
+ * @param {QueryDSL<T>} [query] Optional query to filter the data.
1936
+ * @returns {Promise<T[]>} An array of data matching the query.
1937
+ */
1938
+ async read({
1939
+ query
1940
+ }) {
1941
+ this.emitCollectionEvent("read:start", {
1942
+ operation: "read",
1943
+ collection: this.definition?.name,
1944
+ query,
1945
+ type: "read:start",
1946
+ timestamp: Date.now()
1947
+ });
1948
+ let result = this.collectionData;
1949
+ if (query.filters) {
1950
+ result = result.filter(
1951
+ (item) => this.match.match(item, query.filters)
1952
+ );
1953
+ }
1954
+ if (query.projection) {
1955
+ result = result.map(
1956
+ (item) => this.project.project(item, query.projection)
1957
+ );
1958
+ }
1959
+ if (query.sort) {
1960
+ result = this.sort.sort(result, query.sort);
1961
+ }
1962
+ if (query.pagination) {
1963
+ const paginator = this.paginate.paginate(result, query.pagination);
1964
+ result = (await paginator.next()).value;
1965
+ }
1966
+ this.emitCollectionEvent("read:success", {
1967
+ operation: "read",
1968
+ collection: this.definition?.name,
1969
+ query,
1970
+ output: result,
1971
+ type: "read:success",
1972
+ timestamp: Date.now()
1973
+ });
1974
+ return result;
1975
+ }
1976
+ /**
1977
+ * @method update
1978
+ * @description Updates data in the collection based on the provided query and update data.
1979
+ * @param {{ data?: Partial<T>; patch?: PatchOperation | Array<PatchOperation>; query: QueryFilter }} The update parameters.
1980
+ * @returns {Array<T>} The updated data.
1981
+ */
1982
+ async update({
1983
+ data,
1984
+ patch,
1985
+ query
1986
+ }) {
1987
+ this.emitCollectionEvent("update:start", {
1988
+ operation: "update",
1989
+ collection: this.definition?.name,
1990
+ input: data,
1991
+ query,
1992
+ type: "update:start",
1993
+ timestamp: Date.now()
1994
+ });
1995
+ const results = [];
1996
+ this.collectionData.forEach((i, index) => {
1997
+ if (!this.match.match(i, query)) return;
1998
+ let result = i;
1999
+ if (data) {
2000
+ result = deepMerge(result, data);
2001
+ }
2002
+ if (patch) {
2003
+ const changes = Array.isArray(patch) ? patch : [patch];
2004
+ result = applyPatch(result, changes);
2005
+ }
2006
+ this.collectionData[index] = result;
2007
+ results.push(result);
2008
+ });
2009
+ this.emitCollectionEvent("update:success", {
2010
+ operation: "update",
2011
+ collection: this.definition?.name,
2012
+ input: data,
2013
+ query,
2014
+ output: results,
2015
+ type: "update:success",
2016
+ timestamp: Date.now()
2017
+ });
2018
+ return results;
2019
+ }
2020
+ /**
2021
+ * @method delete
2022
+ * @description Deletes data from the collection based on the provided query.
2023
+ * @param {{ query: QueryFilter<T> }} The query to use for deleting data.
2024
+ * @returns {number} The number of deleted items.
2025
+ */
2026
+ async delete({ query }) {
2027
+ this.emitCollectionEvent("delete:start", {
2028
+ operation: "delete",
2029
+ collection: this.definition?.name,
2030
+ query,
2031
+ type: "delete:start",
2032
+ timestamp: Date.now()
2033
+ });
2034
+ const beforeCount = this.collectionData.length;
2035
+ const remainingItems = this.collectionData.filter(
2036
+ (item) => !this.match.match(item, query)
2037
+ );
2038
+ const deletedCount = beforeCount - remainingItems.length;
2039
+ this.collectionData = remainingItems;
2040
+ this.emitCollectionEvent("delete:success", {
2041
+ operation: "delete",
2042
+ collection: this.definition?.name,
2043
+ query,
2044
+ context: { deletedCount },
2045
+ type: "delete:success",
2046
+ timestamp: Date.now()
2047
+ });
2048
+ return deletedCount;
2049
+ }
2050
+ /**
2051
+ * @method validate
2052
+ * @description Validates data against the collection's schema.
2053
+ * @param {T} data The data to validate.
2054
+ * @returns {{ valid: boolean; issues: StandardSchemaV1.Issue[] | null }} An object containing the validation result.
2055
+ */
2056
+ validate(data) {
2057
+ if (!this.definition) {
2058
+ throw new Error("No schema exists. Call setSchema first.");
2059
+ }
2060
+ if (!this.validator) {
2061
+ this.validator = createStandardSchemaValidator(
2062
+ this.definition,
2063
+ this.predicateMap
2064
+ )["~standard"];
2065
+ }
2066
+ const results = this.validator.validate(
2067
+ data
2068
+ );
2069
+ return { valid: !results.issues, issues: results.issues || null };
2070
+ }
2071
+ /**
2072
+ * @method emitCollectionEvent
2073
+ * @description Emits a collection-related event.
2074
+ * @param {PersistenceEventType} type The type of the event.
2075
+ * @param {PersistenceEvent<SchemaDefinition>} payload The event payload.
2076
+ */
2077
+ emitCollectionEvent(type, payload) {
2078
+ this.collectionEventBus.emit({ name: type, payload });
2079
+ }
2080
+ /**
2081
+ * @method subscribeToCollectionEvents
2082
+ * @description Subscribes to collection-related events.
2083
+ * @param {PersistenceEventType} event The type of the event to subscribe to.
2084
+ * @param {(payload: PersistenceEvent<SchemaDefinition>) => void} callback The callback function.
2085
+ * @returns {() => void} A function to unsubscribe.
2086
+ */
2087
+ subscribe(event, callback) {
2088
+ return this.collectionEventBus.subscribe(event, callback);
2089
+ }
2090
+ async rollback(version, dryRun = true) {
2091
+ this.emitCollectionEvent("rollback:start", {
2092
+ operation: "rollback",
2093
+ collection: this.definition?.name,
2094
+ input: { version },
2095
+ type: "rollback:start",
2096
+ timestamp: Date.now(),
2097
+ context: {
2098
+ dryRun
2099
+ }
2100
+ });
2101
+ if (dryRun) {
2102
+ const input = new ReadableStream({
2103
+ start(controller) {
2104
+ controller.close();
2105
+ }
2106
+ });
2107
+ const result = await this.migrator.dryRun(input, "backward", version);
2108
+ this.emitCollectionEvent("migrate:success", {
2109
+ operation: "rollback",
2110
+ collection: this.definition?.name,
2111
+ input: { version },
2112
+ type: "migrate:success",
2113
+ timestamp: Date.now(),
2114
+ context: {
2115
+ dryRun
2116
+ }
2117
+ });
2118
+ return result;
2119
+ }
2120
+ try {
2121
+ const data = this.collectionData;
2122
+ const input = new ReadableStream({
2123
+ start(controller) {
2124
+ data.forEach((i) => controller.enqueue(i));
2125
+ controller.close();
2126
+ }
2127
+ });
2128
+ const output = Boolean(version) ? await this.migrator.rollbackToVersion(version, input) : await this.migrator.rollback(input);
2129
+ const reader = output.getReader();
2130
+ let value = await reader.read();
2131
+ const result = [];
2132
+ do {
2133
+ if (value.value) {
2134
+ result.push(value.value);
2135
+ }
2136
+ value = await reader.read();
2137
+ } while (!value.done);
2138
+ this.collectionData = result;
2139
+ this.definition = this.migrator.data().schema;
2140
+ this.validator = createStandardSchemaValidator(this.definition, this.predicateMap)["~standard"];
2141
+ this.emitCollectionEvent("rollback:failed", {
2142
+ operation: "rollback",
2143
+ collection: this.definition?.name,
2144
+ input: { version },
2145
+ type: "rollback:failed",
2146
+ timestamp: Date.now(),
2147
+ context: {
2148
+ dryRun
2149
+ }
2150
+ });
2151
+ } catch (error) {
2152
+ this.emitCollectionEvent("migrate:failed", {
2153
+ operation: "rollback",
2154
+ collection: this.definition?.name,
2155
+ input: { version },
2156
+ type: "migrate:failed",
2157
+ timestamp: Date.now(),
2158
+ error,
2159
+ context: {
2160
+ dryRun,
2161
+ error
2162
+ }
2163
+ });
2164
+ }
2165
+ }
2166
+ async migrate(description, cb, dryRun = true) {
2167
+ const helper = createSchemaMigrationHelper(this.definition);
2168
+ const transform = cb(helper);
2169
+ const { migrate, rollback } = helper.changes();
2170
+ this.emitCollectionEvent("migrate:start", {
2171
+ operation: "migrate",
2172
+ collection: this.definition?.name,
2173
+ input: { migrate, rollback },
2174
+ type: "migrate:start",
2175
+ timestamp: Date.now(),
2176
+ context: {
2177
+ dryRun
2178
+ }
2179
+ });
2180
+ await this.migrator.add({
2181
+ description,
2182
+ changes: migrate,
2183
+ rollback,
2184
+ transform
2185
+ });
2186
+ try {
2187
+ if (dryRun) {
2188
+ const input2 = new ReadableStream({
2189
+ start(controller) {
2190
+ controller.close();
2191
+ }
2192
+ });
2193
+ const result2 = await this.migrator.dryRun(input2, "forward");
2194
+ this.emitCollectionEvent("migrate:success", {
2195
+ operation: "migrate",
2196
+ collection: this.definition?.name,
2197
+ input: { migrate, rollback },
2198
+ type: "migrate:success",
2199
+ timestamp: Date.now(),
2200
+ context: {
2201
+ dryRun
2202
+ }
2203
+ });
2204
+ return result2;
2205
+ }
2206
+ const data = this.collectionData;
2207
+ const input = new ReadableStream({
2208
+ start(controller) {
2209
+ data.forEach((i) => controller.enqueue(i));
2210
+ controller.close();
2211
+ }
2212
+ });
2213
+ const output = await this.migrator.migrate(input);
2214
+ const reader = output.getReader();
2215
+ let value = await reader.read();
2216
+ const result = [];
2217
+ do {
2218
+ if (value.value) {
2219
+ result.push(value.value);
2220
+ }
2221
+ value = await reader.read();
2222
+ } while (!value.done);
2223
+ this.collectionData = result;
2224
+ this.definition = this.migrator.data().schema;
2225
+ this.validator = createStandardSchemaValidator(this.definition, this.predicateMap)["~standard"];
2226
+ this.emitCollectionEvent("migrate:success", {
2227
+ operation: "migrate",
2228
+ collection: this.definition?.name,
2229
+ input: { migrate, rollback },
2230
+ type: "migrate:success",
2231
+ timestamp: Date.now(),
2232
+ context: {
2233
+ dryRun
2234
+ }
2235
+ });
2236
+ } catch (error) {
2237
+ this.emitCollectionEvent("migrate:failed", {
2238
+ operation: "migrate",
2239
+ collection: this.definition?.name,
2240
+ input: { migrate, rollback },
2241
+ type: "migrate:failed",
2242
+ timestamp: Date.now(),
2243
+ error,
2244
+ context: {
2245
+ dryRun,
2246
+ error
2247
+ }
2248
+ });
2249
+ }
2250
+ }
2251
+ };
2252
+
2253
+ // src/lib/persistence/index.ts
2254
+ function createEphemeralPersistence(functionMap, predicateMap) {
2255
+ const bus = createEventBus2();
2256
+ const data = /* @__PURE__ */ new Map();
2257
+ function subscribe(event, callback) {
2258
+ return bus.subscribe(event, callback);
2259
+ }
2260
+ function transact(callback) {
2261
+ return callback({
2262
+ createCollection,
2263
+ deleteCollection,
2264
+ collections,
2265
+ schema,
2266
+ collection
2267
+ });
2268
+ }
2269
+ async function createCollection(schema2) {
2270
+ if (data.has(schema2.name)) {
2271
+ bus.emit({
2272
+ name: "collection:create:failed",
2273
+ payload: {
2274
+ operation: "create",
2275
+ collection: schema2.name,
2276
+ input: schema2,
2277
+ type: "collection:create:failed",
2278
+ timestamp: Date.now()
2279
+ }
2280
+ });
2281
+ throw new Error("Collection exists!");
2282
+ }
2283
+ const collection2 = new EmphemeralCollection(
2284
+ schema2,
2285
+ functionMap,
2286
+ predicateMap
2287
+ );
2288
+ data.set(schema2.name, collection2);
2289
+ bus.emit({
2290
+ name: "collection:create:success",
2291
+ payload: {
2292
+ operation: "create",
2293
+ collection: schema2.name,
2294
+ input: schema2,
2295
+ type: "collection:create:success",
2296
+ timestamp: Date.now()
2297
+ }
2298
+ });
2299
+ return collection2;
2300
+ }
2301
+ async function deleteCollection(id) {
2302
+ if (data.has(id)) {
2303
+ data.delete(id);
2304
+ bus.emit({
2305
+ name: "collection:delete:success",
2306
+ payload: {
2307
+ operation: "delete",
2308
+ collection: id,
2309
+ input: id,
2310
+ type: "collection:delete:success",
2311
+ timestamp: Date.now()
2312
+ }
2313
+ });
2314
+ } else {
2315
+ bus.emit({
2316
+ name: "collection:delete:failed",
2317
+ payload: {
2318
+ operation: "delete",
2319
+ collection: id,
2320
+ input: id,
2321
+ type: "collection:delete:failed",
2322
+ timestamp: Date.now()
2323
+ }
2324
+ });
2325
+ throw new Error("Collection not found!");
2326
+ }
2327
+ }
2328
+ async function collections() {
2329
+ return Array.from(data.keys());
2330
+ }
2331
+ async function schema(id) {
2332
+ const collection2 = data.get(id);
2333
+ if (!collection2) throw new Error("Collection not found!");
2334
+ return collection2.schema();
2335
+ }
2336
+ function collection(id) {
2337
+ const coll = data.get(id);
2338
+ if (!coll) throw new Error("Collection not found!");
2339
+ return coll;
2340
+ }
2341
+ return {
2342
+ transact,
2343
+ createCollection,
2344
+ deleteCollection,
2345
+ collections,
2346
+ schema,
2347
+ collection,
2348
+ subscribe
2349
+ };
2350
+ }
2351
+
2352
+ // src/lib/registry/index.ts
2353
+ var registry_exports2 = {};
2354
+ __export(registry_exports2, {
2355
+ default: () => createRegistry
2356
+ });
2357
+ import LightningFS from "@isomorphic-git/lightning-fs";
2358
+ import { Buffer as Buffer2 } from "buffer";
2359
+ import git from "isomorphic-git";
2360
+ import http from "isomorphic-git/http/web";
2361
+
2362
+ // src/lib/registry/repository.ts
2363
+ async function createGithubRepository({
2364
+ token,
2365
+ repoConfig
2366
+ }) {
2367
+ try {
2368
+ const response = await fetch("https://api.github.com/user/repos", {
2369
+ method: "POST",
2370
+ headers: {
2371
+ "X-GitHub-Api-Version": "2022-11-28",
2372
+ Accept: "application/vnd.github+json",
2373
+ Authorization: `Bearer ${token}`,
2374
+ "Content-Type": "application/json"
2375
+ },
2376
+ body: JSON.stringify(repoConfig),
2377
+ redirect: "follow"
2378
+ });
2379
+ if (!response.ok) {
2380
+ throw new Error(`HTTP error! status: ${response.status}`);
2381
+ }
2382
+ const data = await response.json();
2383
+ return data;
2384
+ } catch (error) {
2385
+ console.error("Error creating repository:", error);
2386
+ throw error;
2387
+ }
2388
+ }
2389
+
2390
+ // src/lib/registry/utils.ts
2391
+ function serializeGenerator(fn) {
2392
+ const fnStr = fn.toString();
2393
+ const params = fnStr.substring(fnStr.indexOf("(") + 1, fnStr.indexOf(")"));
2394
+ const body = fnStr.substring(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}")).trim();
2395
+ return JSON.stringify({ params, body });
2396
+ }
2397
+ function deserializeGenerator(serialized) {
2398
+ const { params, body } = JSON.parse(serialized);
2399
+ const GeneratorFunction = Object.getPrototypeOf(function* () {
2400
+ }).constructor;
2401
+ return new GeneratorFunction(params, body);
2402
+ }
2403
+ function serializeFunction(fn) {
2404
+ const fnStr = fn.toString();
2405
+ const params = fnStr.substring(fnStr.indexOf("(") + 1, fnStr.indexOf(")"));
2406
+ const body = fnStr.substring(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}")).trim();
2407
+ return JSON.stringify({ params, body });
2408
+ }
2409
+ function deserializeFunction(serialized) {
2410
+ const { params, body } = JSON.parse(serialized);
2411
+ return new Function(params, body);
2412
+ }
2413
+ function authUrl(repoUrl, username, password) {
2414
+ const u = new URL(repoUrl);
2415
+ u.username = username;
2416
+ u.password = password;
2417
+ return u.toString();
2418
+ }
2419
+
2420
+ // src/lib/registry/index.ts
2421
+ window.Buffer = Buffer2;
2422
+ async function createRegistry(credentials, dir = "/registry", proxy = "https://cors.isomorphic-git.org") {
2423
+ const fs = new LightningFS(dir);
2424
+ const pfs = fs.promises;
2425
+ const main = "main";
2426
+ async function init() {
2427
+ await pfs.mkdir(dir);
2428
+ await git.init({ fs, dir, defaultBranch: main });
2429
+ await pfs.writeFile(
2430
+ `${dir}/registry.json`,
2431
+ JSON.stringify({
2432
+ schemas: {},
2433
+ created: (/* @__PURE__ */ new Date()).toISOString(),
2434
+ updated: (/* @__PURE__ */ new Date()).toISOString()
2435
+ })
2436
+ );
2437
+ await git.add({
2438
+ fs,
2439
+ dir,
2440
+ filepath: `registry.json`
2441
+ });
2442
+ await pfs.writeFile(
2443
+ `${dir}/registry.lock`,
2444
+ JSON.stringify({
2445
+ hashes: [],
2446
+ updated: (/* @__PURE__ */ new Date()).toISOString()
2447
+ })
2448
+ );
2449
+ await git.add({
2450
+ fs,
2451
+ dir,
2452
+ filepath: `registry.lock`
2453
+ });
2454
+ await git.commit({
2455
+ fs,
2456
+ dir,
2457
+ author: { name: "bot", email: "bot@registry.domain" },
2458
+ message: "initial commit"
2459
+ });
2460
+ await createGithubRepository({
2461
+ token: credentials.password,
2462
+ repoConfig: {
2463
+ name: credentials.repository,
2464
+ private: true
2465
+ }
2466
+ });
2467
+ await git.addRemote({
2468
+ fs,
2469
+ dir,
2470
+ remote: "origin",
2471
+ url: `https://github.com/${credentials.username}/${credentials.repository}.git`
2472
+ });
2473
+ await git.push({
2474
+ fs,
2475
+ dir,
2476
+ http,
2477
+ remote: "origin",
2478
+ url: authUrl(
2479
+ `https://github.com/${credentials.username}/${credentials.repository}.git`,
2480
+ credentials.username,
2481
+ credentials.password
2482
+ ),
2483
+ corsProxy: proxy,
2484
+ ref: main,
2485
+ onAuth: () => ({
2486
+ username: credentials.username,
2487
+ password: credentials.password
2488
+ })
2489
+ });
2490
+ }
2491
+ async function clone() {
2492
+ await git.clone({
2493
+ fs,
2494
+ dir,
2495
+ http,
2496
+ corsProxy: proxy,
2497
+ url: authUrl(
2498
+ `https://github.com/${credentials.username}/${credentials.repository}.git`,
2499
+ credentials.username,
2500
+ credentials.password
2501
+ ),
2502
+ onAuth: () => ({
2503
+ username: credentials.username,
2504
+ password: credentials.password
2505
+ }),
2506
+ singleBranch: true,
2507
+ depth: 1
2508
+ });
2509
+ }
2510
+ async function create(schema2) {
2511
+ await git.branch({
2512
+ fs,
2513
+ dir,
2514
+ ref: schema2.name,
2515
+ checkout: true
2516
+ });
2517
+ const dirs = [schema2.name, `${schema2.name}/migrations`];
2518
+ for (const filepath of dirs) {
2519
+ await pfs.mkdir(`${dir}/${filepath}`);
2520
+ }
2521
+ const migrations2 = await Promise.all(
2522
+ (schema2.migrations || []).map(async (migration) => {
2523
+ let content = { ...migration };
2524
+ if (migration.transform && typeof migration.transform !== "string") {
2525
+ content.transform = {
2526
+ forward: serializeFunction(migration.transform.forward),
2527
+ backward: serializeFunction(migration.transform.backward)
2528
+ };
2529
+ }
2530
+ content = JSON.stringify(content);
2531
+ const hash = await generateSHA256Hash(content);
2532
+ return {
2533
+ hash,
2534
+ checksum: migration.checksum,
2535
+ content,
2536
+ id: migration.id
2537
+ };
2538
+ })
2539
+ );
2540
+ await pfs.writeFile(`${dir}/${schema2.name}/migrations/.nomedia`, "");
2541
+ for (const { hash, content } of migrations2) {
2542
+ await pfs.writeFile(
2543
+ `${dir}/${schema2.name}/migrations/${hash}.json`,
2544
+ content
2545
+ );
2546
+ }
2547
+ const schemaContent = JSON.stringify({
2548
+ ...schema2,
2549
+ migrations: [],
2550
+ mock: schema2.mock ? serializeGenerator(schema2.mock) : null
2551
+ });
2552
+ const schemaHash = await generateSHA256Hash(schemaContent);
2553
+ await pfs.writeFile(`${dir}/${schema2.name}/schema.json`, schemaContent);
2554
+ const index = {
2555
+ schema: schema2.name,
2556
+ version: schema2.version,
2557
+ history: [
2558
+ {
2559
+ version: schema2.version,
2560
+ hash: schemaHash,
2561
+ date: (/* @__PURE__ */ new Date()).toISOString(),
2562
+ description: schema2.description || "",
2563
+ migrations: migrations2.map(({ id }) => id),
2564
+ changelog: [],
2565
+ predicates: []
2566
+ }
2567
+ ],
2568
+ migrations: migrations2.reduce(
2569
+ (acc, { hash, checksum, id }) => {
2570
+ acc[id] = { hash, checksum };
2571
+ return acc;
2572
+ },
2573
+ {}
2574
+ )
2575
+ };
2576
+ await pfs.writeFile(
2577
+ `${dir}/${schema2.name}/index.json`,
2578
+ JSON.stringify(index)
2579
+ );
2580
+ await git.add({ fs, dir, filepath: schema2.name });
2581
+ await git.commit({
2582
+ fs,
2583
+ dir,
2584
+ author: { name: "bot", email: "bot@registry.domain" },
2585
+ message: `chore: created schema: ${schema2.name}`
2586
+ });
2587
+ await git.tag({
2588
+ fs,
2589
+ dir,
2590
+ ref: `${schema2.name}-${schema2.version}`
2591
+ });
2592
+ await git.checkout({
2593
+ fs,
2594
+ dir,
2595
+ ref: main
2596
+ });
2597
+ await git.merge({
2598
+ fs,
2599
+ dir,
2600
+ author: { name: "bot", email: "bot@registry.domain" },
2601
+ theirs: `${schema2.name}`,
2602
+ message: `add schema: ${schema2.name}`
2603
+ });
2604
+ await git.checkout({ fs, dir, ref: main });
2605
+ const registry = JSON.parse(
2606
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2607
+ );
2608
+ registry.updated = (/* @__PURE__ */ new Date()).toISOString();
2609
+ registry.schemas[schema2.name] = {
2610
+ name: schema2.name,
2611
+ version: schema2.version,
2612
+ description: schema2.description || "",
2613
+ created: (/* @__PURE__ */ new Date()).toISOString(),
2614
+ updated: (/* @__PURE__ */ new Date()).toISOString()
2615
+ };
2616
+ await pfs.writeFile(`${dir}/registry.json`, JSON.stringify(registry));
2617
+ const files = (await git.listFiles({
2618
+ fs,
2619
+ dir
2620
+ })).filter((i) => i !== "registry.lock");
2621
+ const hashes = await Promise.all(
2622
+ files.map(async (file) => {
2623
+ return [file, await generateSHA256Hash(file)];
2624
+ })
2625
+ );
2626
+ await pfs.writeFile(
2627
+ `${dir}/registry.lock`,
2628
+ JSON.stringify({
2629
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
2630
+ hashes
2631
+ })
2632
+ );
2633
+ await git.add({
2634
+ fs,
2635
+ dir,
2636
+ filepath: `registry.lock`
2637
+ });
2638
+ await git.add({
2639
+ fs,
2640
+ dir,
2641
+ filepath: `registry.json`
2642
+ });
2643
+ await git.commit({
2644
+ fs,
2645
+ dir,
2646
+ author: { name: "bot", email: "bot@registry.domain" },
2647
+ message: `fix: created schema: ${schema2.name}`
2648
+ });
2649
+ }
2650
+ async function update(schema2) {
2651
+ await git.checkout({
2652
+ fs,
2653
+ dir,
2654
+ ref: schema2.name
2655
+ });
2656
+ const migrations2 = await Promise.all(
2657
+ (schema2.migrations || []).map(async (migration) => {
2658
+ let content = { ...migration };
2659
+ if (migration.transform && typeof migration.transform !== "string") {
2660
+ content.transform = {
2661
+ forward: serializeFunction(migration.transform.forward),
2662
+ backward: serializeFunction(migration.transform.backward)
2663
+ };
2664
+ }
2665
+ content = JSON.stringify(content);
2666
+ const hash = await generateSHA256Hash(content);
2667
+ return {
2668
+ hash,
2669
+ checksum: migration.checksum,
2670
+ content,
2671
+ id: migration.id
2672
+ };
2673
+ })
2674
+ );
2675
+ for (const { hash, content } of migrations2) {
2676
+ await pfs.writeFile(
2677
+ `${dir}/${schema2.name}/migrations/${hash}.json`,
2678
+ content
2679
+ );
2680
+ }
2681
+ const schemaContent = JSON.stringify({
2682
+ ...schema2,
2683
+ migrations: [],
2684
+ mock: schema2.mock ? serializeGenerator(schema2.mock) : null
2685
+ });
2686
+ const schemaHash = await generateSHA256Hash(schemaContent);
2687
+ await pfs.writeFile(`${dir}/${schema2.name}/schema.json`, schemaContent);
2688
+ const indexPath = `${dir}/${schema2.name}/index.json`;
2689
+ const existingIndex = JSON.parse(
2690
+ (await pfs.readFile(indexPath)).toString()
2691
+ );
2692
+ const newHistoryEntry = {
2693
+ version: schema2.version,
2694
+ hash: schemaHash,
2695
+ date: (/* @__PURE__ */ new Date()).toISOString(),
2696
+ description: schema2.description || "",
2697
+ migrations: migrations2.map(({ id }) => id),
2698
+ changelog: [],
2699
+ predicates: []
2700
+ };
2701
+ existingIndex.history.push(newHistoryEntry);
2702
+ existingIndex.migrations = {
2703
+ ...existingIndex.migrations,
2704
+ ...migrations2.reduce(
2705
+ (acc, { hash, checksum, id }) => {
2706
+ acc[id] = { hash, checksum };
2707
+ return acc;
2708
+ },
2709
+ {}
2710
+ )
2711
+ };
2712
+ await pfs.writeFile(indexPath, JSON.stringify(existingIndex));
2713
+ await git.add({ fs, dir, filepath: schema2.name });
2714
+ await git.commit({
2715
+ fs,
2716
+ dir,
2717
+ author: { name: "bot", email: "bot@registry.domain" },
2718
+ message: `chore: updated schema: ${schema2.name} to version ${schema2.version}`
2719
+ });
2720
+ await git.tag({
2721
+ fs,
2722
+ dir,
2723
+ ref: `${schema2.name}-${schema2.version}`
2724
+ });
2725
+ await git.checkout({
2726
+ fs,
2727
+ dir,
2728
+ ref: main
2729
+ });
2730
+ await git.merge({
2731
+ fs,
2732
+ dir,
2733
+ author: { name: "bot", email: "bot@registry.domain" },
2734
+ theirs: `${schema2.name}`,
2735
+ message: `update schema: ${schema2.name} to version ${schema2.version}`
2736
+ });
2737
+ const registry = JSON.parse(
2738
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2739
+ );
2740
+ registry.updated = (/* @__PURE__ */ new Date()).toISOString();
2741
+ registry.schemas[schema2.name] = {
2742
+ name: schema2.name,
2743
+ version: schema2.version,
2744
+ description: schema2.description || "",
2745
+ created: registry.schemas[schema2.name]?.created || (/* @__PURE__ */ new Date()).toISOString(),
2746
+ updated: (/* @__PURE__ */ new Date()).toISOString()
2747
+ };
2748
+ await pfs.writeFile(`${dir}/registry.json`, JSON.stringify(registry));
2749
+ const files = (await git.listFiles({
2750
+ fs,
2751
+ dir
2752
+ })).filter((i) => i !== "registry.lock");
2753
+ const hashes = await Promise.all(
2754
+ files.map(async (file) => {
2755
+ return [file, await generateSHA256Hash(file)];
2756
+ })
2757
+ );
2758
+ await pfs.writeFile(
2759
+ `${dir}/registry.lock`,
2760
+ JSON.stringify({
2761
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
2762
+ hashes
2763
+ })
2764
+ );
2765
+ await git.add({
2766
+ fs,
2767
+ dir,
2768
+ filepath: `registry.lock`
2769
+ });
2770
+ await git.add({
2771
+ fs,
2772
+ dir,
2773
+ filepath: `registry.json`
2774
+ });
2775
+ await git.commit({
2776
+ fs,
2777
+ dir,
2778
+ author: { name: "bot", email: "bot@registry.domain" },
2779
+ message: `fix: updated schema: ${schema2.name} to version ${schema2.version}`
2780
+ });
2781
+ await git.checkout({ fs, dir, ref: main });
2782
+ }
2783
+ async function delete_(name) {
2784
+ await git.checkout({
2785
+ fs,
2786
+ dir,
2787
+ ref: main,
2788
+ force: true
2789
+ });
2790
+ await git.deleteBranch({
2791
+ fs,
2792
+ dir,
2793
+ ref: name
2794
+ });
2795
+ const registry = JSON.parse(
2796
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2797
+ );
2798
+ delete registry.schemas[name];
2799
+ registry.updated = (/* @__PURE__ */ new Date()).toISOString();
2800
+ await pfs.writeFile(`${dir}/registry.json`, JSON.stringify(registry));
2801
+ const files = (await git.listFiles({
2802
+ fs,
2803
+ dir
2804
+ })).filter((i) => i !== "registry.lock");
2805
+ const hashes = await Promise.all(
2806
+ files.map(async (file) => {
2807
+ return [file, await generateSHA256Hash(file)];
2808
+ })
2809
+ );
2810
+ await pfs.writeFile(
2811
+ `${dir}/registry.lock`,
2812
+ JSON.stringify({
2813
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
2814
+ hashes
2815
+ })
2816
+ );
2817
+ await git.add({
2818
+ fs,
2819
+ dir,
2820
+ filepath: `registry.json`
2821
+ });
2822
+ await git.add({
2823
+ fs,
2824
+ dir,
2825
+ filepath: `registry.lock`
2826
+ });
2827
+ await git.commit({
2828
+ fs,
2829
+ dir,
2830
+ author: { name: "bot", email: "bot@registry.domain" },
2831
+ message: `chore: deleted schema: ${name}`
2832
+ });
2833
+ }
2834
+ async function list() {
2835
+ await git.checkout({
2836
+ fs,
2837
+ dir,
2838
+ ref: main,
2839
+ force: true
2840
+ });
2841
+ const registry = JSON.parse(
2842
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2843
+ );
2844
+ const result = Object.entries(registry.schemas).map(
2845
+ ([name, { version }]) => ({ name, version })
2846
+ );
2847
+ return result;
2848
+ }
2849
+ async function schema(name, version, migrations2 = false) {
2850
+ await git.checkout({
2851
+ fs,
2852
+ dir,
2853
+ ref: main,
2854
+ force: true
2855
+ });
2856
+ const registry = JSON.parse(
2857
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2858
+ );
2859
+ if (!registry.schemas[name]) {
2860
+ return null;
2861
+ }
2862
+ let ref = name;
2863
+ if (version) {
2864
+ ref = await git.resolveRef({ fs, dir, ref: `${name}-${version}` });
2865
+ }
2866
+ await git.checkout({
2867
+ fs,
2868
+ dir,
2869
+ ref,
2870
+ force: true
2871
+ });
2872
+ const schema2 = JSON.parse(
2873
+ (await pfs.readFile(`${dir}/${name}/schema.json`)).toString()
2874
+ );
2875
+ if (schema2.mock) {
2876
+ schema2.mock = deserializeGenerator(schema2.mock);
2877
+ }
2878
+ if (migrations2) {
2879
+ const migrations3 = await Promise.all(
2880
+ (await pfs.readdir(`${dir}/${name}/migrations`)).filter((i) => i !== ".nomedia").map(
2881
+ async (i) => (await pfs.readFile(`${dir}/${name}/migrations/${i}`)).toString()
2882
+ )
2883
+ );
2884
+ schema2.migrations = migrations3.map((m) => {
2885
+ const migration = JSON.parse(m);
2886
+ migration.transform = {
2887
+ forward: deserializeFunction(migration.transform.forward),
2888
+ backward: deserializeFunction(migration.transform.backward)
2889
+ };
2890
+ return migration;
2891
+ });
2892
+ }
2893
+ await git.checkout({
2894
+ fs,
2895
+ dir,
2896
+ ref: main,
2897
+ force: true
2898
+ });
2899
+ return schema2;
2900
+ }
2901
+ async function stats(schema2) {
2902
+ await git.checkout({
2903
+ fs,
2904
+ dir,
2905
+ ref: main,
2906
+ force: true
2907
+ });
2908
+ if (schema2) {
2909
+ const index = JSON.parse(
2910
+ (await pfs.readFile(`${dir}/${schema2}/index.json`)).toString()
2911
+ );
2912
+ return index;
2913
+ } else {
2914
+ const index = JSON.parse(
2915
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2916
+ );
2917
+ return index;
2918
+ }
2919
+ }
2920
+ async function sync() {
2921
+ await git.pull({
2922
+ fs,
2923
+ dir,
2924
+ http,
2925
+ remote: "origin",
2926
+ corsProxy: proxy,
2927
+ ref: main,
2928
+ author: { name: "bot", email: "bot@registry.domain" },
2929
+ fastForwardOnly: true,
2930
+ url: authUrl(
2931
+ `https://github.com/${credentials.username}/${credentials.repository}.git`,
2932
+ credentials.username,
2933
+ credentials.password
2934
+ ),
2935
+ onAuth: () => ({
2936
+ username: credentials.username,
2937
+ password: credentials.password
2938
+ })
2939
+ });
2940
+ await git.push({
2941
+ fs,
2942
+ http,
2943
+ dir,
2944
+ corsProxy: proxy,
2945
+ remote: "origin",
2946
+ ref: main,
2947
+ url: authUrl(
2948
+ `https://github.com/${credentials.username}/${credentials.repository}.git`,
2949
+ credentials.username,
2950
+ credentials.password
2951
+ ),
2952
+ onAuth: () => ({
2953
+ username: credentials.username,
2954
+ password: credentials.password
2955
+ })
2956
+ });
2957
+ }
2958
+ async function predicates(name, version) {
2959
+ throw new Error("predicates not implemented");
2960
+ }
2961
+ async function migrations(name, version) {
2962
+ await git.checkout({
2963
+ fs,
2964
+ dir,
2965
+ ref: main,
2966
+ force: true
2967
+ });
2968
+ const registry = JSON.parse(
2969
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
2970
+ );
2971
+ if (!registry.schemas[name]) {
2972
+ return [];
2973
+ }
2974
+ let effectiveVersion = version || registry.schemas[name].version;
2975
+ const index = JSON.parse(
2976
+ (await pfs.readFile(`${dir}/${name}/index.json`)).toString()
2977
+ );
2978
+ const compatibleMigrations = [];
2979
+ for (const migrationId of Object.keys(index.migrations)) {
2980
+ const { hash } = index.migrations[migrationId];
2981
+ const migrationFile = `${dir}/${name}/migrations/${hash}.json`;
2982
+ const migrationContent = JSON.parse(
2983
+ (await pfs.readFile(migrationFile)).toString()
2984
+ );
2985
+ if (compareSemanticVersions(
2986
+ migrationContent.schemaVersion,
2987
+ effectiveVersion
2988
+ ) <= 0) {
2989
+ migrationContent.transform = {
2990
+ forward: deserializeFunction(migrationContent.transform.forward),
2991
+ backward: deserializeFunction(migrationContent.transform.backward)
2992
+ };
2993
+ compatibleMigrations.push(migrationContent);
2994
+ }
2995
+ }
2996
+ return compatibleMigrations.sort(
2997
+ (a, b) => compareSemanticVersions(a.schemaVersion, b.schemaVersion)
2998
+ );
2999
+ }
3000
+ async function history(name) {
3001
+ await git.checkout({
3002
+ fs,
3003
+ dir,
3004
+ ref: main,
3005
+ force: true
3006
+ });
3007
+ const registry = JSON.parse(
3008
+ (await pfs.readFile(`${dir}/registry.json`)).toString()
3009
+ );
3010
+ if (!registry.schemas[name]) {
3011
+ return [];
3012
+ }
3013
+ const index = JSON.parse(
3014
+ (await pfs.readFile(`${dir}/${name}/index.json`)).toString()
3015
+ );
3016
+ const historicalSchemas = [];
3017
+ for (const historyEntry of index.history) {
3018
+ const schemaDefinition = await schema(name, historyEntry.version, true);
3019
+ if (schemaDefinition) {
3020
+ historicalSchemas.push(schemaDefinition);
3021
+ }
3022
+ }
3023
+ return historicalSchemas.sort(
3024
+ (a, b) => compareSemanticVersions(a.version, b.version)
3025
+ );
3026
+ }
3027
+ return {
3028
+ init,
3029
+ clone,
3030
+ create,
3031
+ update,
3032
+ delete: delete_,
3033
+ list,
3034
+ schema,
3035
+ stats,
3036
+ sync,
3037
+ predicates,
3038
+ migrations,
3039
+ history
3040
+ };
3041
+ }
3042
+
3043
+ // src/lib/schema/index.ts
3044
+ var schema_exports = {};
3045
+ __export(schema_exports, {
3046
+ MigrationSchema: () => MigrationSchema,
3047
+ createSchemaMigrationHelper: () => createSchemaMigrationHelper,
3048
+ validate: () => validate,
3049
+ validateMigration: () => validateMigration,
3050
+ validateSchemaChange: () => validateSchemaChange,
3051
+ validateSchemaDefinition: () => validateSchemaDefinition
3052
+ });
3053
+
3054
+ // src/tools/typegen.ts
3055
+ var typegen_exports = {};
3056
+ __export(typegen_exports, {
3057
+ default: () => typegen_default,
3058
+ schemaToTypes: () => schemaToTypes
3059
+ });
3060
+ function convertFieldTypeToTS(field, parentType, fieldName) {
3061
+ switch (field.type) {
3062
+ case "string":
3063
+ return "string";
3064
+ case "number":
3065
+ return "number";
3066
+ case "boolean":
3067
+ return "boolean";
3068
+ case "array":
3069
+ if (field.itemsType) {
3070
+ if (field.itemsType === "object" && field.nestedSchema) {
3071
+ const nestedTypeName = `${parentType}ItemsItem`;
3072
+ return `${nestedTypeName}[]`;
3073
+ }
3074
+ return `${field.itemsType}[]`;
3075
+ }
3076
+ return "any[]";
3077
+ case "object":
3078
+ if (field.nestedSchema) {
3079
+ return `${parentType}${capitalize(fieldName)}`;
3080
+ }
3081
+ return "Record<string, any>";
3082
+ case "dynamic":
3083
+ return "any";
3084
+ default:
3085
+ return "any";
3086
+ }
3087
+ }
3088
+ function generateNestedTypes(fields, parentName) {
3089
+ let types = "";
3090
+ for (const [fieldName, field] of Object.entries(fields)) {
3091
+ if (field.type === "object" && field.nestedSchema) {
3092
+ const typeName = `${parentName}${capitalize(fieldName)}`;
3093
+ types += `
3094
+ export interface ${typeName} {
3095
+ ${generateTypeProperties(field.nestedSchema, typeName)}
3096
+ }`;
3097
+ const nestedTypes = generateNestedTypes(field.nestedSchema, typeName);
3098
+ if (nestedTypes) {
3099
+ types += `
3100
+ ${nestedTypes}`;
3101
+ }
3102
+ } else if (field.type === "array" && field.itemsType === "object" && field.nestedSchema) {
3103
+ const typeName = `${parentName}ItemsItem`;
3104
+ types += `
3105
+ export interface ${typeName} {
3106
+ ${generateTypeProperties(field.nestedSchema, typeName)}
3107
+ }`;
3108
+ const nestedTypes = generateNestedTypes(field.nestedSchema, typeName);
3109
+ if (nestedTypes) {
3110
+ types += `
3111
+ ${nestedTypes}`;
3112
+ }
3113
+ }
3114
+ }
3115
+ return types;
3116
+ }
3117
+ function generateTypeProperties(fields, parentType) {
3118
+ return Object.entries(fields).map(([fieldName, field]) => {
3119
+ const lines = [];
3120
+ if (field.description) {
3121
+ lines.push(` /** ${field.description} */`);
3122
+ }
3123
+ if (field.deprecated) {
3124
+ lines.push(" /** @deprecated */");
3125
+ }
3126
+ const optional = !field.required ? "?" : "";
3127
+ const tsType = convertFieldTypeToTS(field, parentType, fieldName);
3128
+ lines.push(` ${fieldName}${optional}: ${tsType};`);
3129
+ return lines.join("\n");
3130
+ }).join("\n");
3131
+ }
3132
+ function capitalize(str) {
3133
+ return str.charAt(0).toUpperCase() + str.slice(1);
3134
+ }
3135
+ function schemaToTypes(schema) {
3136
+ const mainTypeName = capitalize(schema.name);
3137
+ let output = `// Generated from schema version ${schema.version}
3138
+ `;
3139
+ if (schema.description) {
3140
+ output += `/** ${schema.description} */
3141
+ `;
3142
+ }
3143
+ output += `export interface ${mainTypeName} {
3144
+ ${generateTypeProperties(schema.fields, mainTypeName)}
3145
+ }`;
3146
+ const nestedTypes = generateNestedTypes(schema.fields, mainTypeName);
3147
+ if (nestedTypes) {
3148
+ output += `
3149
+ ${nestedTypes}`;
3150
+ }
3151
+ output += "\n";
3152
+ return output;
3153
+ }
3154
+ var typegen_default = schemaToTypes;
3155
+ export {
3156
+ migrations_exports as MigrationTypes,
3157
+ persistence_exports as PersistenceTypes,
3158
+ registry_exports as RegistryType,
3159
+ schema_definition_exports as SchemaTypes,
3160
+ crypto_exports as crypto,
3161
+ merge_exports as merge,
3162
+ migration_exports as migration,
3163
+ patch_exports as patch,
3164
+ persistence_exports2 as persistence,
3165
+ registry_exports2 as registry,
3166
+ schema_exports as schema,
3167
+ typegen_exports as typegen,
3168
+ validator_exports as validator,
3169
+ version_exports as version
3170
+ };