@growth-labs/cms 0.5.27 → 0.5.29

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 (44) hide show
  1. package/README.md +20 -0
  2. package/dist/engine/slug.d.ts.map +1 -1
  3. package/dist/engine/slug.js +11 -1
  4. package/dist/engine/slug.js.map +1 -1
  5. package/dist/integration/options.d.ts +196 -0
  6. package/dist/integration/options.d.ts.map +1 -1
  7. package/dist/integration/options.js +62 -0
  8. package/dist/integration/options.js.map +1 -1
  9. package/dist/routes/content.d.ts.map +1 -1
  10. package/dist/routes/content.js +30 -0
  11. package/dist/routes/content.js.map +1 -1
  12. package/dist/ui/client/mount.d.ts.map +1 -1
  13. package/dist/ui/client/mount.js +1 -0
  14. package/dist/ui/client/mount.js.map +1 -1
  15. package/dist/ui/editor/ContentForm.d.ts +3 -1
  16. package/dist/ui/editor/ContentForm.d.ts.map +1 -1
  17. package/dist/ui/editor/ContentForm.js +35 -8
  18. package/dist/ui/editor/ContentForm.js.map +1 -1
  19. package/dist/ui/editor/content-payload.d.ts +12 -0
  20. package/dist/ui/editor/content-payload.d.ts.map +1 -1
  21. package/dist/ui/editor/content-payload.js +24 -0
  22. package/dist/ui/editor/content-payload.js.map +1 -1
  23. package/dist/ui/screens/ContentRoute.d.ts +3 -1
  24. package/dist/ui/screens/ContentRoute.d.ts.map +1 -1
  25. package/dist/ui/screens/ContentRoute.js +2 -2
  26. package/dist/ui/screens/ContentRoute.js.map +1 -1
  27. package/dist/ui/screens/EditorScreen.d.ts +3 -1
  28. package/dist/ui/screens/EditorScreen.d.ts.map +1 -1
  29. package/dist/ui/screens/EditorScreen.js +2 -2
  30. package/dist/ui/screens/EditorScreen.js.map +1 -1
  31. package/dist/ui/screens/registry.d.ts +3 -1
  32. package/dist/ui/screens/registry.d.ts.map +1 -1
  33. package/dist/ui/screens/registry.js +2 -2
  34. package/dist/ui/screens/registry.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/engine/slug.ts +12 -1
  37. package/src/integration/options.ts +69 -0
  38. package/src/routes/content.ts +37 -0
  39. package/src/ui/client/mount.tsx +1 -0
  40. package/src/ui/editor/ContentForm.tsx +74 -5
  41. package/src/ui/editor/content-payload.ts +39 -0
  42. package/src/ui/screens/ContentRoute.tsx +4 -0
  43. package/src/ui/screens/EditorScreen.tsx +4 -0
  44. package/src/ui/screens/registry.tsx +4 -0
package/README.md CHANGED
@@ -103,6 +103,26 @@ Masthead consumers can expose named category controls by passing
103
103
  persists the selected slug through `primaryCategory`, and the Library can filter
104
104
  the same canonical `content_items.channel` value.
105
105
 
106
+ Sites can also expose bounded metadata selects without forking Masthead:
107
+
108
+ ```ts
109
+ contentMetadataSelects: [{
110
+ key: 'format',
111
+ label: 'Format',
112
+ contentTypes: ['video'],
113
+ options: [
114
+ { value: 'briefing', label: 'Briefing' },
115
+ { value: 'series', label: 'Series' },
116
+ ],
117
+ defaultValue: 'briefing',
118
+ inferenceMarkerKey: 'format_inferred',
119
+ }]
120
+ ```
121
+
122
+ Values live in the existing bounded `content_items.metadata_json` object and
123
+ participate in normal revisions. Masthead preserves undeclared keys; a human
124
+ selection clears only the configured inference marker.
125
+
106
126
  The Masthead rich-text editor keeps link and underline marks off leading and
107
127
  trailing whitespace for both toolbar selections and pasted formatted content.
