@beechcms/core 0.5.0 → 0.6.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/auth/hash-provider.d.ts.map +1 -1
  2. package/dist/auth/hash-provider.js +2 -0
  3. package/dist/auth/password-reset-token.repository.d.ts.map +1 -1
  4. package/dist/auth/password-reset-token.repository.js +2 -0
  5. package/dist/auth/session.repository.d.ts.map +1 -1
  6. package/dist/auth/session.repository.js +2 -0
  7. package/dist/auth/token-service.d.ts +2 -0
  8. package/dist/auth/token-service.d.ts.map +1 -1
  9. package/dist/auth/token-service.js +2 -0
  10. package/dist/auth/user.repository.d.ts +4 -1
  11. package/dist/auth/user.repository.d.ts.map +1 -1
  12. package/dist/auth/user.repository.js +2 -0
  13. package/dist/automations-grammar-words.d.ts.map +1 -1
  14. package/dist/automations-grammar-words.js +2 -0
  15. package/dist/automations.repository.interface.d.ts.map +1 -1
  16. package/dist/automations.repository.interface.js +2 -0
  17. package/dist/automations.runner.interface.d.ts.map +1 -1
  18. package/dist/automations.runner.interface.js +2 -0
  19. package/dist/automations.runner.stub.d.ts.map +1 -1
  20. package/dist/automations.runner.stub.js +2 -0
  21. package/dist/automations.types.d.ts +2 -0
  22. package/dist/automations.types.d.ts.map +1 -1
  23. package/dist/automations.types.js +2 -0
  24. package/dist/clock.d.ts.map +1 -1
  25. package/dist/clock.js +2 -0
  26. package/dist/content-scan.repository.d.ts.map +1 -1
  27. package/dist/content-scan.repository.js +2 -0
  28. package/dist/content.repository.d.ts +62 -0
  29. package/dist/content.repository.d.ts.map +1 -1
  30. package/dist/content.repository.js +18 -0
  31. package/dist/define-seed.d.ts.map +1 -1
  32. package/dist/define-seed.js +2 -0
  33. package/dist/demo-data.repository.d.ts +5 -0
  34. package/dist/demo-data.repository.d.ts.map +1 -0
  35. package/dist/demo-data.repository.js +3 -0
  36. package/dist/engine.d.ts +76 -0
  37. package/dist/engine.d.ts.map +1 -1
  38. package/dist/engine.js +246 -5
  39. package/dist/file-types.d.ts +13 -0
  40. package/dist/file-types.d.ts.map +1 -0
  41. package/dist/file-types.js +85 -0
  42. package/dist/id-generator.d.ts +7 -0
  43. package/dist/id-generator.d.ts.map +1 -1
  44. package/dist/id-generator.js +5 -0
  45. package/dist/idempotency.repository.d.ts.map +1 -1
  46. package/dist/idempotency.repository.js +2 -0
  47. package/dist/index.d.ts +12 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +14 -1
  50. package/dist/layout-permissions.d.ts +3 -0
  51. package/dist/layout-permissions.d.ts.map +1 -0
  52. package/dist/layout-permissions.js +11 -0
  53. package/dist/media.repository.d.ts.map +1 -1
  54. package/dist/media.repository.js +2 -0
  55. package/dist/notifications/notification-service.d.ts.map +1 -1
  56. package/dist/notifications/notification-service.js +2 -0
  57. package/dist/notifications/notification.repository.d.ts.map +1 -1
  58. package/dist/notifications/notification.repository.js +2 -9
  59. package/dist/observability/activity-log.repository.d.ts.map +1 -1
  60. package/dist/observability/activity-log.repository.js +2 -0
  61. package/dist/observability/activity-logger.d.ts +2 -2
  62. package/dist/observability/activity-logger.d.ts.map +1 -1
  63. package/dist/observability/activity-logger.js +2 -11
  64. package/dist/observability/analytics.repository.d.ts.map +1 -1
  65. package/dist/observability/analytics.repository.js +2 -0
  66. package/dist/policies.d.ts.map +1 -1
  67. package/dist/policies.js +2 -0
  68. package/dist/rate-limit/rate-limiter.d.ts.map +1 -1
  69. package/dist/rate-limit/rate-limiter.js +2 -0
  70. package/dist/relations.d.ts +28 -0
  71. package/dist/relations.d.ts.map +1 -0
  72. package/dist/relations.js +25 -0
  73. package/dist/richtext-render.d.ts.map +1 -1
  74. package/dist/richtext-render.js +2 -0
  75. package/dist/richtext.d.ts.map +1 -1
  76. package/dist/richtext.js +2 -0
  77. package/dist/scheduler.interface.d.ts.map +1 -1
  78. package/dist/scheduler.interface.js +2 -0
  79. package/dist/scheduler.stub.d.ts.map +1 -1
  80. package/dist/scheduler.stub.js +2 -0
  81. package/dist/schema-mutator.d.ts +22 -0
  82. package/dist/schema-mutator.d.ts.map +1 -0
  83. package/dist/schema-mutator.js +3 -0
  84. package/dist/search/search.repository.d.ts.map +1 -1
  85. package/dist/search/search.repository.js +2 -0
  86. package/dist/seed-ddl.d.ts +40 -0
  87. package/dist/seed-ddl.d.ts.map +1 -0
  88. package/dist/seed-ddl.js +100 -0
  89. package/dist/seed-layout.d.ts +117 -0
  90. package/dist/seed-layout.d.ts.map +1 -0
  91. package/dist/seed-layout.js +169 -0
  92. package/dist/seed-layout.repository.d.ts +18 -0
  93. package/dist/seed-layout.repository.d.ts.map +1 -0
  94. package/dist/seed-layout.repository.js +3 -0
  95. package/dist/seed-registry.d.ts +23 -1
  96. package/dist/seed-registry.d.ts.map +1 -1
  97. package/dist/seed-registry.js +105 -0
  98. package/dist/seed-validation.d.ts +23 -0
  99. package/dist/seed-validation.d.ts.map +1 -0
  100. package/dist/seed-validation.js +156 -0
  101. package/dist/seed.repository.d.ts +37 -0
  102. package/dist/seed.repository.d.ts.map +1 -0
  103. package/dist/seed.repository.js +3 -0
  104. package/dist/seeds.d.ts.map +1 -1
  105. package/dist/seeds.js +2 -0
  106. package/dist/site-settings.repository.d.ts +16 -0
  107. package/dist/site-settings.repository.d.ts.map +1 -0
  108. package/dist/site-settings.repository.js +3 -0
  109. package/dist/slug-utils.d.ts.map +1 -1
  110. package/dist/slug-utils.js +2 -0
  111. package/dist/storage.d.ts +12 -38
  112. package/dist/storage.d.ts.map +1 -1
  113. package/dist/storage.js +2 -0
  114. package/dist/types.d.ts +55 -1
  115. package/dist/types.d.ts.map +1 -1
  116. package/dist/types.js +2 -0
  117. package/dist/validation.d.ts +23 -17
  118. package/dist/validation.d.ts.map +1 -1
  119. package/dist/validation.js +428 -379
  120. package/dist/webhook-validation.d.ts +3 -0
  121. package/dist/webhook-validation.d.ts.map +1 -0
  122. package/dist/webhook-validation.js +6 -0
  123. package/dist/widget/widget.repository.d.ts.map +1 -1
  124. package/dist/widget/widget.repository.js +2 -0
  125. package/package.json +5 -4
