@krantho/schema 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/dist/archetypes.d.ts +39 -0
  3. package/dist/archetypes.d.ts.map +1 -0
  4. package/dist/archetypes.js +139 -0
  5. package/dist/archetypes.js.map +1 -0
  6. package/dist/collection.d.ts +78 -0
  7. package/dist/collection.d.ts.map +1 -0
  8. package/dist/collection.js +65 -0
  9. package/dist/collection.js.map +1 -0
  10. package/dist/config.d.ts +27 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +38 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/content-archetypes.d.ts +34 -0
  15. package/dist/content-archetypes.d.ts.map +1 -0
  16. package/dist/content-archetypes.js +64 -0
  17. package/dist/content-archetypes.js.map +1 -0
  18. package/dist/contract-codegen.d.ts +11 -0
  19. package/dist/contract-codegen.d.ts.map +1 -0
  20. package/dist/contract-codegen.js +29 -0
  21. package/dist/contract-codegen.js.map +1 -0
  22. package/dist/errors.d.ts +31 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +28 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.d.ts +26 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +20 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/metadata-defaults.d.ts +10 -0
  31. package/dist/metadata-defaults.d.ts.map +1 -0
  32. package/dist/metadata-defaults.js +73 -0
  33. package/dist/metadata-defaults.js.map +1 -0
  34. package/dist/page/define-page.d.ts +21 -0
  35. package/dist/page/define-page.d.ts.map +1 -0
  36. package/dist/page/define-page.js +28 -0
  37. package/dist/page/define-page.js.map +1 -0
  38. package/dist/page/index.d.ts +4 -0
  39. package/dist/page/index.d.ts.map +1 -0
  40. package/dist/page/index.js +3 -0
  41. package/dist/page/index.js.map +1 -0
  42. package/dist/page/references.d.ts +24 -0
  43. package/dist/page/references.d.ts.map +1 -0
  44. package/dist/page/references.js +29 -0
  45. package/dist/page/references.js.map +1 -0
  46. package/dist/page/types.d.ts +50 -0
  47. package/dist/page/types.d.ts.map +1 -0
  48. package/dist/page/types.js +10 -0
  49. package/dist/page/types.js.map +1 -0
  50. package/dist/portable-schema.d.ts +6 -0
  51. package/dist/portable-schema.d.ts.map +1 -0
  52. package/dist/portable-schema.js +30 -0
  53. package/dist/portable-schema.js.map +1 -0
  54. package/dist/presets.d.ts +24 -0
  55. package/dist/presets.d.ts.map +1 -0
  56. package/dist/presets.js +23 -0
  57. package/dist/presets.js.map +1 -0
  58. package/dist/repository-content.d.ts +17 -0
  59. package/dist/repository-content.d.ts.map +1 -0
  60. package/dist/repository-content.js +65 -0
  61. package/dist/repository-content.js.map +1 -0
  62. package/dist/resolved-contract.d.ts +5 -0
  63. package/dist/resolved-contract.d.ts.map +1 -0
  64. package/dist/resolved-contract.js +28 -0
  65. package/dist/resolved-contract.js.map +1 -0
  66. package/dist/runtime-schema.d.ts +24 -0
  67. package/dist/runtime-schema.d.ts.map +1 -0
  68. package/dist/runtime-schema.js +225 -0
  69. package/dist/runtime-schema.js.map +1 -0
  70. package/dist/schema-export.d.ts +13 -0
  71. package/dist/schema-export.d.ts.map +1 -0
  72. package/dist/schema-export.js +13 -0
  73. package/dist/schema-export.js.map +1 -0
  74. package/dist/validate-content.d.ts +30 -0
  75. package/dist/validate-content.d.ts.map +1 -0
  76. package/dist/validate-content.js +90 -0
  77. package/dist/validate-content.js.map +1 -0
  78. package/dist/validate-document.d.ts +11 -0
  79. package/dist/validate-document.d.ts.map +1 -0
  80. package/dist/validate-document.js +41 -0
  81. package/dist/validate-document.js.map +1 -0
  82. package/package.json +40 -3
  83. package/README.md +0 -3