108
128
  Underline is trimmed independently from the link mark: boundary whitespace is
@@ -1 +1 @@
1
- {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../src/engine/slug.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,EAC7D,IAAI,EAAE,MAAM,GACV,MAAM,CAER"}
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../src/engine/slug.ts"],"names":[],"mappings":"AAcA,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,EAC7D,IAAI,EAAE,MAAM,GACV,MAAM,CAER"}
@@ -1,9 +1,19 @@
1
1
  // Slug helpers ported verbatim from fulcrum-labs/fronts src/lib/slug.ts
2
2
  // (inventory §1: `slug.ts` — extract, pure). No Fronts coupling.
3
+ // Straight quotes/backtick plus every smart-quote and prime variant editors'
4
+ // paste sources (Word, Google Docs, iOS) actually produce. Stripping only the
5
+ // straight forms let curly apostrophes survive as literal characters instead
6
+ // of being removed before the non-alphanumeric collapse below, so
7
+ // "Ukraine's" slugified to "ukraine-s" instead of "ukraines" (packages#397).
8
+ // Covers, via \uXXXX escapes (not literal glyphs, for unambiguous
9
+ // editors/diffs): ' " ` (straight) ‘-‟ (curly single/double quote
10
+ // family, incl. low-9/reversed-9 variants) ′/″ (prime/double
11
+ // prime) ʼ (modifier letter apostrophe).
12
+ const QUOTE_CHARS = /['"`‘-‟′″ʼ]/g;
3
13
  export function slugify(input) {
4
14
  return input
5
15
  .toLowerCase()
6
- .replace(/['"`]/g, '')
16
+ .replace(QUOTE_CHARS, '')
7
17
  .replace(/[^a-z0-9]+/g, '-')
8
18
  .replace(/^-+|-+$/g, '')
9
19
  .replace(/--+/g, '-')
@@ -1 +1 @@
1
- {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/engine/slug.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,iEAAiE;AAEjE,MAAM,UAAU,OAAO,CAAC,KAAa;IACpC,OAAO,KAAK;SACV,WAAW,EAAE;SACb,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;AACT,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAgC;IAC7D,OAAO,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IACnD,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAA;IACzB,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAClD,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,GAAG,CAAA;IAC7C,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,IAA6D,EAC7D,IAAY;IAEZ,OAAO,mBAAmB,CAAC,IAAI,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC9D,CAAC"}
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/engine/slug.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,iEAAiE;AAEjE,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,kEAAkE;AAClE,6EAA6E;AAC7E,kEAAkE;AAClE,kEAAkE;AAClE,6DAA6D;AAC7D,yCAAyC;AACzC,MAAM,WAAW,GAAG,cAAc,CAAA;AAElC,MAAM,UAAU,OAAO,CAAC,KAAa;IACpC,OAAO,KAAK;SACV,WAAW,EAAE;SACb,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;AACT,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAgC;IAC7D,OAAO,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IACnD,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAA;IACzB,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAClD,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,GAAG,CAAA;IAC7C,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,IAA6D,EAC7D,IAAY;IAEZ,OAAO,mBAAmB,CAAC,IAAI,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC9D,CAAC"}
@@ -1,4 +1,67 @@
1
1
  import { z } from 'zod';
2
+ declare const contentMetadataSelectFieldSchema: z.ZodEffects<z.ZodObject<{
3
+ key: z.ZodString;
4
+ label: z.ZodString;
5
+ helpText: z.ZodOptional<z.ZodString>;
6
+ contentTypes: z.ZodArray<z.ZodEnum<["article", "video", "podcast", "newsletter", "page"]>, "many">;
7
+ options: z.ZodArray<z.ZodObject<{
8
+ value: z.ZodString;
9
+ label: z.ZodString;
10
+ }, "strict", z.ZodTypeAny, {
11
+ value: string;
12
+ label: string;
13
+ }, {
14
+ value: string;
15
+ label: string;
16
+ }>, "many">;
17
+ defaultValue: z.ZodOptional<z.ZodString>;
18
+ inferenceMarkerKey: z.ZodOptional<z.ZodString>;
19
+ }, "strict", z.ZodTypeAny, {
20
+ options: {
21
+ value: string;
22
+ label: string;
23
+ }[];
24
+ key: string;
25
+ label: string;
26
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
27
+ helpText?: string | undefined;
28
+ defaultValue?: string | undefined;
29
+ inferenceMarkerKey?: string | undefined;
30
+ }, {
31
+ options: {
32
+ value: string;
33
+ label: string;
34
+ }[];
35
+ key: string;
36
+ label: string;
37
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
38
+ helpText?: string | undefined;
39
+ defaultValue?: string | undefined;
40
+ inferenceMarkerKey?: string | undefined;
41
+ }>, {
42
+ options: {
43
+ value: string;
44
+ label: string;
45
+ }[];
46
+ key: string;
47
+ label: string;
48
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
49
+ helpText?: string | undefined;
50
+ defaultValue?: string | undefined;
51
+ inferenceMarkerKey?: string | undefined;
52
+ }, {
53
+ options: {
54
+ value: string;
55
+ label: string;
56
+ }[];
57
+ key: string;
58
+ label: string;
59
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
60
+ helpText?: string | undefined;
61
+ defaultValue?: string | undefined;
62
+ inferenceMarkerKey?: string | undefined;
63
+ }>;
64
+ export type ContentMetadataSelectField = z.output<typeof contentMetadataSelectFieldSchema>;
2
65
  export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
3
66
  workspaces: z.ZodArray<z.ZodObject<{
4
67
  id: z.ZodString;
@@ -26,6 +89,90 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
26
89
  slug: string;
27
90
  label: string;
28
91
  }>, "many">>;
92
+ contentMetadataSelects: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodObject<{
93
+ key: z.ZodString;
94
+ label: z.ZodString;
95
+ helpText: z.ZodOptional<z.ZodString>;
96
+ contentTypes: z.ZodArray<z.ZodEnum<["article", "video", "podcast", "newsletter", "page"]>, "many">;
97
+ options: z.ZodArray<z.ZodObject<{
98
+ value: z.ZodString;
99
+ label: z.ZodString;
100
+ }, "strict", z.ZodTypeAny, {
101
+ value: string;
102
+ label: string;
103
+ }, {
104
+ value: string;
105
+ label: string;
106
+ }>, "many">;
107
+ defaultValue: z.ZodOptional<z.ZodString>;
108
+ inferenceMarkerKey: z.ZodOptional<z.ZodString>;
109
+ }, "strict", z.ZodTypeAny, {
110
+ options: {
111
+ value: string;
112
+ label: string;
113
+ }[];
114
+ key: string;
115
+ label: string;
116
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
117
+ helpText?: string | undefined;
118
+ defaultValue?: string | undefined;
119
+ inferenceMarkerKey?: string | undefined;
120
+ }, {
121
+ options: {
122
+ value: string;
123
+ label: string;
124
+ }[];
125
+ key: string;
126
+ label: string;
127
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
128
+ helpText?: string | undefined;
129
+ defaultValue?: string | undefined;
130
+ inferenceMarkerKey?: string | undefined;
131
+ }>, {
132
+ options: {
133
+ value: string;
134
+ label: string;
135
+ }[];
136
+ key: string;
137
+ label: string;
138
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
139
+ helpText?: string | undefined;
140
+ defaultValue?: string | undefined;
141
+ inferenceMarkerKey?: string | undefined;
142
+ }, {
143
+ options: {
144
+ value: string;
145
+ label: string;
146
+ }[];
147
+ key: string;
148
+ label: string;
149
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
150
+ helpText?: string | undefined;
151
+ defaultValue?: string | undefined;
152
+ inferenceMarkerKey?: string | undefined;
153
+ }>, "many">, {
154
+ options: {
155
+ value: string;
156
+ label: string;
157
+ }[];
158
+ key: string;
159
+ label: string;
160
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
161
+ helpText?: string | undefined;
162
+ defaultValue?: string | undefined;
163
+ inferenceMarkerKey?: string | undefined;
164
+ }[], {
165
+ options: {
166
+ value: string;
167
+ label: string;
168
+ }[];
169
+ key: string;
170
+ label: string;
171
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
172
+ helpText?: string | undefined;
173
+ defaultValue?: string | undefined;
174
+ inferenceMarkerKey?: string | undefined;
175
+ }[]>>;
29
176
  activeWorkspaceId: z.ZodOptional<z.ZodString>;
30
177
  adminBasePath: z.ZodDefault<z.ZodString>;
31
178
  searchEnabled: z.ZodDefault<z.ZodBoolean>;
@@ -71,6 +218,18 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
71
218
  slug: string;
72
219
  label: string;
73
220
  }[];
221
+ contentMetadataSelects: {
222
+ options: {
223
+ value: string;
224
+ label: string;
225
+ }[];
226
+ key: string;
227
+ label: string;
228
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
229
+ helpText?: string | undefined;
230
+ defaultValue?: string | undefined;
231
+ inferenceMarkerKey?: string | undefined;
232
+ }[];
74
233
  adminBasePath: string;
75
234
  searchEnabled: boolean;
76
235
  stubPuckSsrRichtext: boolean;
@@ -98,6 +257,18 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
98
257
  slug: string;
99
258
  label: string;
100
259
  }[] | undefined;
260
+ contentMetadataSelects?: {
261
+ options: {
262
+ value: string;
263
+ label: string;
264
+ }[];
265
+ key: string;
266
+ label: string;
267
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
268
+ helpText?: string | undefined;
269
+ defaultValue?: string | undefined;
270
+ inferenceMarkerKey?: string | undefined;
271
+ }[] | undefined;
101
272
  activeWorkspaceId?: string | undefined;
102
273
  adminBasePath?: string | undefined;
103
274
  searchEnabled?: boolean | undefined;
@@ -126,6 +297,18 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
126
297
  slug: string;
127
298
  label: string;
128
299
  }[];
300
+ contentMetadataSelects: {
301
+ options: {
302
+ value: string;
303
+ label: string;
304
+ }[];
305
+ key: string;
306
+ label: string;
307
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
308
+ helpText?: string | undefined;
309
+ defaultValue?: string | undefined;
310
+ inferenceMarkerKey?: string | undefined;
311
+ }[];
129
312
  adminBasePath: string;
130
313
  searchEnabled: boolean;
131
314
  stubPuckSsrRichtext: boolean;
@@ -152,6 +335,18 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
152
335
  slug: string;
153
336
  label: string;
154
337
  }[] | undefined;
338
+ contentMetadataSelects?: {
339
+ options: {
340
+ value: string;
341
+ label: string;
342
+ }[];
343
+ key: string;
344
+ label: string;
345
+ contentTypes: ("article" | "video" | "podcast" | "newsletter" | "page")[];
346
+ helpText?: string | undefined;
347
+ defaultValue?: string | undefined;
348
+ inferenceMarkerKey?: string | undefined;
349
+ }[] | undefined;
155
350
  activeWorkspaceId?: string | undefined;
156
351
  adminBasePath?: string | undefined;
157
352
  searchEnabled?: boolean | undefined;
@@ -171,4 +366,5 @@ export declare const cmsIntegrationOptionsSchema: z.ZodEffects<z.ZodObject<{
171
366
  }>;
172
367
  export type CmsIntegrationOptions = z.input<typeof cmsIntegrationOptionsSchema>;
173
368
  export type ResolvedCmsIntegrationOptions = z.output<typeof cmsIntegrationOptionsSchema>;
369
+ export {};
174
370
  //# sourceMappingURL=options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/integration/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAoCvB,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBoD,CAAA;AAE5F,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAC/E,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAA"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/integration/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAmBvB,QAAA,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CnC,CAAA;AAmBH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gCAAgC,CAAC,CAAA;AAuB1F,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBoD,CAAA;AAE5F,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAC/E,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAA"}
@@ -10,6 +10,67 @@ const primaryCategorySchema = z.object({
10
10
  slug: z.string().min(1),
11
11
  label: z.string().min(1),
12
12
  });
13
+ const contentMetadataKeySchema = z
14
+ .string()
15
+ .regex(/^[a-z][a-z0-9_]{0,63}$/, 'metadata keys must be lowercase snake_case');
16
+ const contentMetadataSelectFieldSchema = z
17
+ .object({
18
+ key: contentMetadataKeySchema,
19
+ label: z.string().trim().min(1).max(100),
20
+ helpText: z.string().trim().min(1).max(500).optional(),
21
+ contentTypes: z.array(z.enum(['article', 'video', 'podcast', 'newsletter', 'page'])).min(1),
22
+ options: z
23
+ .array(z
24
+ .object({
25
+ value: z.string().trim().min(1).max(100),
26
+ label: z.string().trim().min(1).max(100),
27
+ })
28
+ .strict())
29
+ .min(1),
30
+ defaultValue: z.string().trim().min(1).max(100).optional(),
31
+ inferenceMarkerKey: contentMetadataKeySchema.optional(),
32
+ })
33
+ .strict()
34
+ .superRefine((field, ctx) => {
35
+ const values = field.options.map(({ value }) => value);
36
+ if (new Set(values).size !== values.length) {
37
+ ctx.addIssue({
38
+ code: 'custom',
39
+ path: ['options'],
40
+ message: 'metadata select option values must be unique',
41
+ });
42
+ }
43
+ if (field.defaultValue && !values.includes(field.defaultValue)) {
44
+ ctx.addIssue({
45
+ code: 'custom',
46
+ path: ['defaultValue'],
47
+ message: 'metadata select defaultValue must match a declared option',
48
+ });
49
+ }
50
+ if (field.inferenceMarkerKey === field.key) {
51
+ ctx.addIssue({
52
+ code: 'custom',
53
+ path: ['inferenceMarkerKey'],
54
+ message: 'metadata select inference marker must use a separate key',
55
+ });
56
+ }
57
+ });
58
+ const contentMetadataSelectsSchema = z
59
+ .array(contentMetadataSelectFieldSchema)
60
+ .superRefine((fields, ctx) => {
61
+ const keys = new Set();
62
+ for (const [index, field] of fields.entries()) {
63
+ if (keys.has(field.key)) {
64
+ ctx.addIssue({
65
+ code: 'custom',
66
+ path: [index, 'key'],
67
+ message: 'metadata select keys must be unique',
68
+ });
69
+ }
70
+ keys.add(field.key);
71
+ }
72
+ })
73
+ .default([]);
13
74
  const themeSchema = z
14
75
  .object({
15
76
  mode: z.enum(['light', 'dark']).default('dark'),
@@ -32,6 +93,7 @@ export const cmsIntegrationOptionsSchema = z
32
93
  .object({
33
94
  workspaces: z.array(workspaceSchema).min(1, 'at least one workspace is required'),
34
95
  primaryCategories: z.array(primaryCategorySchema).default([]),
96
+ contentMetadataSelects: contentMetadataSelectsSchema,
35
97
  activeWorkspaceId: z.string().optional(),
36
98
  adminBasePath: z.string().default('/admin'),
37
99
  searchEnabled: z.boolean().default(true),
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/integration/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;CACpC,CAAC,CAAA;AAEF,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxB,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC;KACnB,MAAM,CAAC;IACP,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IACjF,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACnE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACvC,CAAC;KACD,OAAO,CAAC,EAAE,CAAC,CAAA;AAEb,MAAM,mBAAmB,GAAG,CAAC;KAC3B,MAAM,CAAC;IACP,yBAAyB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACpD,CAAC;KACD,OAAO,CAAC,EAAE,CAAC,CAAA;AAEb,MAAM,mBAAmB,GAAG,CAAC;KAC3B,MAAM,CAAC;IACP,QAAQ,EAAE,cAAc;CACxB,CAAC;KACD,MAAM,EAAE,CAAA;AAEV,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC;KAC1C,MAAM,CAAC;IACP,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,oCAAoC,CAAC;IACjF,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7D,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC3C,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACxC,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,yEAAyE;IACzE,0EAA0E;IAC1E,4BAA4B;IAC5B,mBAAmB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9C,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,mBAAmB,CAAC,QAAQ,EAAE;CAC7C,CAAC;KACD,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/integration/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;CACpC,CAAC,CAAA;AAEF,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxB,CAAC,CAAA;AAEF,MAAM,wBAAwB,GAAG,CAAC;KAChC,MAAM,EAAE;KACR,KAAK,CAAC,wBAAwB,EAAE,4CAA4C,CAAC,CAAA;AAE/E,MAAM,gCAAgC,GAAG,CAAC;KACxC,MAAM,CAAC;IACP,GAAG,EAAE,wBAAwB;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACtD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,OAAO,EAAE,CAAC;SACR,KAAK,CACL,CAAC;SACC,MAAM,CAAC;QACP,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;KACxC,CAAC;SACD,MAAM,EAAE,CACV;SACA,GAAG,CAAC,CAAC,CAAC;IACR,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC1D,kBAAkB,EAAE,wBAAwB,CAAC,QAAQ,EAAE;CACvD,CAAC;KACD,MAAM,EAAE;KACR,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IACtD,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC5C,GAAG,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,SAAS,CAAC;YACjB,OAAO,EAAE,8CAA8C;SACvD,CAAC,CAAA;IACH,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,cAAc,CAAC;YACtB,OAAO,EAAE,2DAA2D;SACpE,CAAC,CAAA;IACH,CAAC;IACD,IAAI,KAAK,CAAC,kBAAkB,KAAK,KAAK,CAAC,GAAG,EAAE,CAAC;QAC5C,GAAG,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,OAAO,EAAE,0DAA0D;SACnE,CAAC,CAAA;IACH,CAAC;AACF,CAAC,CAAC,CAAA;AAEH,MAAM,4BAA4B,GAAG,CAAC;KACpC,KAAK,CAAC,gCAAgC,CAAC;KACvC,WAAW,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAC5B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,QAAQ,CAAC;gBACZ,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;gBACpB,OAAO,EAAE,qCAAqC;aAC9C,CAAC,CAAA;QACH,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACpB,CAAC;AACF,CAAC,CAAC;KACD,OAAO,CAAC,EAAE,CAAC,CAAA;AAIb,MAAM,WAAW,GAAG,CAAC;KACnB,MAAM,CAAC;IACP,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IACjF,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACnE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACvC,CAAC;KACD,OAAO,CAAC,EAAE,CAAC,CAAA;AAEb,MAAM,mBAAmB,GAAG,CAAC;KAC3B,MAAM,CAAC;IACP,yBAAyB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACpD,CAAC;KACD,OAAO,CAAC,EAAE,CAAC,CAAA;AAEb,MAAM,mBAAmB,GAAG,CAAC;KAC3B,MAAM,CAAC;IACP,QAAQ,EAAE,cAAc;CACxB,CAAC;KACD,MAAM,EAAE,CAAA;AAEV,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC;KAC1C,MAAM,CAAC;IACP,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,oCAAoC,CAAC;IACjF,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7D,sBAAsB,EAAE,4BAA4B;IACpD,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC3C,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACxC,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,yEAAyE;IACzE,0EAA0E;IAC1E,4BAA4B;IAC5B,mBAAmB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9C,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,mBAAmB,CAAC,QAAQ,EAAE;CAC7C,CAAC;KACD,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/routes/content.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/routes/content.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ import { z } from 'zod';
17
17
  import { logActivity } from '../engine/activity-log.js';
18
18
  import { generateContentDek } from '../engine/ai-dek.js';
19
19
  import { createDekFailureNotifications } from '../engine/ai-dek-notifications.js';
20
+ import { ContentMetadataError, serializeContentMetadata, } from '../engine/content-metadata.js';
20
21
  import { listContributors, setContributors } from '../engine/contributors.js';
21
22
  import { applyFoundryCallback, dispatchToFoundry, FoundryDispatchPrerequisiteError, verifyHmac, } from '../engine/foundry-dispatch.js';
22
23
  import { evaluateArticleBody } from '../engine/publish-guard.js';
@@ -168,6 +169,20 @@ const BodyContentCreateSchema = z.object({
168
169
  readTimeMinutes: z.number().int().optional().nullable(),
169
170
  editorTakeaways: z.array(z.string().min(1)).max(4).optional().nullable(),
170
171
  });
172
+ const ContentMetadataSchema = z
173
+ .record(z.string(), z.unknown())
174
+ .superRefine((metadata, ctx) => {
175
+ try {
176
+ serializeContentMetadata(metadata);
177
+ }
178
+ catch (error) {
179
+ ctx.addIssue({
180
+ code: 'custom',
181
+ message: error instanceof ContentMetadataError ? error.message : 'content metadata is invalid',
182
+ });
183
+ }
184
+ })
185
+ .transform((metadata) => metadata);
171
186
  function buildSchemas(resolved) {
172
187
  const category = slugEnum(resolved.primaryCategorySlugs);
173
188
  const topic = slugEnum(resolved.primaryTopicSlugs);
@@ -189,6 +204,7 @@ function buildSchemas(resolved) {
189
204
  socialImageId: z.string().optional().nullable(),
190
205
  canonicalUrl: z.string().url().optional().nullable(),
191
206
  tags: z.array(z.string()).optional(),
207
+ metadata: ContentMetadataSchema.optional(),
192
208
  });
193
209
  const CreateSchema = z.discriminatedUnion('type', [
194
210
  BaseSchema.extend({
@@ -250,6 +266,7 @@ function buildSchemas(resolved) {
250
266
  socialImageId: z.string().optional().nullable(),
251
267
  canonicalUrl: z.string().url().optional().nullable(),
252
268
  tags: z.array(z.string()).optional(),
269
+ metadata: ContentMetadataSchema.optional(),
253
270
  content: z.record(z.string(), z.any()).optional(),
254
271
  relations: z.array(RelationSchema).optional(),
255
272
  aiLockedFields: z.array(z.string()).optional(),
@@ -893,6 +910,11 @@ export function createContentRoutes(config) {
893
910
  if (!parsed.success) {
894
911
  return json({ error: 'Invalid request', details: parsed.error.flatten() }, 400);
895
912
  }
913
+ // Warn-severity body-lint results. Declared here so the success payload
914
+ // below can carry them: they do not block the save, but an editor who is
915
+ // never told is how a malformed Sources section reached a published page
916
+ // (packages#329).
917
+ let bodyWarnings = [];
896
918
  if (parsed.data.content !== undefined) {
897
919
  const contentSchema = getContentUpdateSchema(existing.type);
898
920
  if (!contentSchema)
@@ -919,6 +941,11 @@ export function createContentRoutes(config) {
919
941
  if (!guard.ok) {
920
942
  return json({ error: 'Article body failed pre-publish validation', errors: guard.errors }, 422);
921
943
  }
944
+ // Warn-severity violations do not block the save, but the editor
945
+ // has to be told: an unreported warning is why a malformed Sources
946
+ // section reached a published page (packages#329). Carried into
947
+ // the 200 payload below rather than only console.warn'd.
948
+ bodyWarnings = guard.warnings;
922
949
  }
923
950
  }
924
951
  }
@@ -952,6 +979,9 @@ export function createContentRoutes(config) {
952
979
  podcastFoundryQueued: Boolean(podcastAttempt.result),
953
980
  podcastFoundryCorrelationId: podcastAttempt.result?.correlationId ?? null,
954
981
  podcastFoundryReason: podcastAttempt.reason,
982
+ // Present and empty when the body linted clean, so a client can
983
+ // distinguish "no warnings" from "this build does not report them".
984
+ bodyWarnings,
955
985
  });
956
986
  },
957
987
  async action(ctx) {