@@ -0,0 +1,18 @@
1
+ import type { FormLayout } from './seed-layout.js';
2
+ export interface SeedLayoutRecord {
3
+ slug: string;
4
+ layout: FormLayout;
5
+ updatedAt: number;
6
+ updatedBy: string;
7
+ }
8
+ export interface ISeedLayoutRepository {
9
+ /** Return the stored layout for a seed, or null if none was ever saved. */
10
+ get(slug: string): Promise<SeedLayoutRecord | null>;
11
+ /** Return all stored layouts, keyed by slug — used by GET /api/schema to enrich. */
12
+ getAllAsMap(): Promise<Map<string, FormLayout>>;
13
+ /** Upsert. `updatedBy` is the writer's user id. */
14
+ upsert(slug: string, layout: FormLayout, updatedBy: string): Promise<void>;
15
+ /** Remove the stored row — used by the "Reset" action. */
16
+ remove(slug: string): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=seed-layout.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-layout.repository.d.ts","sourceRoot":"","sources":["../src/seed-layout.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IACnD,oFAAoF;IACpF,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;IAC/C,mDAAmD;IACnD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,0DAA0D;IAC1D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC"}
@@ -0,0 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -1,4 +1,4 @@
1
- import type { Seed } from './types.js';
1
+ import type { Seed, Branch } from './types.js';
2
2
  export interface ISeedRegistry {
3
3
  /**
4
4
  * Returns all seeds as a flat array, preserving insertion order.
@@ -46,4 +46,26 @@ export declare class SeedRegistry implements ISeedRegistry {
46
46
  */
47
47
  export declare class InMemorySeedRegistry extends SeedRegistry {
48
48
  }
49
+ /** Finds a branch by its stable id within a Seed. Returns null if not found. */
50
+ export declare function findBranchById(seed: Seed, id: string): Branch | null;
51
+ /**
52
+ * Returns the next free branch id for a seed in the form `br_NN` (zero-padded to 2,
53
+ * growing as needed). Scans existing ids, never reuses a number already present —
54
+ * even if a branch was removed, its id is not recycled (ids must be globally stable
55
+ * for the life of the seed so layouts/automations/FTS triggers never collide).
56
+ */
57
+ export declare function nextBranchId(seed: Pick<Seed, 'branches'>): string;
58
+ /**
59
+ * Returns the input seeds reordered so that every seed appears AFTER all the
60
+ * seeds it depends on (its `relation` branch targets). Pure function — does
61
+ * not read from any global registry.
62
+ *
63
+ * Uses Kahn's algorithm (BFS on in-degree) for cycle detection and topological
64
+ * ordering. Sprint 3 (CLI / migration runner) consumes this to create tables in
65
+ * the correct order without disabling SQLite FK constraints.
66
+ *
67
+ * @throws {Error} When a relation targets an unknown slug not in `seeds`.
68
+ * @throws {Error} When a cyclic dependency is detected, listing involved slugs.
69
+ */
70
+ export declare function sortSeedsByDependencies(seeds: ReadonlyArray<Seed>): Seed[];
49
71
  //# sourceMappingURL=seed-registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../src/seed-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAGtC,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAED,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;gBAEzB,KAAK,EAAE,IAAI,EAAE;IAezB,GAAG,IAAI,IAAI,EAAE;IAIb,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI9B,kBAAkB,IAAI,IAAI,EAAE;IAI5B,cAAc,IAAI,IAAI,EAAE;IAIxB,YAAY,IAAI,IAAI,EAAE;CAGvB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG"}
1
+ {"version":3,"file":"seed-registry.d.ts","sourceRoot":"","sources":["../src/seed-registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,GAAG,IAAI,IAAI,EAAE,CAAA;IAEb;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAE9B;;;;;OAKG;IACH,kBAAkB,IAAI,IAAI,EAAE,CAAA;IAE5B;;;OAGG;IACH,cAAc,IAAI,IAAI,EAAE,CAAA;IAExB;;;OAGG;IACH,YAAY,IAAI,IAAI,EAAE,CAAA;CACvB;AAID,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;gBAEzB,KAAK,EAAE,IAAI,EAAE;IA4BzB,GAAG,IAAI,IAAI,EAAE;IAIb,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI9B,kBAAkB,IAAI,IAAI,EAAE;IAI5B,cAAc,IAAI,IAAI,EAAE;IAIxB,YAAY,IAAI,IAAI,EAAE;CAGvB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,MAAM,CAQjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAsE1E"}
@@ -1,14 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
1
3
  import { AUTOMATION_RESERVED_WORDS } from './automations-grammar-words.js';
4
+ const BRANCH_ID_RE = /^br_[A-Za-z0-9]+$/;
2
5
  export class SeedRegistry {
3
6
  seedMap;
4
7
  orderedSeeds;
5
8
  constructor(seeds) {
6
9
  for (const seed of seeds) {
10
+ const idsInSeed = new Set();
7
11
  for (const branch of seed.branches) {
8
12
  if (AUTOMATION_RESERVED_WORDS.has(branch.alias)) {
9
13
  throw new Error(`Seed "${seed.slug}" uses reserved alias "${branch.alias}". `
10
14
  + `Pick a different alias — this word is used by the automation template grammar.`);
11
15
  }
16
+ if (!branch.id || !BRANCH_ID_RE.test(branch.id)) {
17
+ throw new Error(`Seed "${seed.slug}" branch "${branch.alias}" has invalid id "${branch.id}". `
18
+ + `Expected format ^br_[A-Za-z0-9]+$.`);
19
+ }
20
+ if (idsInSeed.has(branch.id)) {
21
+ throw new Error(`Seed "${seed.slug}" has duplicate branch id "${branch.id}".`);
22
+ }
23
+ idsInSeed.add(branch.id);
12
24
  }
13
25
  }
14
26
  this.orderedSeeds = seeds;
@@ -36,3 +48,96 @@ export class SeedRegistry {
36
48
  */
37
49
  export class InMemorySeedRegistry extends SeedRegistry {
38
50
  }
51
+ /** Finds a branch by its stable id within a Seed. Returns null if not found. */
52
+ export function findBranchById(seed, id) {
53
+ return seed.branches.find(b => b.id === id) ?? null;
54
+ }
55
+ /**
56
+ * Returns the next free branch id for a seed in the form `br_NN` (zero-padded to 2,
57
+ * growing as needed). Scans existing ids, never reuses a number already present —
58
+ * even if a branch was removed, its id is not recycled (ids must be globally stable
59
+ * for the life of the seed so layouts/automations/FTS triggers never collide).
60
+ */
61
+ export function nextBranchId(seed) {
62
+ let max = 0;
63
+ for (const b of seed.branches) {
64
+ const m = /^br_0*([0-9]+)$/.exec(b.id);
65
+ if (m)
66
+ max = Math.max(max, parseInt(m[1], 10));
67
+ }
68
+ const n = max + 1;
69
+ return `br_${String(n).padStart(2, '0')}`;
70
+ }
71
+ /**
72
+ * Returns the input seeds reordered so that every seed appears AFTER all the
73
+ * seeds it depends on (its `relation` branch targets). Pure function — does
74
+ * not read from any global registry.
75
+ *
76
+ * Uses Kahn's algorithm (BFS on in-degree) for cycle detection and topological
77
+ * ordering. Sprint 3 (CLI / migration runner) consumes this to create tables in
78
+ * the correct order without disabling SQLite FK constraints.
79
+ *
80
+ * @throws {Error} When a relation targets an unknown slug not in `seeds`.
81
+ * @throws {Error} When a cyclic dependency is detected, listing involved slugs.
82
+ */
83
+ export function sortSeedsByDependencies(seeds) {
84
+ const slugSet = new Set(seeds.map(s => s.slug));
85
+ // Validate all relation targets exist in the input array
86
+ for (const seed of seeds) {
87
+ for (const branch of seed.branches) {
88
+ if (branch.type === 'relation' && branch.targetSeed) {
89
+ if (!slugSet.has(branch.targetSeed)) {
90
+ throw new Error(`Seed '${seed.slug}' relates to unknown target '${branch.targetSeed}'`);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ // Build adjacency: inDegree[slug] = number of dependencies
96
+ // dependents[slug] = slugs that depend on slug
97
+ const inDegree = new Map();
98
+ const dependents = new Map();
99
+ for (const seed of seeds) {
100
+ if (!inDegree.has(seed.slug))
101
+ inDegree.set(seed.slug, 0);
102
+ if (!dependents.has(seed.slug))
103
+ dependents.set(seed.slug, []);
104
+ }
105
+ for (const seed of seeds) {
106
+ // Deduplicate targets to avoid inflating inDegree on multi-branch refs to same seed
107
+ const targets = new Set(seed.branches
108
+ .filter(b => b.type === 'relation' && b.targetSeed)
109
+ .map(b => b.targetSeed));
110
+ for (const target of targets) {
111
+ // seed depends on target → increment seed's in-degree
112
+ inDegree.set(seed.slug, (inDegree.get(seed.slug) ?? 0) + 1);
113
+ dependents.get(target).push(seed.slug);
114
+ }
115
+ }
116
+ // Kahn's BFS: start with seeds that have no dependencies
117
+ const seedBySlug = new Map(seeds.map(s => [s.slug, s]));
118
+ const queue = [];
119
+ for (const [slug, deg] of inDegree) {
120
+ if (deg === 0)
121
+ queue.push(slug);
122
+ }
123
+ const result = [];
124
+ while (queue.length > 0) {
125
+ const slug = queue.shift();
126
+ result.push(seedBySlug.get(slug));
127
+ for (const dependent of dependents.get(slug) ?? []) {
128
+ const newDeg = (inDegree.get(dependent) ?? 0) - 1;
129
+ inDegree.set(dependent, newDeg);
130
+ if (newDeg === 0)
131
+ queue.push(dependent);
132
+ }
133
+ }
134
+ if (result.length !== seeds.length) {
135
+ // Cycle exists — collect participating slugs (those with in-degree > 0 after BFS)
136
+ const cycle = [...inDegree.entries()]
137
+ .filter(([, deg]) => deg > 0)
138
+ .map(([slug]) => slug)
139
+ .sort();
140
+ throw new Error(`Cyclic dependency detected among seeds: ${cycle.join(', ')}`);
141
+ }
142
+ return result;
143
+ }
@@ -0,0 +1,23 @@
1
+ import type { Seed } from './types.js';
2
+ /**
3
+ * Allowed charset for a branch alias. An alias becomes a raw SQL column name in
4
+ * CREATE TABLE / ADD COLUMN / CREATE INDEX and in SELECT/WHERE/ORDER BY clauses
5
+ * (see engine.ts), so it MUST be restricted to a safe identifier charset to
6
+ * prevent DDL/query injection. Exported so the seeds API rename route reuses the
7
+ * exact same guard — do not inline a divergent copy.
8
+ */
9
+ export declare const BRANCH_ALIAS_RE: RegExp;
10
+ export interface SeedValidationIssue {
11
+ slug: string;
12
+ messages: string[];
13
+ fatal: boolean;
14
+ }
15
+ /**
16
+ * Pure, console-free, throw-free validation of a seed set.
17
+ * The single seed being created/edited should be validated in the context of
18
+ * the full active set: call validateSeedDefinitions([...otherActiveSeeds, edited]).
19
+ */
20
+ export declare function validateSeedDefinitions(seeds: Seed[]): SeedValidationIssue[];
21
+ /** Convenience: true iff no fatal issues. */
22
+ export declare function isSeedSetValid(seeds: Seed[]): boolean;
23
+ //# sourceMappingURL=seed-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-validation.d.ts","sourceRoot":"","sources":["../src/seed-validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAMtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,QAAsB,CAAA;AAElD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,mBAAmB,EAAE,CA6I5E;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAErD"}
@@ -0,0 +1,156 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ import { AUTOMATION_RESERVED_WORDS } from './automations-grammar-words.js';
4
+ import { sortSeedsByDependencies } from './seed-registry.js';
5
+ const BRANCH_ID_RE = /^br_[A-Za-z0-9]+$/;
6
+ /**
7
+ * Allowed charset for a branch alias. An alias becomes a raw SQL column name in
8
+ * CREATE TABLE / ADD COLUMN / CREATE INDEX and in SELECT/WHERE/ORDER BY clauses
9
+ * (see engine.ts), so it MUST be restricted to a safe identifier charset to
10
+ * prevent DDL/query injection. Exported so the seeds API rename route reuses the
11
+ * exact same guard — do not inline a divergent copy.
12
+ */
13
+ export const BRANCH_ALIAS_RE = /^[a-z][a-z0-9_]*$/;
14
+ /**
15
+ * Pure, console-free, throw-free validation of a seed set.
16
+ * The single seed being created/edited should be validated in the context of
17
+ * the full active set: call validateSeedDefinitions([...otherActiveSeeds, edited]).
18
+ */
19
+ export function validateSeedDefinitions(seeds) {
20
+ const result = [];
21
+ // ── Fatal 1: unknown relation targets ────────────────────────────────────
22
+ const slugSet = new Set(seeds.map(s => s.slug));
23
+ for (const seed of seeds) {
24
+ const messages = [];
25
+ for (const branch of seed.branches) {
26
+ if (branch.type === 'relation' && branch.targetSeed) {
27
+ if (!slugSet.has(branch.targetSeed)) {
28
+ messages.push(`branch '${branch.alias}' targets unknown seed '${branch.targetSeed}'`);
29
+ }
30
+ }
31
+ }
32
+ if (messages.length > 0)
33
+ result.push({ slug: seed.slug, messages, fatal: true });
34
+ }
35
+ // ── Fatal 2: multi-relation with SET NULL ────────────────────────────────
36
+ for (const seed of seeds) {
37
+ const messages = [];
38
+ for (const branch of seed.branches) {
39
+ if (branch.type === 'relation' && branch.multiple === true && branch.onDelete === 'SET NULL') {
40
+ messages.push(`Branch '${branch.alias}': multi-relations cannot use ON DELETE SET NULL. ` +
41
+ `Use 'CASCADE' or 'RESTRICT'.`);
42
+ }
43
+ }
44
+ if (messages.length > 0)
45
+ result.push({ slug: seed.slug, messages, fatal: true });
46
+ }
47
+ // ── Fatal 3: junction table name collisions / length ─────────────────────
48
+ {
49
+ const junctionNames = new Set();
50
+ for (const seed of seeds) {
51
+ const messages = [];
52
+ for (const branch of seed.branches) {
53
+ if (branch.type !== 'relation' || branch.multiple !== true)
54
+ continue;
55
+ const name = `rel_${seed.slug}_${branch.alias}`;
56
+ if (name.length > 256) {
57
+ messages.push(`Junction table name '${name}' exceeds 256 characters (${name.length})`);
58
+ }
59
+ if (junctionNames.has(name)) {
60
+ messages.push(`Junction table name collision: '${name}' already used by another seed/branch`);
61
+ }
62
+ junctionNames.add(name);
63
+ }
64
+ if (messages.length > 0)
65
+ result.push({ slug: seed.slug, messages, fatal: true });
66
+ }
67
+ }
68
+ // ── Fatal 4: dependency cycles ────────────────────────────────────────────
69
+ const hasUnknownTargets = result.some(e => e.fatal);
70
+ if (!hasUnknownTargets) {
71
+ try {
72
+ sortSeedsByDependencies(seeds);
73
+ }
74
+ catch (err) {
75
+ const msg = err instanceof Error ? err.message : String(err);
76
+ result.push({ slug: '<graph>', messages: [msg], fatal: true });
77
+ }
78
+ }
79
+ // ── Fatal 5: branch id format / uniqueness ───────────────────────────────
80
+ for (const seed of seeds) {
81
+ const messages = [];
82
+ const idsInSeed = new Set();
83
+ for (const branch of seed.branches) {
84
+ if (!branch.id || !BRANCH_ID_RE.test(branch.id)) {
85
+ messages.push(`branch '${branch.alias}' has invalid id '${branch.id}'. Expected format ^br_[A-Za-z0-9]+$.`);
86
+ }
87
+ else if (idsInSeed.has(branch.id)) {
88
+ messages.push(`duplicate branch id '${branch.id}'`);
89
+ }
90
+ if (branch.id)
91
+ idsInSeed.add(branch.id);
92
+ // Alias becomes a raw SQL column name — reject anything outside the safe
93
+ // identifier charset before it can reach DDL/query string interpolation.
94
+ if (typeof branch.alias !== 'string' || !BRANCH_ALIAS_RE.test(branch.alias)) {
95
+ messages.push(`branch alias '${branch.alias}' is invalid. Expected format ${BRANCH_ALIAS_RE.source} ` +
96
+ `(lowercase letter followed by lowercase letters, digits or underscores).`);
97
+ }
98
+ }
99
+ if (messages.length > 0)
100
+ result.push({ slug: seed.slug, messages, fatal: true });
101
+ }
102
+ // ── Fatal 6: reserved aliases ─────────────────────────────────────────────
103
+ for (const seed of seeds) {
104
+ const messages = [];
105
+ for (const branch of seed.branches) {
106
+ if (AUTOMATION_RESERVED_WORDS.has(branch.alias)) {
107
+ messages.push(`branch '${branch.alias}' uses reserved alias. ` +
108
+ `This word is used by the automation template grammar.`);
109
+ }
110
+ }
111
+ if (messages.length > 0)
112
+ result.push({ slug: seed.slug, messages, fatal: true });
113
+ }
114
+ // ── Warning 7: duplicate slug ─────────────────────────────────────────────
115
+ {
116
+ const slugsSeen = new Set();
117
+ for (const seed of seeds) {
118
+ const messages = [];
119
+ if (slugsSeen.has(seed.slug)) {
120
+ messages.push(`duplicate slug "${seed.slug}" — each seed must have a unique slug`);
121
+ }
122
+ slugsSeen.add(seed.slug);
123
+ if (messages.length > 0)
124
+ result.push({ slug: seed.slug, messages, fatal: false });
125
+ }
126
+ }
127
+ // ── Warning 8: duplicate branch alias within a seed ───────────────────────
128
+ for (const seed of seeds) {
129
+ const messages = [];
130
+ const aliasesSeen = new Set();
131
+ for (const branch of seed.branches) {
132
+ if (aliasesSeen.has(branch.alias)) {
133
+ messages.push(`duplicate branch alias "${branch.alias}"`);
134
+ }
135
+ aliasesSeen.add(branch.alias);
136
+ }
137
+ if (messages.length > 0)
138
+ result.push({ slug: seed.slug, messages, fatal: false });
139
+ }
140
+ // ── Warning 9: displayNameAlias not in branches ───────────────────────────
141
+ for (const seed of seeds) {
142
+ const allAliases = new Set(seed.branches.map(b => b.alias));
143
+ if (!allAliases.has(seed.displayNameAlias)) {
144
+ result.push({
145
+ slug: seed.slug,
146
+ messages: [`displayNameAlias "${seed.displayNameAlias}" not found in branches`],
147
+ fatal: false,
148
+ });
149
+ }
150
+ }
151
+ return result;
152
+ }
153
+ /** Convenience: true iff no fatal issues. */
154
+ export function isSeedSetValid(seeds) {
155
+ return validateSeedDefinitions(seeds).every(i => !i.fatal);
156
+ }
@@ -0,0 +1,37 @@
1
+ import type { Seed } from './types.js';
2
+ export interface SeedRecord {
3
+ slug: string;
4
+ definition: Seed;
5
+ status: 'active' | 'deleted';
6
+ source: 'code' | 'runtime';
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ }
10
+ /**
11
+ * Persistence contract for runtime Seed definitions.
12
+ * Implemented by D1SeedRepository in apps/api/src/shared/seed.repository.d1.ts.
13
+ *
14
+ * `listActive()` returns only status='active' rows — this is what the registry is
15
+ * hydrated from. `getRegistryVersion` / `bumpRegistryVersion` back the multi-isolate
16
+ * cache token (see docs/Sprints/runtime-seeds/00-overview.md).
17
+ */
18
+ export interface ISeedRepository {
19
+ /** All active seed definitions, ordered by created_at ASC. */
20
+ listActive(): Promise<Seed[]>;
21
+ /** Every row including soft-deleted ones (for admin/diff use). */
22
+ listAll(): Promise<SeedRecord[]>;
23
+ /** Single active-or-deleted record by slug, or null. */
24
+ get(slug: string): Promise<SeedRecord | null>;
25
+ /** Insert or replace a definition. Sets source on insert; preserves it on update unless given. */
26
+ upsert(slug: string, definition: Seed, source?: 'code' | 'runtime'): Promise<void>;
27
+ /** Soft-delete: set status='deleted'. Table is NOT dropped (additive-only). */
28
+ softDelete(slug: string): Promise<void>;
29
+ /** Hard-delete (sprint 06): permanently remove the `seeds` row. The caller is
30
+ * responsible for dropping the backing tables first via ISchemaMutator. */
31
+ hardDelete(slug: string): Promise<void>;
32
+ /** Current cache token. */
33
+ getRegistryVersion(): Promise<number>;
34
+ /** Atomically increment and return the new token. Call after any write. */
35
+ bumpRegistryVersion(): Promise<number>;
36
+ }
37
+ //# sourceMappingURL=seed.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.repository.d.ts","sourceRoot":"","sources":["../src/seed.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,IAAI,CAAA;IAChB,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,UAAU,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IAC7B,kEAAkE;IAClE,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;IAChC,wDAAwD;IACxD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAC7C,kGAAkG;IAClG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClF,+EAA+E;IAC/E,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC;gFAC4E;IAC5E,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,2BAA2B;IAC3B,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACrC,2EAA2E;IAC3E,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CACvC"}
@@ -0,0 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"seeds.d.ts","sourceRoot":"","sources":["../src/seeds.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAM,CAAA;AAErD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAI1C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEjD"}
1
+ {"version":3,"file":"seeds.d.ts","sourceRoot":"","sources":["../src/seeds.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAM,CAAA;AAErD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAI1C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEjD"}
package/dist/seeds.js CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
1
3
  /**
2
4
  * Registro globale dei Seed.
3
5
  * In produzione, questo viene popolato dalle definizioni dell'utente.
@@ -0,0 +1,16 @@
1
+ export interface SiteSettings {
2
+ siteTitle: string;
3
+ defaultLanguage: string;
4
+ timezone: string;
5
+ currency: string;
6
+ companyName: string | null;
7
+ companyWebsite: string | null;
8
+ companyAbbreviation: string | null;
9
+ }
10
+ export interface ISiteSettingsRepository {
11
+ /** Returns all stored settings, applying sensible defaults for missing keys. */
12
+ getAll(): Promise<SiteSettings>;
13
+ /** Upserts the provided keys. Partial update — unspecified keys are untouched. */
14
+ setMany(values: Partial<SiteSettings>): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=site-settings.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-settings.repository.d.ts","sourceRoot":"","sources":["../src/site-settings.repository.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,gFAAgF;IAChF,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAAA;IAC/B,kFAAkF;IAClF,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtD"}
@@ -0,0 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
3
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"slug-utils.d.ts","sourceRoot":"","sources":["../src/slug-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU7C;AAGD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CASnG"}
1
+ {"version":3,"file":"slug-utils.d.ts","sourceRoot":"","sources":["../src/slug-utils.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU7C;AAGD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CASnG"}
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
1
3
  /**
2
4
  * Utility per la gestione degli slug.
3
5
  * Condivisa tra Dashboard e API pubbliche.
package/dist/storage.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * BeechBucket - S3-like interface for object storage in BeechCMS.
3
- *
4
- * This interface abstracts the underlying storage provider (R2, S3, or Local)
5
- * allowing the application to scale without being tied to a specific vendor.
6
- */
7
1
  export interface PutBucketOptions {
8
2
  contentType?: string;
9
3
  metadata?: Record<string, string>;
@@ -14,49 +8,25 @@ export interface GetBucketResult {
14
8
  size: number;
15
9
  metadata?: Record<string, string>;
16
10
  }
11
+ export interface PresignOptions {
12
+ /** Duration of the signed URL in seconds. */
13
+ expiresIn: number;
14
+ /** Content-Type bound in the signature (PUT). */
15
+ contentType?: string;
16
+ /** Expected Content-Length in bytes (PUT). */
17
+ contentLength?: number;
18
+ }
17
19
  export interface BeechBucket {
18
- /**
19
- * Uploads an object to the bucket.
20
- * @param key The unique key (path) for the object.
21
- * @param body The data to store.
22
- * @param options Optional metadata like content type.
23
- */
24
20
  put(key: string, body: ArrayBuffer | Uint8Array | ReadableStream, options?: PutBucketOptions): Promise<void>;
25
- /**
26
- * Retrieves an object from the bucket.
27
- * @param key The unique key for the object.
28
- * @returns The object data and metadata, or null if not found.
29
- */
30
21
  get(key: string): Promise<GetBucketResult | null>;
31
- /**
32
- * Deletes an object from the bucket.
33
- * @param key The unique key for the object.
34
- */
35
22
  delete(key: string): Promise<void>;
36
- /**
37
- * Retrieves metadata for an object without downloading its content.
38
- * @param key The unique key for the object.
39
- */
40
23
  head(key: string): Promise<{
41
24
  size: number;
42
25
  contentType?: string;
43
26
  metadata?: Record<string, string>;
44
27
  } | null>;
45
- /**
46
- * Returns a publicly accessible URL for the given key.
47
- * The implementation decides if this is a direct vendor URL (CDN)
48
- * or a proxied URL through the Beech API.
49
- * @param key The unique key for the object.
50
- */
51
28
  getUrl(key: string): string;
52
- /**
53
- * Calculates the total size of all objects in the bucket.
54
- * Warning: This may be an expensive operation on some providers.
55
- */
56
29
  getTotalSize(): Promise<number>;
57
- /**
58
- * Lists objects in the bucket.
59
- */
60
30
  list(options?: {
61
31
  prefix?: string;
62
32
  limit?: number;
@@ -68,5 +38,9 @@ export interface BeechBucket {
68
38
  }>;
69
39
  cursor?: string;
70
40
  }>;
41
+ /** Generates a signed URL for direct upload (PUT). */
42
+ presignPut(key: string, options: PresignOptions): Promise<string>;
43
+ /** Generates a signed URL for direct read (GET). */
44
+ presignGet(key: string, options: PresignOptions): Promise<string>;
71
45
  }
72
46
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,cAAc,GAAG,WAAW,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7G;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAElD;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;OAGG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAE7G;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAE5B;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhC;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnJ"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,cAAc,GAAG,WAAW,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7G,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC7G,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAElJ,sDAAsD;IACtD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAElE,oDAAoD;IACpD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnE"}
package/dist/storage.js CHANGED
@@ -1 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
1
3
  export {};