@caelo-cms/shared 0.2.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 (77) hide show
  1. package/dist/ai-tools.d.ts +571 -0
  2. package/dist/ai-tools.d.ts.map +1 -0
  3. package/dist/ai-tools.js +696 -0
  4. package/dist/ai-tools.js.map +1 -0
  5. package/dist/auth-forms.d.ts +24 -0
  6. package/dist/auth-forms.d.ts.map +1 -0
  7. package/dist/auth-forms.js +27 -0
  8. package/dist/auth-forms.js.map +1 -0
  9. package/dist/cap-failures.d.ts +17 -0
  10. package/dist/cap-failures.d.ts.map +1 -0
  11. package/dist/cap-failures.js +58 -0
  12. package/dist/cap-failures.js.map +1 -0
  13. package/dist/content.d.ts +111 -0
  14. package/dist/content.d.ts.map +1 -0
  15. package/dist/content.js +137 -0
  16. package/dist/content.js.map +1 -0
  17. package/dist/context.d.ts +40 -0
  18. package/dist/context.d.ts.map +1 -0
  19. package/dist/context.js +3 -0
  20. package/dist/context.js.map +1 -0
  21. package/dist/i18n.d.ts +49 -0
  22. package/dist/i18n.d.ts.map +1 -0
  23. package/dist/i18n.js +154 -0
  24. package/dist/i18n.js.map +1 -0
  25. package/dist/index.d.ts +20 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +21 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/logger.d.ts +56 -0
  30. package/dist/logger.d.ts.map +1 -0
  31. package/dist/logger.js +84 -0
  32. package/dist/logger.js.map +1 -0
  33. package/dist/media.d.ts +143 -0
  34. package/dist/media.d.ts.map +1 -0
  35. package/dist/media.js +168 -0
  36. package/dist/media.js.map +1 -0
  37. package/dist/preview-compose.d.ts +84 -0
  38. package/dist/preview-compose.d.ts.map +1 -0
  39. package/dist/preview-compose.js +385 -0
  40. package/dist/preview-compose.js.map +1 -0
  41. package/dist/preview-scanner.d.ts +44 -0
  42. package/dist/preview-scanner.d.ts.map +1 -0
  43. package/dist/preview-scanner.js +177 -0
  44. package/dist/preview-scanner.js.map +1 -0
  45. package/dist/result.d.ts +21 -0
  46. package/dist/result.d.ts.map +1 -0
  47. package/dist/result.js +14 -0
  48. package/dist/result.js.map +1 -0
  49. package/dist/seo.d.ts +128 -0
  50. package/dist/seo.d.ts.map +1 -0
  51. package/dist/seo.js +176 -0
  52. package/dist/seo.js.map +1 -0
  53. package/dist/skills.d.ts +88 -0
  54. package/dist/skills.d.ts.map +1 -0
  55. package/dist/skills.js +127 -0
  56. package/dist/skills.js.map +1 -0
  57. package/dist/snapshots.d.ts +54 -0
  58. package/dist/snapshots.d.ts.map +1 -0
  59. package/dist/snapshots.js +59 -0
  60. package/dist/snapshots.js.map +1 -0
  61. package/dist/structured-sets.d.ts +116 -0
  62. package/dist/structured-sets.d.ts.map +1 -0
  63. package/dist/structured-sets.js +154 -0
  64. package/dist/structured-sets.js.map +1 -0
  65. package/dist/subagents.d.ts +123 -0
  66. package/dist/subagents.d.ts.map +1 -0
  67. package/dist/subagents.js +202 -0
  68. package/dist/subagents.js.map +1 -0
  69. package/dist/translation.d.ts +127 -0
  70. package/dist/translation.d.ts.map +1 -0
  71. package/dist/translation.js +208 -0
  72. package/dist/translation.js.map +1 -0
  73. package/dist/version.d.ts +46 -0
  74. package/dist/version.d.ts.map +1 -0
  75. package/dist/version.js +46 -0
  76. package/dist/version.js.map +1 -0
  77. package/package.json +38 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * P10A — skill auto-matcher (pure function).
