@beechcms/core 0.5.0 → 0.6.0-preview.2

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 (141) 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/dashboard-layout.d.ts +154 -0
  32. package/dist/dashboard-layout.d.ts.map +1 -0
  33. package/dist/dashboard-layout.js +186 -0
  34. package/dist/dashboard-layout.repository.d.ts +18 -0
  35. package/dist/dashboard-layout.repository.d.ts.map +1 -0
  36. package/dist/dashboard-layout.repository.js +3 -0
  37. package/dist/dashboard-permissions.d.ts +3 -0
  38. package/dist/dashboard-permissions.d.ts.map +1 -0
  39. package/dist/dashboard-permissions.js +11 -0
  40. package/dist/dashboard-scopes.d.ts +12 -0
  41. package/dist/dashboard-scopes.d.ts.map +1 -0
  42. package/dist/dashboard-scopes.js +30 -0
  43. package/dist/define-seed.d.ts.map +1 -1
  44. package/dist/define-seed.js +2 -0
  45. package/dist/demo-data.repository.d.ts +5 -0
  46. package/dist/demo-data.repository.d.ts.map +1 -0
  47. package/dist/demo-data.repository.js +3 -0
  48. package/dist/engine.d.ts +76 -0
  49. package/dist/engine.d.ts.map +1 -1
  50. package/dist/engine.js +259 -5
  51. package/dist/file-types.d.ts +13 -0
  52. package/dist/file-types.d.ts.map +1 -0
  53. package/dist/file-types.js +85 -0
  54. package/dist/id-generator.d.ts +7 -0
  55. package/dist/id-generator.d.ts.map +1 -1
  56. package/dist/id-generator.js +5 -0
  57. package/dist/idempotency.repository.d.ts.map +1 -1
  58. package/dist/idempotency.repository.js +2 -0
  59. package/dist/index.d.ts +16 -1
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +18 -1
  62. package/dist/layout-permissions.d.ts +3 -0
  63. package/dist/layout-permissions.d.ts.map +1 -0
  64. package/dist/layout-permissions.js +11 -0
  65. package/dist/media.repository.d.ts.map +1 -1
  66. package/dist/media.repository.js +2 -0
  67. package/dist/notifications/notification-service.d.ts.map +1 -1
  68. package/dist/notifications/notification-service.js +2 -0
  69. package/dist/notifications/notification.repository.d.ts.map +1 -1
  70. package/dist/notifications/notification.repository.js +2 -9
  71. package/dist/observability/activity-log.repository.d.ts.map +1 -1
  72. package/dist/observability/activity-log.repository.js +2 -0
  73. package/dist/observability/activity-logger.d.ts +2 -2
  74. package/dist/observability/activity-logger.d.ts.map +1 -1
  75. package/dist/observability/activity-logger.js +2 -11
  76. package/dist/observability/analytics.repository.d.ts.map +1 -1
  77. package/dist/observability/analytics.repository.js +2 -0
  78. package/dist/policies.d.ts.map +1 -1
  79. package/dist/policies.js +8 -3
  80. package/dist/rate-limit/rate-limiter.d.ts.map +1 -1
  81. package/dist/rate-limit/rate-limiter.js +2 -0
  82. package/dist/relations.d.ts +28 -0
  83. package/dist/relations.d.ts.map +1 -0
  84. package/dist/relations.js +25 -0
  85. package/dist/richtext-render.d.ts.map +1 -1
  86. package/dist/richtext-render.js +2 -0
  87. package/dist/richtext.d.ts.map +1 -1
  88. package/dist/richtext.js +2 -0
  89. package/dist/scheduler.interface.d.ts.map +1 -1
  90. package/dist/scheduler.interface.js +2 -0
  91. package/dist/scheduler.stub.d.ts.map +1 -1
  92. package/dist/scheduler.stub.js +2 -0
  93. package/dist/schema-mutator.d.ts +22 -0
  94. package/dist/schema-mutator.d.ts.map +1 -0
  95. package/dist/schema-mutator.js +3 -0
  96. package/dist/search/search.repository.d.ts.map +1 -1
  97. package/dist/search/search.repository.js +2 -0
  98. package/dist/seed-ddl-destructive.d.ts +40 -0
  99. package/dist/seed-ddl-destructive.d.ts.map +1 -0
  100. package/dist/seed-ddl-destructive.js +149 -0
  101. package/dist/seed-ddl.d.ts +40 -0
  102. package/dist/seed-ddl.d.ts.map +1 -0
  103. package/dist/seed-ddl.js +100 -0
  104. package/dist/seed-layout.d.ts +117 -0
  105. package/dist/seed-layout.d.ts.map +1 -0
  106. package/dist/seed-layout.js +169 -0
  107. package/dist/seed-layout.repository.d.ts +18 -0
  108. package/dist/seed-layout.repository.d.ts.map +1 -0
  109. package/dist/seed-layout.repository.js +3 -0
  110. package/dist/seed-registry.d.ts +23 -1
  111. package/dist/seed-registry.d.ts.map +1 -1
  112. package/dist/seed-registry.js +105 -0
  113. package/dist/seed-validation.d.ts +23 -0
  114. package/dist/seed-validation.d.ts.map +1 -0
  115. package/dist/seed-validation.js +224 -0
  116. package/dist/seed.repository.d.ts +37 -0
  117. package/dist/seed.repository.d.ts.map +1 -0
  118. package/dist/seed.repository.js +3 -0
  119. package/dist/seeds.d.ts.map +1 -1
  120. package/dist/seeds.js +2 -0
  121. package/dist/site-settings.repository.d.ts +16 -0
  122. package/dist/site-settings.repository.d.ts.map +1 -0
  123. package/dist/site-settings.repository.js +3 -0
  124. package/dist/slug-utils.d.ts.map +1 -1
  125. package/dist/slug-utils.js +2 -0
  126. package/dist/storage.d.ts +12 -38
  127. package/dist/storage.d.ts.map +1 -1
  128. package/dist/storage.js +2 -0
  129. package/dist/types.d.ts +81 -1
  130. package/dist/types.d.ts.map +1 -1
  131. package/dist/types.js +2 -0
  132. package/dist/validation.d.ts +23 -17
  133. package/dist/validation.d.ts.map +1 -1
  134. package/dist/validation.js +487 -381
  135. package/dist/webhook-validation.d.ts +3 -0
  136. package/dist/webhook-validation.d.ts.map +1 -0
  137. package/dist/webhook-validation.js +6 -0
  138. package/dist/widget/widget.repository.d.ts +32 -3
  139. package/dist/widget/widget.repository.d.ts.map +1 -1
  140. package/dist/widget/widget.repository.js +6 -1
  141. package/package.json +5 -4