@@ -0,0 +1,28 @@
1
+ import { assertAuthorProperty, compileContentContract, defineMetadataArchetype, } from './archetypes.js';
2
+ import { fromPortableJsonSchema } from './portable-schema.js';
3
+ import { mergeSchemas } from './runtime-schema.js';
4
+ /** Runtime additions produce a complete new contract; saved contracts never change. */
5
+ export function resolveCollectionContract(collection, runtime) {
6
+ const metadata = { ...collection.archetype.metadata };
7
+ for (const group of runtime?.metadata ?? []) {
8
+ assertAuthorProperty(group.slot);
9
+ if (Object.hasOwn(metadata, group.slot))
10
+ throw new Error(`Metadata slot "${group.slot}" is already defined`);
11
+ if (group.schema['type'] !== 'object' || !group.schema['properties'])
12
+ throw new Error('Metadata groups require named properties');
13
+ const schema = fromPortableJsonSchema(group.schema);
14
+ metadata[group.slot] = {
15
+ required: group.required,
16
+ archetype: defineMetadataArchetype({
17
+ id: group.id,
18
+ label: group.label,
19
+ schema,
20
+ }),
21
+ };
22
+ }
23
+ for (const field of runtime?.fields ?? [])
24
+ assertAuthorProperty(field.name);
25
+ const archetype = { ...collection.archetype, metadata };
26
+ return compileContentContract(archetype, mergeSchemas(collection.schema, runtime?.fields ?? []));
27
+ }
28
+ //# sourceMappingURL=resolved-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved-contract.js","sourceRoot":"","sources":["../src/resolved-contract.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EAEtB,uBAAuB,GAExB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,uFAAuF;AACvF,MAAM,UAAU,yBAAyB,CACvC,UAAsB,EACtB,OAAuC;IAEvC,MAAM,QAAQ,GAAiC,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAA;IACnF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC5C,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,sBAAsB,CAAC,CAAA;QACrE,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACnD,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;YACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,uBAAuB,CAAC;gBACjC,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM;aACP,CAAC;SACH,CAAA;IACH,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,MAAM,IAAI,EAAE;QAAE,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3E,MAAM,SAAS,GAAsB,EAAE,GAAG,UAAU,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAA;IAC1E,OAAO,sBAAsB,CAAC,SAAS,EAAE,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAA;AAClG,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { RuntimeFieldDefinition } from '@krantho/persistence';
2
+ import type { ZodObject, ZodRawShape, ZodType } from 'zod';
3
+ /**
4
+ * Convert a single runtime field definition to a Zod type.
5
+ * @internal Used only by mergeSchemas()
6
+ */
7
+ export declare function runtimeFieldToZod(field: RuntimeFieldDefinition): ZodType;
8
+ /**
9
+ * Build a Zod object schema from runtime field definitions.
10
+ * @internal Used only by mergeSchemas()
11
+ */
12
+ export declare function runtimeFieldsToZod(fields: RuntimeFieldDefinition[]): ZodObject<ZodRawShape>;
13
+ /**
14
+ * Merge a code-defined Zod schema with runtime field definitions.
15
+ * Code fields take precedence — runtime fields only add new keys.
16
+ * Returns a new schema that validates both code and runtime fields.
17
+ */
18
+ export declare function mergeSchemas(codeSchema: ZodObject<ZodRawShape>, runtimeFields: RuntimeFieldDefinition[]): ZodObject<ZodRawShape>;
19
+ /**
20
+ * Generate Zod code string from code JSON Schema + runtime fields.
21
+ * Used for the "Export" feature in Studio schema editor.
22
+ */
23
+ export declare function exportSchemaAsZod(collectionName: string, codeProperties: Record<string, Record<string, unknown>>, codeRequired: string[], runtimeFields: RuntimeFieldDefinition[]): string;
24
+ //# sourceMappingURL=runtime-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-schema.d.ts","sourceRoot":"","sources":["../src/runtime-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAI1D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAyExE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,CAM3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,CAAC,WAAW,CAAC,EAClC,aAAa,EAAE,sBAAsB,EAAE,GACtC,SAAS,CAAC,WAAW,CAAC,CAexB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvD,YAAY,EAAE,MAAM,EAAE,EACtB,aAAa,EAAE,sBAAsB,EAAE,GACtC,MAAM,CA8BR"}
@@ -0,0 +1,225 @@
1
+ import { z } from 'zod';
2
+ import { retainPortableExtension } from './portable-schema.js';
3
+ /**
4
+ * Convert a single runtime field definition to a Zod type.
5
+ * @internal Used only by mergeSchemas()
6
+ */
7
+ export function runtimeFieldToZod(field) {
8
+ let schema;
9
+ switch (field.type) {
10
+ case 'string':
11
+ case 'textarea': {
12
+ let s = z.string();
13
+ if (field.min !== undefined)
14
+ s = s.min(field.min);
15
+ if (field.max !== undefined)
16
+ s = s.max(field.max);
17
+ if (field.pattern)
18
+ s = s.regex(new RegExp(field.pattern));
19
+ schema = s;
20
+ break;
21
+ }
22
+ case 'number': {
23
+ let n = z.number();
24
+ if (field.min !== undefined)
25
+ n = n.min(field.min);
26
+ if (field.max !== undefined)
27
+ n = n.max(field.max);
28
+ schema = n;
29
+ break;
30
+ }
31
+ case 'boolean':
32
+ schema = z.boolean();
33
+ break;
34
+ case 'date':
35
+ schema = z.union([z.iso.date(), z.iso.datetime({ offset: true })]); // portable ISO date or date-time
36
+ break;
37
+ case 'enum': {
38
+ const values = (field.enumValues ?? []).filter((v) => typeof v === 'string');
39
+ if (values.length < 2) {
40
+ schema = z.string();
41
+ }
42
+ else {
43
+ schema = z.enum(values);
44
+ }
45
+ break;
46
+ }
47
+ case 'url':
48
+ schema = z.string().url();
49
+ break;
50
+ case 'email':
51
+ schema = z.string().email();
52
+ break;
53
+ case 'color':
54
+ schema = z.string();
55
+ break;
56
+ case 'reference':
57
+ schema = z.string();
58
+ if (field.refCollection) {
59
+ schema = z.string().describe(`ref:${field.refCollection}`);
60
+ }
61
+ break;
62
+ default:
63
+ // Development warning — unknown types fall back to string
64
+ console.warn(`[schema] Unknown field type "${field.type}" for "${field.name}", defaulting to string`);
65
+ schema = z.string();
66
+ }
67
+ if (field.isArray)
68
+ schema = z.array(schema);
69
+ if (field.default !== undefined) {
70
+ schema = schema.default(field.default);
71
+ }
72
+ if (!field.required) {
73
+ schema = schema.optional();
74
+ }
75
+ if (field.description && field.type !== 'reference') {
76
+ schema = schema.describe(field.description);
77
+ }
78
+ return schema;
79
+ }
80
+ /**
81
+ * Build a Zod object schema from runtime field definitions.
82
+ * @internal Used only by mergeSchemas()
83
+ */
84
+ export function runtimeFieldsToZod(fields) {
85
+ const shape = {};
86
+ for (const field of fields) {
87
+ shape[field.name] = runtimeFieldToZod(field);
88
+ }
89
+ return z.object(shape);
90
+ }
91
+ /**
92
+ * Merge a code-defined Zod schema with runtime field definitions.
93
+ * Code fields take precedence — runtime fields only add new keys.
94
+ * Returns a new schema that validates both code and runtime fields.
95
+ */
96
+ export function mergeSchemas(codeSchema, runtimeFields) {
97
+ if (runtimeFields.length === 0)
98
+ return codeSchema;
99
+ // Get code-defined field names
100
+ const codeFieldNames = new Set(Object.keys(codeSchema.shape));
101
+ // Only include runtime fields that don't conflict with code
102
+ const newFields = runtimeFields.filter((f) => !codeFieldNames.has(f.name));
103
+ if (newFields.length === 0)
104
+ return codeSchema;
105
+ // Build the runtime-only schema and extend the code schema
106
+ const runtimeZod = runtimeFieldsToZod(newFields);
107
+ const extended = codeSchema.extend(runtimeZod.shape);
108
+ retainPortableExtension(codeSchema, runtimeZod, extended);
109
+ return extended;
110
+ }
111
+ /**
112
+ * Generate Zod code string from code JSON Schema + runtime fields.
113
+ * Used for the "Export" feature in Studio schema editor.
114
+ */
115
+ export function exportSchemaAsZod(collectionName, codeProperties, codeRequired, runtimeFields) {
116
+ const lines = [];
117
+ const requiredSet = new Set(codeRequired);
118
+ lines.push(`const ${collectionName} = defineCollection({`);
119
+ lines.push(` name: '${collectionName}',`);
120
+ lines.push(` source: 'filesystem',`);
121
+ lines.push(` directory: join(process.cwd(), 'content', '${collectionName}'),`);
122
+ lines.push(` schema: z.object({`);
123
+ // Code-defined fields
124
+ if (Object.keys(codeProperties).length > 0) {
125
+ lines.push(` // Code-defined fields`);
126
+ for (const [name, prop] of Object.entries(codeProperties)) {
127
+ lines.push(` '${name}': ${jsonSchemaPropertyToZod(prop, requiredSet.has(name))},`);
128
+ }
129
+ }
130
+ // Runtime fields
131
+ if (runtimeFields.length > 0) {
132
+ lines.push(` // Runtime fields (added via Studio)`);
133
+ for (const field of runtimeFields) {
134
+ lines.push(` '${field.name}': ${runtimeFieldToZodCode(field)},`);
135
+ }
136
+ }
137
+ lines.push(` }),`);
138
+ lines.push(`})`);
139
+ return lines.join('\n');
140
+ }
141
+ /** Shared helper: build the base Zod type code from a type string and constraints */
142
+ function buildZodTypeCode(opts) {
143
+ const { type, enumValues, min, max, pattern, refCollection } = opts;
144
+ if (enumValues && enumValues.length >= 2) {
145
+ return `z.enum([${enumValues.map((v) => `'${v}'`).join(', ')}])`;
146
+ }
147
+ switch (type) {
148
+ case 'number':
149
+ case 'integer': {
150
+ let code = 'z.number()';
151
+ if (min !== undefined)
152
+ code += `.min(${min})`;
153
+ if (max !== undefined)
154
+ code += `.max(${max})`;
155
+ return code;
156
+ }
157
+ case 'boolean':
158
+ return 'z.boolean()';
159
+ case 'url':
160
+ case 'uri':
161
+ return 'z.string().url()';
162
+ case 'email':
163
+ return 'z.string().email()';
164
+ case 'reference':
165
+ return `z.string().describe('ref:${refCollection ?? 'unknown'}')`;
166
+ default: {
167
+ let code = 'z.string()';
168
+ if (min !== undefined)
169
+ code += `.min(${min})`;
170
+ if (max !== undefined)
171
+ code += `.max(${max})`;
172
+ if (pattern)
173
+ code += `.regex(/${pattern}/)`;
174
+ return code;
175
+ }
176
+ }
177
+ }
178
+ /** Append default, description, and optional modifiers to a Zod code string */
179
+ function applyZodModifiers(code, opts) {
180
+ let result = code;
181
+ if (opts.defaultValue !== undefined) {
182
+ result += `.default(${JSON.stringify(opts.defaultValue)})`;
183
+ }
184
+ if (opts.description) {
185
+ result += `.describe('${opts.description}')`;
186
+ }
187
+ if (!opts.isRequired) {
188
+ result += '.optional()';
189
+ }
190
+ return result;
191
+ }
192
+ function jsonSchemaPropertyToZod(prop, isRequired) {
193
+ const type = typeof prop['type'] === 'string' ? prop['type'] : undefined;
194
+ const enumValues = Array.isArray(prop['enum']) && prop['enum'].every((v) => typeof v === 'string')
195
+ ? prop['enum']
196
+ : undefined;
197
+ const format = typeof prop['format'] === 'string' ? prop['format'] : undefined;
198
+ // Map JSON Schema format to our internal type names
199
+ const effectiveType = format === 'email' ? 'email' : format === 'uri' ? 'uri' : (type ?? 'string');
200
+ const code = type === 'array' && prop['items'] && typeof prop['items'] === 'object'
201
+ ? `z.array(${jsonSchemaPropertyToZod(prop['items'], true)})`
202
+ : buildZodTypeCode({ type: effectiveType, enumValues });
203
+ return applyZodModifiers(code, {
204
+ defaultValue: prop['default'],
205
+ isRequired,
206
+ });
207
+ }
208
+ function runtimeFieldToZodCode(field) {
209
+ const baseCode = buildZodTypeCode({
210
+ type: field.type,
211
+ enumValues: field.enumValues,
212
+ min: field.min,
213
+ max: field.max,
214
+ pattern: field.pattern,
215
+ refCollection: field.refCollection,
216
+ });
217
+ const scalarCode = field.type === 'date' ? 'z.union([z.iso.date(), z.iso.datetime({ offset: true })])' : baseCode;
218
+ const code = field.isArray ? `z.array(${scalarCode})` : scalarCode;
219
+ return applyZodModifiers(code, {
220
+ defaultValue: field.default,
221
+ description: field.type !== 'reference' ? field.description : undefined,
222
+ isRequired: field.required ?? false,
223
+ });
224
+ }
225
+ //# sourceMappingURL=runtime-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-schema.js","sourceRoot":"","sources":["../src/runtime-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Collection } from './collection.js';
2
+ /** JSON Schema representation of a collection's frontmatter */
3
+ export interface CollectionJsonSchema {
4
+ name: string;
5
+ source: 'filesystem' | 'database';
6
+ schema: Record<string, unknown>;
7
+ }
8
+ /**
9
+ * Convert a collection's Zod schema to JSON Schema format.
10
+ * Used by Studio to auto-generate form fields.
11
+ */
12
+ export declare function collectionToJsonSchema(collection: Collection): CollectionJsonSchema;
13
+ //# sourceMappingURL=schema-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export.d.ts","sourceRoot":"","sources":["../src/schema-export.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,+DAA+D;AAC/D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,GAAG,UAAU,CAAA;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB,CAMnF"}
@@ -0,0 +1,13 @@
1
+ import { toJSONSchema } from 'zod';
2
+ /**
3
+ * Convert a collection's Zod schema to JSON Schema format.
4
+ * Used by Studio to auto-generate form fields.
5
+ */
6
+ export function collectionToJsonSchema(collection) {
7
+ return {
8
+ name: collection.name,
9
+ source: collection.source,
10
+ schema: toJSONSchema(collection.schema),
11
+ };
12
+ }
13
+ //# sourceMappingURL=schema-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-export.js","sourceRoot":"","sources":["../src/schema-export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAUlC;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAsB;IAC3D,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,MAAM,CAA4B;KACnE,CAAA;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { IPersistenceAdapter } from '@krantho/persistence';
2
+ import type { ZodObject, ZodRawShape } from 'zod';
3
+ import type { Collection } from './collection.js';
4
+ import type { ContentConfig } from './config.js';
5
+ import type { ValidationError, ValidationResult } from './errors.js';
6
+ /**
7
+ * Options for content validation.
8
+ */
9
+ export interface ValidateOptions {
10
+ /** 'strict' throws on first collection with errors, 'warn' collects all errors */
11
+ mode?: 'strict' | 'warn' | undefined;
12
+ }
13
+ /**
14
+ * Validate content fields against a collection's Zod schema.
15
+ *
16
+ * Returns an array of validation errors (empty if valid).
17
+ */
18
+ export declare function validateFields(fields: Record<string, unknown>, collection: Collection<ZodObject<ZodRawShape>>, slug: string): ValidationError[];
19
+ /**
20
+ * Validate all content across all filesystem-mastered collections.
21
+ *
22
+ * Reads each content file via the persistence adapter, parses fields,
23
+ * and validates against the collection's Zod schema.
24
+ *
25
+ * @param config - The project content configuration from defineConfig()
26
+ * @param adapter - A persistence adapter that reads each collection's files
27
+ * @param options - Validation options (mode: 'strict' | 'warn')
28
+ */
29
+ export declare function validateAllContent(config: ContentConfig, adapter: IPersistenceAdapter, options?: ValidateOptions): Promise<ValidationResult>;
30
+ //# sourceMappingURL=validate-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-content.d.ts","sourceRoot":"","sources":["../src/validate-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAE/D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,CAAA;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,EAC9C,IAAI,EAAE,MAAM,GACX,eAAe,EAAE,CAqBnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA0D3B"}
@@ -0,0 +1,90 @@
1
+ import matter from 'gray-matter';
2
+ import { ContentValidationError } from './errors.js';
3
+ /**
4
+ * Validate content fields against a collection's Zod schema.
5
+ *
6
+ * Returns an array of validation errors (empty if valid).
7
+ */
8
+ export function validateFields(fields, collection, slug) {
9
+ const result = collection.schema.safeParse(fields);
10
+ if (result.success) {
11
+ return [];
12
+ }
13
+ const errors = [];
14
+ for (const issue of result.error.issues) {
15
+ const field = issue.path.join('.');
16
+ errors.push({
17
+ collection: collection.name,
18
+ slug,
19
+ field: field || '(root)',
20
+ message: issue.message,
21
+ expected: 'expected' in issue ? String(issue.expected) : 'valid value',
22
+ received: 'received' in issue ? String(issue.received) : 'invalid',
23
+ });
24
+ }
25
+ return errors;
26
+ }
27
+ /**
28
+ * Validate all content across all filesystem-mastered collections.
29
+ *
30
+ * Reads each content file via the persistence adapter, parses fields,
31
+ * and validates against the collection's Zod schema.
32
+ *
33
+ * @param config - The project content configuration from defineConfig()
34
+ * @param adapter - A persistence adapter that reads each collection's files
35
+ * @param options - Validation options (mode: 'strict' | 'warn')
36
+ */
37
+ export async function validateAllContent(config, adapter, options = {}) {
38
+ const mode = options.mode ?? 'strict';
39
+ const allErrors = [];
40
+ let total = 0;
41
+ for (const [, collection] of config.collections) {
42
+ // Only validate filesystem-mastered collections (database validation happens at write time)
43
+ if (collection.source !== 'filesystem')
44
+ continue;
45
+ if (adapter.query) {
46
+ const { items } = await adapter.query({
47
+ state: 'current',
48
+ projection: 'summary',
49
+ collections: [collection.name],
50
+ });
51
+ for (const item of items) {
52
+ total++;
53
+ const errors = validateFields(item.fields, collection, item.meta.slug);
54
+ if (errors.length > 0) {
55
+ allErrors.push(...errors);
56
+ if (mode === 'strict') {
57
+ throw new ContentValidationError(errors);
58
+ }
59
+ }
60
+ }
61
+ }
62
+ else {
63
+ // Fallback: listSlugs + read (no directory scoping)
64
+ const slugs = await adapter.listSlugs();
65
+ for (const slug of slugs) {
66
+ total++;
67
+ const raw = await adapter.read(slug);
68
+ const { data: parsedFrontmatter } = matter(raw);
69
+ const errors = validateFields(parsedFrontmatter, collection, slug);
70
+ if (errors.length > 0) {
71
+ allErrors.push(...errors);
72
+ if (mode === 'strict') {
73
+ throw new ContentValidationError(errors);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ const invalid = new Set(allErrors.map((e) => `${e.collection}/${e.slug}`)).size;
80
+ return {
81
+ valid: allErrors.length === 0,
82
+ errors: allErrors,
83
+ summary: {
84
+ total,
85
+ valid: total - invalid,
86
+ invalid,
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=validate-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-content.js","sourceRoot":"","sources":["../src/validate-content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ContentContract } from '@krantho/persistence';
2
+ import { type ZodType } from 'zod';
3
+ export interface DocumentValues {
4
+ fields: Record<string, unknown>;
5
+ metadata: Record<string, Record<string, unknown>>;
6
+ body: string;
7
+ }
8
+ /** Writes and historic previews use the same portable contract representation. */
9
+ export declare function documentSchema(contract: ContentContract): ZodType<DocumentValues>;
10
+ export declare function validateDocument(contract: ContentContract, values: DocumentValues): ReturnType<ZodType<DocumentValues>['safeParse']>;
11
+ //# sourceMappingURL=validate-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-document.d.ts","sourceRoot":"","sources":["../src/validate-document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAkB,KAAK,OAAO,EAAK,MAAM,KAAK,CAAA;AAErD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACjD,IAAI,EAAE,MAAM,CAAA;CACb;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAiBjF;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,cAAc,GACrB,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,WAAW,CAAC,CAAC,CAElD"}
@@ -0,0 +1,41 @@
1
+ import { normalizeTimestamps } from '@krantho/core';
2
+ import { fromJSONSchema, z } from 'zod';
3
+ /** Writes and historic previews use the same portable contract representation. */
4
+ export function documentSchema(contract) {
5
+ const groups = {};
6
+ for (const [slot, group] of Object.entries(contract.metadata)) {
7
+ const schema = fromJSONSchema(group.schema);
8
+ groups[slot] = group.required ? schema : schema.optional();
9
+ }
10
+ let body = z.string();
11
+ if (contract.body === 'none')
12
+ body = body.max(0, 'This document has no body');
13
+ if (contract.body === 'required')
14
+ body = body.refine((value) => value.trim().length > 0, 'Content is required');
15
+ return z
16
+ .object({
17
+ fields: fromJSONSchema(contract.fields),
18
+ metadata: z.object(groups).strict(),
19
+ body,
20
+ })
21
+ .strict();
22
+ }
23
+ export function validateDocument(contract, values) {
24
+ return documentSchema(contract).safeParse(withUtcTimestamps(contract, values));
25
+ }
26
+ /** A date written alone is midnight UTC, and a time with an offset is the same moment in UTC */
27
+ function withUtcTimestamps(contract, values) {
28
+ const metadata = Object.fromEntries(Object.entries(values.metadata).map(([slot, group]) => {
29
+ const declared = contract.metadata[slot];
30
+ return [
31
+ slot,
32
+ declared ? normalizeTimestamps(declared.schema, group) : group,
33
+ ];
34
+ }));
35
+ return {
36
+ ...values,
37
+ fields: normalizeTimestamps(contract.fields, values.fields),
38
+ metadata,
39
+ };
40
+ }
41
+ //# sourceMappingURL=validate-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-document.js","sourceRoot":"","sources":["../src/validate-document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAwB,MAAM,eAAe,CAAA;AAEzE,OAAO,EAAE,cAAc,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAA;AAQrD,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,MAAM,MAAM,GAA4B,EAAE,CAAA;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC5D,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;IACrB,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM;QAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAA;IAC7E,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU;QAC9B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,qBAAqB,CAAC,CAAA;IAC/E,OAAO,CAAC;SACL,MAAM,CAAC;QACN,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE;QACnC,IAAI;KACL,CAAC;SACD,MAAM,EAA6B,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,QAAyB,EACzB,MAAsB;IAEtB,OAAO,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;AAChF,CAAC;AAED,gGAAgG;AAChG,SAAS,iBAAiB,CAAC,QAAyB,EAAE,MAAsB;IAC1E,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CACjC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACpD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACxC,OAAO;YACL,IAAI;YACJ,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,MAAyB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;SAClF,CAAA;IACH,CAAC,CAAC,CAC2B,CAAA;IAC/B,OAAO;QACL,GAAG,MAAM;QACT,MAAM,EAAE,mBAAmB,CACzB,QAAQ,CAAC,MAAyB,EAClC,MAAM,CAAC,MAAM,CACc;QAC7B,QAAQ;KACT,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
1
  {
2
2
  "name": "@krantho/schema",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "homepage": "https://krantho.com",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/descoped/krantho.git",
9
+ "directory": "packages/schema"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/descoped/krantho/issues"
13
+ },
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "dependencies": {
25
+ "gray-matter": "^4.0.3",
26
+ "@krantho/core": "1.0.0",
27
+ "@krantho/seo-shared": "1.0.0",
28
+ "@krantho/persistence": "1.0.0"
29
+ },
30
+ "peerDependencies": {
31
+ "zod": "^4.4.3"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^25.9.9",
35
+ "typescript": "^6.0.3",
36
+ "zod": "^4.4.3"
37
+ },
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "typecheck": "tsc --noEmit",
41
+ "clean": "rm -rf dist"
42
+ }
6
43
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.