3
+ *
4
+ * Scores site-active skills against the current chat turn's user
5
+ * message + element-reference chips. Top-K matches go into
6
+ * `auto`-source engagements; pinned defaults + manual overrides
7
+ * compose with the matcher output in the chat-runner.
8
+ *
9
+ * Scoring is intentionally simple — keyword + chip-trigger + always-on
10
+ * — to keep this layer LLM-free. The matcher runs every turn; an
11
+ * LLM-based matcher would double provider cost without obvious gain.
12
+ */
13
+ import { z } from "zod";
14
+ export declare const skillAutoEngagementHints: z.ZodObject<{
15
+ keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
16
+ chipTrigger: z.ZodDefault<z.ZodBoolean>;
17
+ alwaysOn: z.ZodDefault<z.ZodBoolean>;
18
+ }, z.core.$strict>;
19
+ export type SkillAutoEngagementHints = z.infer<typeof skillAutoEngagementHints>;
20
+ export interface CandidateSkill {
21
+ readonly id: string;
22
+ readonly slug: string;
23
+ readonly displayName: string;
24
+ readonly hints: SkillAutoEngagementHints;
25
+ }
26
+ export interface MatcherInput {
27
+ readonly userMessage: string;
28
+ /** Element-reference chips attached to this turn (P5 click-to-chat). */
29
+ readonly chipCount: number;
30
+ readonly skills: readonly CandidateSkill[];
31
+ /** Top-K cap. Defaults to 5 — engaging more than 5 skills bloats the system prompt. */
32
+ readonly topK?: number;
33
+ }
34
+ export interface SkillMatch {
35
+ readonly skillId: string;
36
+ readonly slug: string;
37
+ readonly displayName: string;
38
+ readonly score: number;
39
+ readonly rationale: string;
40
+ }
41
+ /**
42
+ * Score every candidate skill against the turn context. Returns the
43
+ * top-K matches sorted by score (descending). `alwaysOn` skills always
44
+ * score at least 1; `chipTrigger` skills score 100 when chips present;
45
+ * keywords add 1 per matching keyword (case-insensitive substring).
46
+ *
47
+ * Skills with score 0 are dropped — they never engage automatically.
48
+ */
49
+ export declare function matchSkills(input: MatcherInput): SkillMatch[];
50
+ export type EngagementSource = "auto" | "manual" | "pinned";
51
+ export interface ChatEngagement {
52
+ readonly skillId: string;
53
+ readonly slug: string;
54
+ readonly displayName: string;
55
+ readonly source: EngagementSource;
56
+ readonly rationale: string;
57
+ }
58
+ /**
59
+ * Resolve the final per-call engagement set. Composition rules:
60
+ * - Manual ENGAGE overrides matcher (always engaged).
61
+ * - Manual DISENGAGE overrides matcher + pinned (never engaged).
62
+ * - Pinned defaults engage unless manually disengaged.
63
+ * - Auto matches engage unless manually disengaged.
64
+ *
65
+ * Returns the final set tagged with the source so the UI panel can
66
+ * render badges + the user can see which decisions came from where.
67
+ */
68
+ export interface ResolveEngagementsInput {
69
+ readonly autoMatches: readonly SkillMatch[];
70
+ /**
71
+ * Manual overrides per chat. NULL = no overrides yet (auto + pinned only).
72
+ * Empty array = explicit "user disengaged everything" intent.
73
+ * Non-empty = list of explicit engages + disengages.
74
+ */
75
+ readonly manualOverrides: ReadonlyArray<{
76
+ skillId: string;
77
+ slug: string;
78
+ displayName: string;
79
+ intent: "engage" | "disengage";
80
+ }> | null;
81
+ readonly pinnedSkills: ReadonlyArray<{
82
+ skillId: string;
83
+ slug: string;
84
+ displayName: string;
85
+ }>;
86
+ }
87
+ export declare function resolveEngagements(input: ResolveEngagementsInput): ChatEngagement[];
88
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;kBAS1B,CAAC;AACZ,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC;CAC1C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,uFAAuF;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,EAAE,CA2C7D;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;QACtC,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;KAChC,CAAC,GAAG,IAAI,CAAC;IACV,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,cAAc,EAAE,CA+CnF"}
package/dist/skills.js ADDED
@@ -0,0 +1,127 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * P10A — skill auto-matcher (pure function).
4
+ *
5
+ * Scores site-active skills against the current chat turn's user
6
+ * message + element-reference chips. Top-K matches go into
7
+ * `auto`-source engagements; pinned defaults + manual overrides
8
+ * compose with the matcher output in the chat-runner.
9
+ *
10
+ * Scoring is intentionally simple — keyword + chip-trigger + always-on
11
+ * — to keep this layer LLM-free. The matcher runs every turn; an
12
+ * LLM-based matcher would double provider cost without obvious gain.
13
+ */
14
+ import { z } from "zod";
15
+ export const skillAutoEngagementHints = z
16
+ .object({
17
+ /** Lowercase substrings that boost the score when present in the user message. */
18
+ keywords: z.array(z.string().min(1).max(80)).default([]),
19
+ /** When true, engage automatically whenever element-ref chips are attached. */
20
+ chipTrigger: z.boolean().default(false),
21
+ /** When true, always engage on every call (e.g. brand-voice-guard). */
22
+ alwaysOn: z.boolean().default(false),
23
+ })
24
+ .strict();
25
+ /**
26
+ * Score every candidate skill against the turn context. Returns the
27
+ * top-K matches sorted by score (descending). `alwaysOn` skills always
28
+ * score at least 1; `chipTrigger` skills score 100 when chips present;
29
+ * keywords add 1 per matching keyword (case-insensitive substring).
30
+ *
31
+ * Skills with score 0 are dropped — they never engage automatically.
32
+ */
33
+ export function matchSkills(input) {
34
+ const topK = input.topK ?? 5;
35
+ const lowered = input.userMessage.toLowerCase();
36
+ const matches = [];
37
+ for (const s of input.skills) {
38
+ let score = 0;
39
+ const reasons = [];
40
+ if (s.hints.alwaysOn) {
41
+ score += 1;
42
+ reasons.push("always-on");
43
+ }
44
+ if (s.hints.chipTrigger && input.chipCount > 0) {
45
+ score += 100;
46
+ reasons.push(`element chips (${input.chipCount})`);
47
+ }
48
+ const matchedKeywords = [];
49
+ for (const k of s.hints.keywords) {
50
+ const needle = k.toLowerCase();
51
+ if (needle.length > 0 && lowered.includes(needle)) {
52
+ matchedKeywords.push(k);
53
+ }
54
+ }
55
+ if (matchedKeywords.length > 0) {
56
+ score += matchedKeywords.length;
57
+ const sample = matchedKeywords.slice(0, 3).join(", ");
58
+ reasons.push(matchedKeywords.length > 3
59
+ ? `keywords: ${sample}, +${matchedKeywords.length - 3}`
60
+ : `keywords: ${sample}`);
61
+ }
62
+ if (score > 0) {
63
+ matches.push({
64
+ skillId: s.id,
65
+ slug: s.slug,
66
+ displayName: s.displayName,
67
+ score,
68
+ rationale: reasons.join("; "),
69
+ });
70
+ }
71
+ }
72
+ matches.sort((a, b) => b.score - a.score || a.slug.localeCompare(b.slug));
73
+ return matches.slice(0, topK);
74
+ }
75
+ export function resolveEngagements(input) {
76
+ const disengaged = new Set();
77
+ const engagedManual = new Map();
78
+ if (input.manualOverrides) {
79
+ for (const m of input.manualOverrides) {
80
+ if (m.intent === "disengage") {
81
+ disengaged.add(m.skillId);
82
+ }
83
+ else {
84
+ engagedManual.set(m.skillId, {
85
+ skillId: m.skillId,
86
+ slug: m.slug,
87
+ displayName: m.displayName,
88
+ source: "manual",
89
+ rationale: "manually engaged",
90
+ });
91
+ }
92
+ }
93
+ }
94
+ const out = new Map();
95
+ // Pinned defaults first (lowest priority among engaged).
96
+ for (const p of input.pinnedSkills) {
97
+ if (disengaged.has(p.skillId))
98
+ continue;
99
+ out.set(p.skillId, {
100
+ skillId: p.skillId,
101
+ slug: p.slug,
102
+ displayName: p.displayName,
103
+ source: "pinned",
104
+ rationale: "pinned default",
105
+ });
106
+ }
107
+ // Auto matches — overwrite pinned label only if not already in out.
108
+ for (const a of input.autoMatches) {
109
+ if (disengaged.has(a.skillId))
110
+ continue;
111
+ if (out.has(a.skillId))
112
+ continue;
113
+ out.set(a.skillId, {
114
+ skillId: a.skillId,
115
+ slug: a.slug,
116
+ displayName: a.displayName,
117
+ source: "auto",
118
+ rationale: a.rationale,
119
+ });
120
+ }
121
+ // Manual engages always win — always overwrite.
122
+ for (const m of engagedManual.values()) {
123
+ out.set(m.skillId, m);
124
+ }
125
+ return [...out.values()];
126
+ }
127
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Zod input schemas for the P4 snapshot ops. Lives in @caelo-cms/shared so that
3
+ * route actions and the ops themselves import from a single source — same
4
+ * pattern as packages/shared/src/content.ts for P3.
5
+ *
6
+ * Every schema is `.strict()` so unknown keys are rejected at the Validator
7
+ * before the handler runs. Snapshot state JSONB is *not* validated by Zod
8
+ * here — it is emitted by trusted ops, never user-supplied (see CMS plan
9
+ * §"Validator rules").
10
+ */
11
+ import { z } from "zod";
12
+ export declare const snapshotsListInput: z.ZodObject<{
13
+ before: z.ZodOptional<z.ZodString>;
14
+ limit: z.ZodDefault<z.ZodNumber>;
15
+ forModuleId: z.ZodOptional<z.ZodString>;
16
+ forPageId: z.ZodOptional<z.ZodString>;
17
+ forTemplateId: z.ZodOptional<z.ZodString>;
18
+ opKinds: z.ZodOptional<z.ZodArray<z.ZodString>>;
19
+ includeArchived: z.ZodDefault<z.ZodBoolean>;
20
+ }, z.core.$strict>;
21
+ export declare const archiveOlderThanInput: z.ZodObject<{
22
+ before: z.ZodString;
23
+ limit: z.ZodDefault<z.ZodNumber>;
24
+ }, z.core.$strict>;
25
+ export type ArchiveOlderThanInput = z.infer<typeof archiveOlderThanInput>;
26
+ export declare const snapshotGetInput: z.ZodObject<{
27
+ snapshotId: z.ZodString;
28
+ }, z.core.$strict>;
29
+ export declare const moduleImpactInput: z.ZodObject<{
30
+ moduleId: z.ZodString;
31
+ }, z.core.$strict>;
32
+ export declare const revertSiteInput: z.ZodObject<{
33
+ snapshotId: z.ZodString;
34
+ }, z.core.$strict>;
35
+ export declare const revertModuleInput: z.ZodObject<{
36
+ moduleId: z.ZodString;
37
+ snapshotId: z.ZodString;
38
+ }, z.core.$strict>;
39
+ export declare const revertTemplateInput: z.ZodObject<{
40
+ templateId: z.ZodString;
41
+ snapshotId: z.ZodString;
42
+ }, z.core.$strict>;
43
+ export declare const revertPageInput: z.ZodObject<{
44
+ pageId: z.ZodString;
45
+ snapshotId: z.ZodString;
46
+ }, z.core.$strict>;
47
+ export type SnapshotsListInput = z.infer<typeof snapshotsListInput>;
48
+ export type SnapshotGetInput = z.infer<typeof snapshotGetInput>;
49
+ export type ModuleImpactInput = z.infer<typeof moduleImpactInput>;
50
+ export type RevertSiteInput = z.infer<typeof revertSiteInput>;
51
+ export type RevertModuleInput = z.infer<typeof revertModuleInput>;
52
+ export type RevertTemplateInput = z.infer<typeof revertTemplateInput>;
53
+ export type RevertPageInput = z.infer<typeof revertPageInput>;
54
+ //# sourceMappingURL=snapshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../src/snapshots.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;kBAgBpB,CAAC;AAEZ,eAAO,MAAM,qBAAqB;;;kBAOvB,CAAC;AACZ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E,eAAO,MAAM,gBAAgB;;kBAAuD,CAAC;AAErF,eAAO,MAAM,iBAAiB;;kBAAqD,CAAC;AAEpF,eAAO,MAAM,eAAe;;kBAAuD,CAAC;AAEpF,eAAO,MAAM,iBAAiB;;;kBAKnB,CAAC;AAEZ,eAAO,MAAM,mBAAmB;;;kBAKrB,CAAC;AAEZ,eAAO,MAAM,eAAe;;;kBAKjB,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACpE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACtE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -0,0 +1,59 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * Zod input schemas for the P4 snapshot ops. Lives in @caelo-cms/shared so that
4
+ * route actions and the ops themselves import from a single source — same
5
+ * pattern as packages/shared/src/content.ts for P3.
6
+ *
7
+ * Every schema is `.strict()` so unknown keys are rejected at the Validator
8
+ * before the handler runs. Snapshot state JSONB is *not* validated by Zod
9
+ * here — it is emitted by trusted ops, never user-supplied (see CMS plan
10
+ * §"Validator rules").
11
+ */
12
+ import { z } from "zod";
13
+ export const snapshotsListInput = z
14
+ .object({
15
+ /** ISO timestamp; only snapshots strictly before this are returned. */
16
+ before: z.string().datetime().optional(),
17
+ limit: z.number().int().min(1).max(200).default(50),
18
+ /** When set, only snapshots that touched this module are returned. */
19
+ forModuleId: z.string().uuid().optional(),
20
+ /** When set, only snapshots that touched this page (metadata or layout). */
21
+ forPageId: z.string().uuid().optional(),
22
+ /** When set, only snapshots that touched this template (incl. block changes). */
23
+ forTemplateId: z.string().uuid().optional(),
24
+ /** When set, only snapshots whose op_kind matches one of these values. */
25
+ opKinds: z.array(z.string()).optional(),
26
+ /** When true, archived snapshots are also returned. Defaults to false. */
27
+ includeArchived: z.boolean().default(false),
28
+ })
29
+ .strict();
30
+ export const archiveOlderThanInput = z
31
+ .object({
32
+ /** ISO timestamp; snapshots with `created_at < before` get archived_at set. */
33
+ before: z.string().datetime(),
34
+ /** Hard cap to keep one call from updating the whole table by mistake. */
35
+ limit: z.number().int().min(1).max(10_000).default(1000),
36
+ })
37
+ .strict();
38
+ export const snapshotGetInput = z.object({ snapshotId: z.string().uuid() }).strict();
39
+ export const moduleImpactInput = z.object({ moduleId: z.string().uuid() }).strict();
40
+ export const revertSiteInput = z.object({ snapshotId: z.string().uuid() }).strict();
41
+ export const revertModuleInput = z
42
+ .object({
43
+ moduleId: z.string().uuid(),
44
+ snapshotId: z.string().uuid(),
45
+ })
46
+ .strict();
47
+ export const revertTemplateInput = z
48
+ .object({
49
+ templateId: z.string().uuid(),
50
+ snapshotId: z.string().uuid(),
51
+ })
52
+ .strict();
53
+ export const revertPageInput = z
54
+ .object({
55
+ pageId: z.string().uuid(),
56
+ snapshotId: z.string().uuid(),
57
+ })
58
+ .strict();
59
+ //# sourceMappingURL=snapshots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshots.js","sourceRoot":"","sources":["../src/snapshots.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,uEAAuE;IACvE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACnD,sEAAsE;IACtE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACzC,4EAA4E;IAC5E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACvC,iFAAiF;IACjF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC3C,0EAA0E;IAC1E,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACvC,0EAA0E;IAC1E,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CAC5C,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,CAAC;IACN,+EAA+E;IAC/E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,0EAA0E;IAC1E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;CACzD,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAErF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAEpF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAEpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC3B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC9B,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC7B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC9B,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACzB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC9B,CAAC;KACD,MAAM,EAAE,CAAC"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * P6.7.5 — typed schemas for the `structured_sets` table.
3
+ *
4
+ * One database table holds N kinds of named lists (nav-menus, taxonomies,
5
+ * theme tokens, tag lists, footer link blocks, ...). The `kind`
6
+ * discriminator drives both the Zod validator at the Query API layer
7
+ * and the renderer that turns the items into HTML at preview / deploy.
8
+ *
9
+ * Adding a new kind: add a Zod schema below, add it to the
10
+ * `structuredSetItem` discriminated union, add a renderer in
11
+ * `packages/shared/src/structured-set-renderer.ts`. No DB migration
12
+ * required — the table already accepts arbitrary `kind` text.
13
+ *
14
+ * Item shapes are deliberately **structured data**, not HTML strings.
15
+ * That's what makes `change_page_slug` able to retarget every menu
16
+ * link automatically: walk the JSON, swap `href` matches.
17
+ */
18
+ import { z } from "zod";
19
+ /** Recursive nav menu — supports arbitrary submenu nesting. */
20
+ export declare const navMenuItem: z.ZodType<{
21
+ label: string;
22
+ href: string;
23
+ target?: "_self" | "_blank";
24
+ children?: {
25
+ label: string;
26
+ href: string;
27
+ }[];
28
+ /** When set, the renderer delegates this slot to the named ad plugin. */
29
+ adSlotId?: string;
30
+ }>;
31
+ /** Tree-shaped category list. Used by typed-content / tag pages (P12A). */
32
+ export declare const taxonomyItem: z.ZodObject<{
33
+ slug: z.ZodString;
34
+ displayName: z.ZodString;
35
+ parentSlug: z.ZodOptional<z.ZodString>;
36
+ description: z.ZodOptional<z.ZodString>;
37
+ }, z.core.$strict>;
38
+ /** One CSS variable. Renderer emits `<style>:root{--<token>: <value>;…}</style>`. */
39
+ export declare const themeToken: z.ZodObject<{
40
+ token: z.ZodString;
41
+ value: z.ZodString;
42
+ scope: z.ZodOptional<z.ZodEnum<{
43
+ color: "color";
44
+ font: "font";
45
+ space: "space";
46
+ radius: "radius";
47
+ shadow: "shadow";
48
+ }>>;
49
+ }, z.core.$strict>;
50
+ /** Flat tag — used by post taxonomies, content filtering. */
51
+ export declare const tagItem: z.ZodObject<{
52
+ slug: z.ZodString;
53
+ displayName: z.ZodString;
54
+ color: z.ZodOptional<z.ZodString>;
55
+ }, z.core.$strict>;
56
+ /** Footer "legal" / related-resources block. */
57
+ export declare const linkListItem: z.ZodObject<{
58
+ label: z.ZodString;
59
+ href: z.ZodString;
60
+ description: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strict>;
62
+ /**
63
+ * P9 review-pass — `language-selector` kind. Items are user-supplied
64
+ * overrides (e.g. force a specific display label per locale); empty
65
+ * array means "auto-populate from the locale registry at render time."
66
+ * The renderer (apps/static-generator + preview op) reads the locale
67
+ * registry + the current page's slug + resolveLocaleUrl to emit
68
+ * `<a hreflang lang href>` rows. Closes CMS_REQUIREMENTS §7.8.
69
+ */
70
+ export declare const languageSelectorOverride: z.ZodObject<{
71
+ locale: z.ZodString;
72
+ label: z.ZodOptional<z.ZodString>;
73
+ hidden: z.ZodOptional<z.ZodBoolean>;
74
+ }, z.core.$strict>;
75
+ /** Discriminated kind → items array. The Query API op picks the
76
+ * validator at runtime by reading `kind` first. */
77
+ export declare const structuredSetKind: z.ZodEnum<{
78
+ "nav-menu": "nav-menu";
79
+ taxonomy: "taxonomy";
80
+ theme: "theme";
81
+ tags: "tags";
82
+ "link-list": "link-list";
83
+ "language-selector": "language-selector";
84
+ }>;
85
+ export type StructuredSetKind = z.infer<typeof structuredSetKind>;
86
+ /** Validate `items` against the right schema for `kind`. Throws a
87
+ * ZodError on mismatch — callers wrap and return `Err(ValidationFailed)`. */
88
+ export declare function validateStructuredSetItems(kind: StructuredSetKind, items: unknown): unknown[];
89
+ export type NavMenuItem = z.infer<typeof navMenuItem>;
90
+ export type TaxonomyItem = z.infer<typeof taxonomyItem>;
91
+ export type ThemeToken = z.infer<typeof themeToken>;
92
+ export type TagItem = z.infer<typeof tagItem>;
93
+ export type LinkListItem = z.infer<typeof linkListItem>;
94
+ export type LanguageSelectorOverride = z.infer<typeof languageSelectorOverride>;
95
+ /**
96
+ * Render a `<nav class="caelo-language-selector">` with one `<a>`
97
+ * per locale that has a published variant of the current page. Pure
98
+ * function — caller threads the page's published-locale list and a
99
+ * URL resolver. Used by `composePagePreview` (admin) and the static
100
+ * generator (deploy) so byte-for-byte output parity holds.
101
+ *
102
+ * Per CMS_REQUIREMENTS §7.8: locales with no published variant for the
103
+ * current page are excluded.
104
+ */
105
+ export declare function renderLanguageSelector(args: {
106
+ /** Each locale that has a published variant of the current page. */
107
+ readonly availableLocales: ReadonlyArray<{
108
+ code: string;
109
+ displayName: string;
110
+ href: string;
111
+ isCurrent: boolean;
112
+ }>;
113
+ /** Owner-supplied overrides (relabel a locale, hide one). */
114
+ readonly overrides?: ReadonlyArray<LanguageSelectorOverride>;
115
+ }): string;
116
+ //# sourceMappingURL=structured-sets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-sets.d.ts","sourceRoot":"","sources":["../src/structured-sets.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,+DAA+D;AAC/D,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAUA,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,YAAY;;;;;kBAOd,CAAC;AAEZ,qFAAqF;AACrF,eAAO,MAAM,UAAU;;;;;;;;;;kBAUZ,CAAC;AAEZ,6DAA6D;AAC7D,eAAO,MAAM,OAAO;;;;kBAaT,CAAC;AAEZ,gDAAgD;AAChD,eAAO,MAAM,YAAY;;;;kBAMd,CAAC;AAEZ;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;kBAS1B,CAAC;AAEZ;oDACoD;AACpD,eAAO,MAAM,iBAAiB;;;;;;;EAO5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE;8EAC8E;AAC9E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAwB7F;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AACpD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC;AAC9C,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,oEAAoE;IACpE,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC;QACvC,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IACH,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC;CAC9D,GAAG,MAAM,CAgBT"}
@@ -0,0 +1,154 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * P6.7.5 — typed schemas for the `structured_sets` table.
4
+ *
5
+ * One database table holds N kinds of named lists (nav-menus, taxonomies,
6
+ * theme tokens, tag lists, footer link blocks, ...). The `kind`
7
+ * discriminator drives both the Zod validator at the Query API layer
8
+ * and the renderer that turns the items into HTML at preview / deploy.
9
+ *
10
+ * Adding a new kind: add a Zod schema below, add it to the
11
+ * `structuredSetItem` discriminated union, add a renderer in
12
+ * `packages/shared/src/structured-set-renderer.ts`. No DB migration
13
+ * required — the table already accepts arbitrary `kind` text.
14
+ *
15
+ * Item shapes are deliberately **structured data**, not HTML strings.
16
+ * That's what makes `change_page_slug` able to retarget every menu
17
+ * link automatically: walk the JSON, swap `href` matches.
18
+ */
19
+ import { z } from "zod";
20
+ /** Recursive nav menu — supports arbitrary submenu nesting. */
21
+ export const navMenuItem = z.lazy(() => z
22
+ .object({
23
+ label: z.string().min(1).max(120),
24
+ href: z.string().min(1).max(500),
25
+ target: z.enum(["_self", "_blank"]).optional(),
26
+ children: z.array(navMenuItem).optional(),
27
+ adSlotId: z.string().min(1).max(100).optional(),
28
+ })
29
+ .strict());
30
+ /** Tree-shaped category list. Used by typed-content / tag pages (P12A). */
31
+ export const taxonomyItem = z
32
+ .object({
33
+ slug: z.string().min(1).max(120),
34
+ displayName: z.string().min(1).max(200),
35
+ parentSlug: z.string().min(1).max(120).optional(),
36
+ description: z.string().max(2000).optional(),
37
+ })
38
+ .strict();
39
+ /** One CSS variable. Renderer emits `<style>:root{--<token>: <value>;…}</style>`. */
40
+ export const themeToken = z
41
+ .object({
42
+ token: z
43
+ .string()
44
+ .min(1)
45
+ .max(80)
46
+ .regex(/^[a-z][a-z0-9-]*$/, "lowercase kebab-case"),
47
+ value: z.string().min(1).max(500),
48
+ scope: z.enum(["color", "font", "space", "radius", "shadow"]).optional(),
49
+ })
50
+ .strict();
51
+ /** Flat tag — used by post taxonomies, content filtering. */
52
+ export const tagItem = z
53
+ .object({
54
+ slug: z
55
+ .string()
56
+ .min(1)
57
+ .max(120)
58
+ .regex(/^[a-z0-9-]+$/, "lowercase letters/digits/hyphens"),
59
+ displayName: z.string().min(1).max(200),
60
+ color: z
61
+ .string()
62
+ .regex(/^#[0-9a-fA-F]{3,8}$/, "hex color")
63
+ .optional(),
64
+ })
65
+ .strict();
66
+ /** Footer "legal" / related-resources block. */
67
+ export const linkListItem = z
68
+ .object({
69
+ label: z.string().min(1).max(200),
70
+ href: z.string().min(1).max(500),
71
+ description: z.string().max(500).optional(),
72
+ })
73
+ .strict();
74
+ /**
75
+ * P9 review-pass — `language-selector` kind. Items are user-supplied
76
+ * overrides (e.g. force a specific display label per locale); empty
77
+ * array means "auto-populate from the locale registry at render time."
78
+ * The renderer (apps/static-generator + preview op) reads the locale
79
+ * registry + the current page's slug + resolveLocaleUrl to emit
80
+ * `<a hreflang lang href>` rows. Closes CMS_REQUIREMENTS §7.8.
81
+ */
82
+ export const languageSelectorOverride = z
83
+ .object({
84
+ /** BCP-47 locale code; must match a row in the locales registry. */
85
+ locale: z.string().min(2).max(10),
86
+ /** Override the locale's display_name when rendering this entry. */
87
+ label: z.string().min(1).max(120).optional(),
88
+ /** Hide this locale from the rendered selector even if it has a published page. */
89
+ hidden: z.boolean().optional(),
90
+ })
91
+ .strict();
92
+ /** Discriminated kind → items array. The Query API op picks the
93
+ * validator at runtime by reading `kind` first. */
94
+ export const structuredSetKind = z.enum([
95
+ "nav-menu",
96
+ "taxonomy",
97
+ "theme",
98
+ "tags",
99
+ "link-list",
100
+ "language-selector",
101
+ ]);
102
+ /** Validate `items` against the right schema for `kind`. Throws a
103
+ * ZodError on mismatch — callers wrap and return `Err(ValidationFailed)`. */
104
+ export function validateStructuredSetItems(kind, items) {
105
+ if (!Array.isArray(items)) {
106
+ throw new z.ZodError([
107
+ {
108
+ code: "custom",
109
+ path: ["items"],
110
+ message: "items must be an array",
111
+ },
112
+ ]);
113
+ }
114
+ switch (kind) {
115
+ case "nav-menu":
116
+ return items.map((it) => navMenuItem.parse(it));
117
+ case "taxonomy":
118
+ return items.map((it) => taxonomyItem.parse(it));
119
+ case "theme":
120
+ return items.map((it) => themeToken.parse(it));
121
+ case "tags":
122
+ return items.map((it) => tagItem.parse(it));
123
+ case "link-list":
124
+ return items.map((it) => linkListItem.parse(it));
125
+ case "language-selector":
126
+ return items.map((it) => languageSelectorOverride.parse(it));
127
+ }
128
+ }
129
+ /**
130
+ * Render a `<nav class="caelo-language-selector">` with one `<a>`
131
+ * per locale that has a published variant of the current page. Pure
132
+ * function — caller threads the page's published-locale list and a
133
+ * URL resolver. Used by `composePagePreview` (admin) and the static
134
+ * generator (deploy) so byte-for-byte output parity holds.
135
+ *
136
+ * Per CMS_REQUIREMENTS §7.8: locales with no published variant for the
137
+ * current page are excluded.
138
+ */
139
+ export function renderLanguageSelector(args) {
140
+ const overrideByLocale = new Map((args.overrides ?? []).map((o) => [o.locale, o]));
141
+ const enc = (s) => s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
142
+ const items = args.availableLocales
143
+ .filter((l) => !overrideByLocale.get(l.code)?.hidden)
144
+ .map((l) => {
145
+ const override = overrideByLocale.get(l.code);
146
+ const label = override?.label ?? l.displayName;
147
+ const aria = l.isCurrent ? ' aria-current="true"' : "";
148
+ return `<a hreflang="${enc(l.code)}" lang="${enc(l.code)}" href="${enc(l.href)}"${aria}>${enc(label)}</a>`;
149
+ });
150
+ if (items.length === 0)
151
+ return "";
152
+ return `<nav class="caelo-language-selector" aria-label="Language">${items.join("")}</nav>`;
153
+ }
154
+ //# sourceMappingURL=structured-sets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-sets.js","sourceRoot":"","sources":["../src/structured-sets.ts"],"names":[],"mappings":"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"}