@@ -0,0 +1,224 @@
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-zA-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 alphanumeric characters 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
+ // ── Fatal 10: repeater sub-field constraints ─────────────────────────────
115
+ {
116
+ const REPEATER_DISALLOWED_SUBTYPES = new Set(['repeater', 'relation', 'file']);
117
+ for (const seed of seeds) {
118
+ const messages = [];
119
+ for (const branch of seed.branches) {
120
+ if (branch.type !== 'repeater')
121
+ continue;
122
+ const subIds = new Set();
123
+ const subAliases = new Set();
124
+ for (const sub of branch.fields ?? []) {
125
+ if (REPEATER_DISALLOWED_SUBTYPES.has(sub.type)) {
126
+ messages.push(`branch '${branch.alias}': sub-field '${sub.alias}' has disallowed type '${sub.type}'. ` +
127
+ `Repeater sub-fields cannot be 'repeater', 'relation', or 'file' in v1.`);
128
+ }
129
+ if (!sub.id || !BRANCH_ID_RE.test(sub.id)) {
130
+ messages.push(`branch '${branch.alias}': sub-field '${sub.alias}' has invalid id '${sub.id}'. ` +
131
+ `Expected format ^br_[A-Za-z0-9]+$.`);
132
+ }
133
+ else if (subIds.has(sub.id)) {
134
+ messages.push(`branch '${branch.alias}': duplicate sub-field id '${sub.id}'`);
135
+ }
136
+ if (sub.id)
137
+ subIds.add(sub.id);
138
+ if (typeof sub.alias !== 'string' || !BRANCH_ALIAS_RE.test(sub.alias)) {
139
+ messages.push(`branch '${branch.alias}': sub-field alias '${sub.alias}' is invalid. ` +
140
+ `Expected format ${BRANCH_ALIAS_RE.source}.`);
141
+ }
142
+ else if (subAliases.has(sub.alias)) {
143
+ messages.push(`branch '${branch.alias}': duplicate sub-field alias '${sub.alias}'`);
144
+ }
145
+ subAliases.add(sub.alias);
146
+ }
147
+ }
148
+ if (messages.length > 0)
149
+ result.push({ slug: seed.slug, messages, fatal: true });
150
+ }
151
+ }
152
+ // ── Warning 7: duplicate slug ─────────────────────────────────────────────
153
+ {
154
+ const slugsSeen = new Set();
155
+ for (const seed of seeds) {
156
+ const messages = [];
157
+ if (slugsSeen.has(seed.slug)) {
158
+ messages.push(`duplicate slug "${seed.slug}" — each seed must have a unique slug`);
159
+ }
160
+ slugsSeen.add(seed.slug);
161
+ if (messages.length > 0)
162
+ result.push({ slug: seed.slug, messages, fatal: false });
163
+ }
164
+ }
165
+ // ── Warning 8: duplicate branch alias within a seed ───────────────────────
166
+ for (const seed of seeds) {
167
+ const messages = [];
168
+ const aliasesSeen = new Set();
169
+ for (const branch of seed.branches) {
170
+ if (aliasesSeen.has(branch.alias)) {
171
+ messages.push(`duplicate branch alias "${branch.alias}"`);
172
+ }
173
+ aliasesSeen.add(branch.alias);
174
+ }
175
+ if (messages.length > 0)
176
+ result.push({ slug: seed.slug, messages, fatal: false });
177
+ }
178
+ // ── Warning 9: displayNameAlias not in branches ───────────────────────────
179
+ for (const seed of seeds) {
180
+ const allAliases = new Set(seed.branches.map(b => b.alias));
181
+ if (!allAliases.has(seed.displayNameAlias)) {
182
+ result.push({
183
+ slug: seed.slug,
184
+ messages: [`displayNameAlias "${seed.displayNameAlias}" not found in branches`],
185
+ fatal: false,
186
+ });
187
+ }
188
+ }
189
+ // ── Fatal 11 / Warning 10: repeater cardinality bounds ───────────────────
190
+ {
191
+ for (const seed of seeds) {
192
+ const fatals = [];
193
+ const warnings = [];
194
+ for (const branch of seed.branches) {
195
+ const hasBounds = branch.minItems !== undefined || branch.maxItems !== undefined;
196
+ if (!hasBounds)
197
+ continue;
198
+ if (branch.type !== 'repeater') {
199
+ warnings.push(`branch '${branch.alias}': minItems/maxItems are ignored on type ` +
200
+ `'${branch.type}' (repeater-only).`);
201
+ continue;
202
+ }
203
+ for (const [key, val] of [['minItems', branch.minItems], ['maxItems', branch.maxItems]]) {
204
+ if (val !== undefined && (!Number.isInteger(val) || val < 0)) {
205
+ fatals.push(`branch '${branch.alias}': ${key} must be a non-negative integer (got ${val}).`);
206
+ }
207
+ }
208
+ if (Number.isInteger(branch.minItems) && Number.isInteger(branch.maxItems) &&
209
+ branch.minItems > branch.maxItems) {
210
+ fatals.push(`branch '${branch.alias}': minItems (${branch.minItems}) must be <= maxItems (${branch.maxItems}).`);
211
+ }
212
+ }
213
+ if (fatals.length > 0)
214
+ result.push({ slug: seed.slug, messages: fatals, fatal: true });
215
+ if (warnings.length > 0)
216
+ result.push({ slug: seed.slug, messages: warnings, fatal: false });
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+ /** Convenience: true iff no fatal issues. */
222
+ export function isSeedSetValid(seeds) {
223
+ return validateSeedDefinitions(seeds).every(i => !i.fatal);
224
+ }
@@ -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 {};
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export type BranchType = 'text' | 'number' | 'boolean' | 'json' | 'date' | 'richtext' | 'file' | 'tags';
1
+ import type { FileAccept } from './file-types.js';
2
+ export type BranchType = 'text' | 'number' | 'boolean' | 'json' | 'date' | 'richtext' | 'file' | 'tags' | 'relation' | 'repeater';
2
3
  /** Configurazioni specializzate per il tipo di branch 'number' */
3
4
  export interface NumberFieldOptions {
4
5
  /** Stile di presentazione visiva. Default: 'decimal' */
@@ -22,12 +23,42 @@ export interface NumberFieldOptions {
22
23
  /** Incremento del valore (es. 1 per interi stretti, 0.5 per mezzi passi) */
23
24
  step?: number;
24
25
  }
26
+ /** Configurazioni specializzate per il tipo di branch 'file' */
27
+ export interface FileFieldOptions {
28
+ /**
29
+ * Tipo semantico di file accettato.
30
+ * - 'image': immagini renderizzabili come anteprima
31
+ * - 'document': PDF/Office/text
32
+ * - 'any': qualsiasi file (default — UI mostra icona generica, nessun tentativo di render immagine)
33
+ * Default: 'any'.
34
+ */
35
+ accept?: FileAccept;
36
+ /**
37
+ * Dimensione massima del singolo file in byte.
38
+ * NOTA: il backend /upload applica MAX_FILE_SIZE_BYTES (5MB) globale —
39
+ * questo campo è informativo per la UI; non viene enforced in upload.
40
+ * Default: 5_242_880.
41
+ */
42
+ maxSize?: number;
43
+ }
25
44
  /** Branch: definizione di una proprietà. alias = nome colonna SQL. */
26
45
  export interface Branch {
46
+ /**
47
+ * Stable logical id of this branch, e.g. 'br_01', 'br_title'.
48
+ * Format: ^br_[A-Za-z0-9]+$ — enforced by SeedRegistry at boot (sprint 04-pre).
49
+ *
50
+ * Used by every persistence layer that needs a reference that survives alias renames
51
+ * (FTS triggers, draft indexing, layout JSON, automations). NEVER use alias for that purpose.
52
+ *
53
+ * The Botanical Engine still emits alias as the SQL column name; id is a logical handle.
54
+ */
55
+ id: string;
27
56
  /** Alias human-readable, usato nel payload API e come nome colonna SQL nella tabella dedicata */
28
57
  alias: string;
29
58
  /** Etichetta per la UI */
30
59
  label: string;
60
+ /** Testo di aiuto opzionale mostrato come tooltip accanto al label nella form. UI-only, ignorato dall'engine. */
61
+ hint?: string;
31
62
  /** Tipo del valore */
32
63
  type: BranchType;
33
64
  /**
@@ -70,6 +101,51 @@ export interface Branch {
70
101
  };
71
102
  /** Opzioni avanzate per i campi numerici. Ignorato se type !== 'number' */
72
103
  numberOptions?: NumberFieldOptions;
104
+ /** Opzioni avanzate per i campi file. Ignorato se type !== 'file' */
105
+ fileOptions?: FileFieldOptions;
106
+ /**
107
+ * Slug of the referenced Seed (without the `content_` prefix).
108
+ * REQUIRED when `type === 'relation'`. Ignored otherwise.
109
+ * Example: 'team' → references table `content_team(id)`.
110
+ */
111
+ targetSeed?: string;
112
+ /**
113
+ * SQLite ON DELETE rule applied to the foreign-key constraint.
114
+ * Defaults to 'SET NULL' when `type === 'relation'` and no value is provided.
115
+ * - CASCADE : delete dependent rows when the parent is deleted.
116
+ * - SET NULL : null out the column when the parent is deleted (default).
117
+ * - RESTRICT : block parent deletion while dependent rows exist.
118
+ *
119
+ * NOTE: When `multiple: true` (introduced in Sprint 5 for many-to-many), this
120
+ * rule applies to the FK from the junction table to the target table.
121
+ */
122
+ onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
123
+ /**
124
+ * Sub-schema for `type === 'repeater'`. Each item of the repeater's array
125
+ * value is a record keyed by sub-branch alias, validated against this list.
126
+ * Sub-branches are restricted to leaf/scalar types (no nested `repeater`,
127
+ * `relation`, or `file`) — enforced by validation.ts and seed-validation.ts.
128
+ * Ignored for any other branch type.
129
+ */
130
+ fields?: Branch[];
131
+ /**
132
+ * Minimum number of items a `repeater` value must contain when a value is
133
+ * provided. Repeater-only — ignored for every other branch type.
134
+ *
135
+ * NOTE: this constrains array *length when the field is present*. It does NOT by
136
+ * itself make the field mandatory — an absent/null payload is still allowed unless
137
+ * `requiredOnCreate` / `requiredOnUpdate` is also set. To model "exactly one
138
+ * required object", combine `minItems: 1, maxItems: 1, requiredOnCreate: true`.
139
+ * Must be a non-negative integer and `<= maxItems` when both are set
140
+ * (enforced at boot by seed-validation.ts).
141
+ */
142
+ minItems?: number;
143
+ /**
144
+ * Maximum number of items a `repeater` value may contain. Repeater-only — ignored
145
+ * for every other branch type. `maxItems: 1` models a single "object" column.
146
+ * Must be a non-negative integer and `>= minItems` when both are set.
147
+ */
148
+ maxItems?: number;
73
149
  }
74
150
  /** Dashboard-specific config embedded in a Seed. All fields optional — defaults applied by the dashboard. */
75
151
  export interface DashboardSeedConfig {
@@ -120,6 +196,10 @@ export interface Seed {
120
196
  branches: Branch[];
121
197
  /** Optional dashboard-specific UI config. Ignored by the Botanical Engine. */
122
198
  dashboard?: DashboardSeedConfig;
199
+ /** Custom editor form layout. Absent when no override is stored.
200
+ * Populated server-side by GET /api/schema. Ignored by the Botanical Engine.
201
+ * Type matches FormLayout from seed-layout.ts — kept as unknown here to avoid circular imports. */
202
+ layout?: unknown;
123
203
  }
124
204
  export type FilterOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'is_empty' | 'is_not_empty' | 'in' | 'not_in' | 'has_tag' | 'has_any_tag' | 'has_all_tags';
125
205
  export type FilterType = 'text' | 'number' | 'date' | 'boolean' | 'tags' | 'select' | 'system' | 'json';
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1 +1,3 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Copyright (c) 2024–2026 Flavio De Musso
1
3
  export {};
@@ -1,4 +1,6 @@
1
- import type { Seed } from './types.js';
1
+ import type { Branch, Seed } from './types.js';
2
+ import type { FileAccept } from './file-types.js';
3
+ import type { IIdGenerator } from './id-generator.js';
2
4
  export interface ValidationDetail {
3
5
  field: string;
4
6
  expected: string;
@@ -11,6 +13,13 @@ export interface ValidateSeedPayloadOptions {
11
13
  requireAtLeastOneValidField?: boolean;
12
14
  enforceRequiredFields?: boolean;
13
15
  maxTextLength?: number;
16
+ /**
17
+ * Required when the seed has branches of type `'relation'`.
18
+ * Must be the same IIdGenerator instance used for id generation so that
19
+ * swapping implementations (e.g. ULIDs) automatically updates validation.
20
+ * Do NOT pass a concrete class — inject via the middleware / factory.
21
+ */
22
+ idGenerator?: IIdGenerator;
14
23
  }
15
24
  export interface ValidateSeedPayloadResult {
16
25
  data: Record<string, unknown>;
@@ -20,25 +29,22 @@ export interface ValidateSeedPayloadResult {
20
29
  requiredFieldsMissing: string[];
21
30
  hasAnyValidField: boolean;
22
31
  }
32
+ declare const STATUS_VALUES: readonly ["draft", "review", "published"];
33
+ export declare function resolveFileOptions(branch: Branch): {
34
+ accept: FileAccept;
35
+ maxSize: number;
36
+ };
23
37
  /**
24
- * Common foundation for schema-driven validation and sanitization of payloads.
25
- * Used by the Public API and reusable in the Botanical Engine.
26
- *
27
- * Mandatory execution order at the time of writing:
28
- * validate raw hash (privacy policy) store
29
- * Hashing occurs AFTER validation, not before.
30
- * This ensures that the validated value is the original raw value,
31
- * not the digest — avoiding false failures on fields with formats (e.g., email).
38
+ * Schema-driven validation and sanitization of a seed payload.
39
+ * - Drops unknown aliases (reports them as details).
40
+ * - Runs branch-specific schemas to coerce / sanitize known values.
41
+ * - Optionally enforces required-on-create / required-on-update branches.
42
+ * - Never throws on malformed input — returns a structured result.
32
43
  */
33
44
  export declare function validateAndSanitizeSeedPayload(seed: Seed, payload: Record<string, unknown>, options?: ValidateSeedPayloadOptions): ValidateSeedPayloadResult;
34
45
  /**
35
- * Validates content status supported by the CMS.
36
- */
37
- export declare function isValidContentStatus(value: unknown): value is 'draft' | 'review' | 'published';
38
- /**
39
- * Full Zod runtime compiler:
40
- * - compile per-seed/per-operation with cache
41
- * - strict unknown aliases
42
- * - required fields by operation
46
+ * Type-guard for the content status enum.
43
47
  */
48
+ export declare function isValidContentStatus(value: unknown): value is (typeof STATUS_VALUES)[number];
49
+ export {};
44
50
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAgkBD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAyC3B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,GAAG,QAAQ,GAAG,WAAW,CAE9F;AAED;;;;;GAKG"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAc,IAAI,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAuBD,QAAA,MAAM,aAAa,2CAA4C,CAAA;AAmD/D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAM1F;AA2lBD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAqD3B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAE5F"}