@beechcms/core 0.4.3 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,IAAI,EACJ,MAAM,EAKN,aAAa,EACb,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAgFnB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAsBtD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAuB5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAkBpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAc1D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAgCxD;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,aAAkB,GAAG,kBAAkB,CAqE5F;AA+GD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;CACd;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE,CAc7D;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAmCrF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CA6BzE"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,IAAI,EACJ,MAAM,EAKN,aAAa,EACb,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAgFnB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAsBtD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAuB5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAkBpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAc1D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAgCxD;AAID;;;;GAIG;AAGH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,aAAkB,GAAG,kBAAkB,CAqE5F;AAgHD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;CACd;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,EAAE,CAc7D;AAID;;;GAGG;AAEH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAmCrF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CA6BzE"}
package/dist/engine.js CHANGED
@@ -212,6 +212,7 @@ export function generateFtsTriggers(seed) {
212
212
  * Never uses json_extract — every column is a real column.
213
213
  * Unknown columns in filters/orderBy are ignored (fail-closed).
214
214
  */
215
+ //TODO: buildSelectQuery ha troppe responsabilità, va suddiviso in più funzioni
215
216
  export function buildSelectQuery(seed, options = {}) {
216
217
  const table = tableName(seed);
217
218
  const { filters = [], orderBy, pagination, status, search, fields } = options;
@@ -278,6 +279,7 @@ export function buildSelectQuery(seed, options = {}) {
278
279
  }
279
280
  return { sql, bindings };
280
281
  }
282
+ //TODO: normalizeFilterValue ha troppe responsabilità, va suddiviso in più funzioni
281
283
  function normalizeFilterValue(type, value) {
282
284
  if (value === null || value === undefined)
283
285
  return null;
@@ -286,7 +288,7 @@ function normalizeFilterValue(type, value) {
286
288
  return value;
287
289
  if (typeof value === 'string' && value.trim() !== '') {
288
290
  const d = new Date(value);
289
- return isNaN(d.getTime()) ? null : Math.floor(d.getTime() / 1000);
291
+ return Number.isNaN(d.getTime()) ? null : Math.floor(d.getTime() / 1000);
290
292
  }
291
293
  return null;
292
294
  }
@@ -298,12 +300,13 @@ function normalizeFilterValue(type, value) {
298
300
  return value;
299
301
  if (typeof value === 'string' && value.trim() !== '') {
300
302
  const n = Number(value);
301
- return isNaN(n) ? null : n;
303
+ return Number.isNaN(n) ? null : n;
302
304
  }
303
305
  return null;
304
306
  }
305
307
  return value;
306
308
  }
309
+ //TODO: buildFilterCondition ha troppe responsabilità, va suddiviso in più funzioni
307
310
  function buildFilterCondition(col, type, cond, bindings) {
308
311
  const { op, value } = cond;
309
312
  if (op === 'is_empty') {
@@ -392,6 +395,7 @@ export function getExpectedColumns(seed) {
392
395
  * Serializes a value for writing to the DB.
393
396
  * boolean → 0/1 | date → Unix timestamp | json/asset-list → JSON string
394
397
  */
398
+ //TODO: serializeForDb ha troppe responsabilità, va suddiviso in più funzioni
395
399
  export function serializeForDb(branch, value) {
396
400
  if (value === null || value === undefined)
397
401
  return null;
@@ -407,7 +411,7 @@ export function serializeForDb(branch, value) {
407
411
  return value;
408
412
  if (typeof value === 'string') {
409
413
  const d = new Date(value);
410
- if (isNaN(d.getTime()))
414
+ if (Number.isNaN(d.getTime()))
411
415
  return null;
412
416
  if (branch.format === 'date') {
413
417
  const midnight = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
package/dist/types.d.ts CHANGED
@@ -1,4 +1,27 @@
1
1
  export type BranchType = 'text' | 'number' | 'boolean' | 'json' | 'date' | 'richtext' | 'file' | 'tags';
2
+ /** Configurazioni specializzate per il tipo di branch 'number' */
3
+ export interface NumberFieldOptions {
4
+ /** Stile di presentazione visiva. Default: 'decimal' */
5
+ format?: 'decimal' | 'currency' | 'percentage' | 'compact';
6
+ /** Codice valuta ISO 4217 (obbligatorio se format === 'currency'). Es. 'EUR', 'USD' */
7
+ currency?: string;
8
+ /** Testo personalizzato da anteporre al valore formattato */
9
+ prefix?: string;
10
+ /** Unità di misura personalizzata da appendere al valore formattato (es. 'kg', 'm²') */
11
+ suffix?: string;
12
+ /** Numero esplicito di cifre decimali da visualizzare e imporre */
13
+ decimals?: number;
14
+ /** Abilita/disabilita il separatore delle migliaia. Default: true */
15
+ grouping?: boolean;
16
+ /** Meccanismo di input alternativo per l'editor delle entità. Default: 'input' */
17
+ control?: 'input' | 'slider' | 'rating' | 'stepper';
18
+ /** Valore minimo consentito */
19
+ min?: number;
20
+ /** Valore massimo consentito */
21
+ max?: number;
22
+ /** Incremento del valore (es. 1 per interi stretti, 0.5 per mezzi passi) */
23
+ step?: number;
24
+ }
2
25
  /** Branch: definizione di una proprietà. alias = nome colonna SQL. */
3
26
  export interface Branch {
4
27
  /** Alias human-readable, usato nel payload API e come nome colonna SQL nella tabella dedicata */
@@ -45,6 +68,8 @@ export interface Branch {
45
68
  /** Il campo è incluso nelle risposte della Public API. Default: true */
46
69
  public?: boolean;
47
70
  };
71
+ /** Opzioni avanzate per i campi numerici. Ignorato se type !== 'number' */
72
+ numberOptions?: NumberFieldOptions;
48
73
  }
49
74
  /** Dashboard-specific config embedded in a Seed. All fields optional — defaults applied by the dashboard. */
50
75
  export interface DashboardSeedConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAqaD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAmH3B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,GAAG,QAAQ,GAAG,WAAW,CAE9F;AAED;;;;;GAKG"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAgkBD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,GAAE,0BAA+B,GACvC,yBAAyB,CAyC3B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,GAAG,QAAQ,GAAG,WAAW,CAE9F;AAED;;;;;GAKG"}
@@ -225,91 +225,130 @@ function requiredAliases(seed, operation) {
225
225
  .filter((branch) => (operation === 'create' ? branch.requiredOnCreate : branch.requiredOnUpdate))
226
226
  .map((branch) => branch.alias);
227
227
  }
228
- function buildBranchSchema(branch, options) {
229
- const nullable = options.allowNull ? z.null() : null;
230
- const preprocessEmpty = (schema) => z.preprocess((val) => (val === '' || val === null ? (options.allowNull ? null : undefined) : val), schema.optional());
231
- switch (branch.type) {
232
- case 'text': {
233
- const schema = stringSchema
234
- .transform((value) => sanitizePlainString(value))
235
- .refine((value) => value.length <= options.maxTextLength, {
236
- message: `Expected string(max:${options.maxTextLength})`,
228
+ function getPreprocessEmpty(allowNull) {
229
+ return (schema) => z.preprocess((val) => (val === '' || val === null ? (allowNull ? null : undefined) : val), schema.optional());
230
+ }
231
+ function buildTextSchema(options, nullable) {
232
+ const schema = stringSchema
233
+ .transform((value) => sanitizePlainString(value))
234
+ .refine((value) => value.length <= options.maxTextLength, {
235
+ message: `Expected string(max:${options.maxTextLength})`,
236
+ });
237
+ return nullable ? z.union([schema, nullable]) : schema;
238
+ }
239
+ function buildRichtextSchema(options, nullable) {
240
+ const schema = z.any().transform((value, ctx) => {
241
+ const sanitized = sanitizeRichtext(value);
242
+ if (!sanitized.valid) {
243
+ ctx.addIssue({
244
+ code: 'custom',
245
+ message: 'Expected richtext-json|string',
246
+ params: { expected: 'richtext-json|string' },
237
247
  });
238
- return nullable ? z.union([schema, nullable]) : schema;
239
248
  }
240
- case 'richtext': {
241
- const schema = z.any().transform((value, ctx) => {
242
- const sanitized = sanitizeRichtext(value);
243
- if (!sanitized.valid) {
244
- ctx.addIssue({
245
- code: 'custom',
246
- message: 'Expected richtext-json|string',
247
- params: { expected: 'richtext-json|string' },
248
- });
249
- }
250
- if (sanitized.size > options.maxTextLength) {
251
- ctx.addIssue({
252
- code: 'custom',
253
- message: `Expected richtext(max:${options.maxTextLength})`,
254
- params: { expected: `richtext(max:${options.maxTextLength})` },
255
- });
256
- }
257
- if (sanitized.dangerous) {
258
- ctx.addIssue({
259
- code: 'custom',
260
- message: 'Dangerous richtext content',
261
- params: { dangerous: true },
262
- });
263
- }
264
- return sanitized.value;
249
+ if (sanitized.size > options.maxTextLength) {
250
+ ctx.addIssue({
251
+ code: 'custom',
252
+ message: `Expected richtext(max:${options.maxTextLength})`,
253
+ params: { expected: `richtext(max:${options.maxTextLength})` },
265
254
  });
266
- return nullable ? z.union([schema, nullable]) : schema;
267
255
  }
268
- case 'number': {
269
- const schema = preprocessEmpty(finiteNumberSchema);
270
- return nullable ? z.union([schema, nullable]) : schema;
256
+ if (sanitized.dangerous) {
257
+ ctx.addIssue({
258
+ code: 'custom',
259
+ message: 'Dangerous richtext content',
260
+ params: { dangerous: true },
261
+ });
271
262
  }
272
- case 'boolean': {
273
- const schema = preprocessEmpty(booleanSchema);
274
- return nullable ? z.union([schema, nullable]) : schema;
263
+ return sanitized.value;
264
+ });
265
+ return nullable ? z.union([schema, nullable]) : schema;
266
+ }
267
+ function buildNumberSchema(branch, allowNull, nullable) {
268
+ const opts = branch.numberOptions;
269
+ const numSchema = z.number();
270
+ const refinedSchema = numSchema.superRefine((val, ctx) => {
271
+ if (!Number.isFinite(val)) {
272
+ ctx.addIssue({ code: 'custom', message: 'Expected finite number' });
273
+ return z.NEVER;
275
274
  }
276
- case 'date': {
277
- const schema = preprocessEmpty(stringSchema
278
- .transform((value) => sanitizePlainString(value))
279
- .refine((value) => isIsoDateString(value), { message: 'Expected date(ISO)' }));
275
+ if (opts?.min !== undefined && val < opts.min) {
276
+ ctx.addIssue({ code: 'custom', message: `Expected number(min:${opts.min})` });
277
+ return z.NEVER;
278
+ }
279
+ if (opts?.max !== undefined && val > opts.max) {
280
+ ctx.addIssue({ code: 'custom', message: `Expected number(max:${opts.max})` });
281
+ return z.NEVER;
282
+ }
283
+ if (opts?.step !== undefined) {
284
+ const step = opts.step;
285
+ const min = opts.min ?? 0;
286
+ const valDecimals = (val.toString().split('.')[1] || '').length;
287
+ const stepDecimals = (step.toString().split('.')[1] || '').length;
288
+ const decimals = Math.max(valDecimals, stepDecimals);
289
+ const multiplier = Math.pow(10, decimals);
290
+ if ((Math.round((val - min) * multiplier) % Math.round(step * multiplier)) !== 0) {
291
+ ctx.addIssue({ code: 'custom', message: `Expected number(step:${step})` });
292
+ }
293
+ }
294
+ });
295
+ const schema = getPreprocessEmpty(allowNull)(refinedSchema);
296
+ return nullable ? z.union([schema, nullable]) : schema;
297
+ }
298
+ function buildDateSchema(allowNull, nullable) {
299
+ const schema = getPreprocessEmpty(allowNull)(stringSchema
300
+ .transform((value) => sanitizePlainString(value))
301
+ .refine((value) => isIsoDateString(value), { message: 'Expected date(ISO)' }));
302
+ return nullable ? z.union([schema, nullable]) : schema;
303
+ }
304
+ function buildFileSchema(branch, allowNull, nullable) {
305
+ if (isAssetListBranch(branch)) {
306
+ const schema = getPreprocessEmpty(allowNull)(z.any()
307
+ .transform((rawValue, ctx) => {
308
+ const normalized = normalizeAssetListValue(rawValue);
309
+ if (!normalized) {
310
+ ctx.addIssue({ code: 'custom', message: 'Expected url-string[]' });
311
+ return z.NEVER;
312
+ }
313
+ return normalized;
314
+ })
315
+ .pipe(z.array(z.string().url())));
316
+ return nullable ? z.union([schema, nullable]) : schema;
317
+ }
318
+ const schema = getPreprocessEmpty(allowNull)(z.any()
319
+ .transform((rawValue, ctx) => {
320
+ const normalized = normalizeHttpUrl(rawValue);
321
+ if (!normalized) {
322
+ ctx.addIssue({ code: 'custom', message: 'Expected url-string' });
323
+ return z.NEVER;
324
+ }
325
+ return normalized;
326
+ })
327
+ .pipe(z.string().url()));
328
+ return nullable ? z.union([schema, nullable]) : schema;
329
+ }
330
+ function buildBranchSchema(branch, options) {
331
+ const nullable = options.allowNull ? z.null() : null;
332
+ switch (branch.type) {
333
+ case 'text':
334
+ return buildTextSchema(options, nullable);
335
+ case 'richtext':
336
+ return buildRichtextSchema(options, nullable);
337
+ case 'number':
338
+ return buildNumberSchema(branch, options.allowNull, nullable);
339
+ case 'boolean': {
340
+ const schema = getPreprocessEmpty(options.allowNull)(booleanSchema);
280
341
  return nullable ? z.union([schema, nullable]) : schema;
281
342
  }
343
+ case 'date':
344
+ return buildDateSchema(options.allowNull, nullable);
282
345
  case 'json':
283
346
  case 'tags': {
284
- const schema = preprocessEmpty(jsonObjectOrArraySchema);
285
- return nullable ? z.union([schema, nullable]) : schema;
286
- }
287
- case 'file': {
288
- if (isAssetListBranch(branch)) {
289
- const schema = preprocessEmpty(z.any()
290
- .transform((rawValue, ctx) => {
291
- const normalized = normalizeAssetListValue(rawValue);
292
- if (!normalized) {
293
- ctx.addIssue({ code: 'custom', message: 'Expected url-string[]' });
294
- return z.NEVER;
295
- }
296
- return normalized;
297
- })
298
- .pipe(z.array(z.string().url())));
299
- return nullable ? z.union([schema, nullable]) : schema;
300
- }
301
- const schema = preprocessEmpty(z.any()
302
- .transform((rawValue, ctx) => {
303
- const normalized = normalizeHttpUrl(rawValue);
304
- if (!normalized) {
305
- ctx.addIssue({ code: 'custom', message: 'Expected url-string' });
306
- return z.NEVER;
307
- }
308
- return normalized;
309
- })
310
- .pipe(z.string().url()));
347
+ const schema = getPreprocessEmpty(options.allowNull)(jsonObjectOrArraySchema);
311
348
  return nullable ? z.union([schema, nullable]) : schema;
312
349
  }
350
+ case 'file':
351
+ return buildFileSchema(branch, options.allowNull, nullable);
313
352
  default:
314
353
  throw new Error(`Unhandled branch type: ${branch.type}`);
315
354
  }
@@ -325,6 +364,7 @@ function seedFingerprint(seed) {
325
364
  multiple: branch.multiple ?? false,
326
365
  requiredOnCreate: branch.requiredOnCreate ?? false,
327
366
  requiredOnUpdate: branch.requiredOnUpdate ?? false,
367
+ numberOptions: branch.numberOptions ?? null,
328
368
  })),
329
369
  });
330
370
  }
@@ -370,29 +410,9 @@ function isIsoDateString(value) {
370
410
  const d = new Date(parsed);
371
411
  return d.toISOString().startsWith(value.substring(0, 10));
372
412
  }
373
- /**
374
- * Common foundation for schema-driven validation and sanitization of payloads.
375
- * Used by the Public API and reusable in the Botanical Engine.
376
- *
377
- * Mandatory execution order at the time of writing:
378
- * validate raw → hash (privacy policy) → store
379
- * Hashing occurs AFTER validation, not before.
380
- * This ensures that the validated value is the original raw value,
381
- * not the digest — avoiding false failures on fields with formats (e.g., email).
382
- */
383
- export function validateAndSanitizeSeedPayload(seed, payload, options = {}) {
384
- const normalizedOptions = {
385
- allowNull: options.allowNull ?? false,
386
- operation: options.operation ?? 'create',
387
- requireAtLeastOneValidField: options.requireAtLeastOneValidField ?? true,
388
- enforceRequiredFields: options.enforceRequiredFields ?? true,
389
- maxTextLength: options.maxTextLength ?? DEFAULT_MAX_TEXT_LENGTH,
390
- };
391
- const details = [];
392
- const data = {};
413
+ function filterPayloadAliases(seed, payload) {
393
414
  const unknownAliases = [];
394
- const dangerousFields = [];
395
- const requiredFieldsMissing = [];
415
+ const details = [];
396
416
  const allowedAliases = new Set(seed.branches.map((branch) => branch.alias));
397
417
  const filteredPayload = {};
398
418
  for (const [alias, rawValue] of Object.entries(payload)) {
@@ -408,67 +428,100 @@ export function validateAndSanitizeSeedPayload(seed, payload, options = {}) {
408
428
  }
409
429
  filteredPayload[alias] = rawValue;
410
430
  }
411
- const schema = compileSeedSchema(seed, normalizedOptions);
412
- const parsed = schema.safeParse(filteredPayload);
413
- if (parsed.success) {
414
- Object.assign(data, parsed.data);
415
- }
416
- else {
417
- for (const issue of parsed.error.issues) {
418
- if (issue.code === 'unrecognized_keys') {
419
- for (const alias of issue.keys) {
420
- unknownAliases.push(alias);
421
- details.push({
422
- field: alias,
423
- expected: 'known-seed-alias',
424
- received: 'unknown-alias',
425
- message: `Field '${alias}' is not defined in seed '${seed.slug}'`,
426
- });
427
- }
428
- continue;
429
- }
430
- if (issue.message === 'Required' && normalizedOptions.enforceRequiredFields) {
431
- continue; // Let enforceRequiredFields logic below handle it properly with detailed messages
432
- }
433
- const field = String(issue.path[0] ?? 'payload');
434
- const receivedValue = filteredPayload[field];
435
- const expected = typeof issue.message === 'string' && issue.message.startsWith('Expected ')
436
- ? issue.message.replace('Expected ', '')
437
- : 'valid-field-value';
438
- if (issue.params?.dangerous === true) {
439
- dangerousFields.push(field);
440
- }
441
- details.push(makeDetail(field, expected, receivedValue));
442
- }
443
- }
444
- if (normalizedOptions.enforceRequiredFields) {
445
- for (const branch of seed.branches) {
446
- const isRequired = normalizedOptions.operation === 'create' ? branch.requiredOnCreate : branch.requiredOnUpdate;
447
- if (!isRequired)
448
- continue;
449
- const hasProvidedAlias = Object.hasOwn(payload, branch.alias);
450
- if (!hasProvidedAlias) {
451
- requiredFieldsMissing.push(branch.alias);
452
- details.push({
453
- field: branch.alias,
454
- expected: 'required-field',
455
- received: 'missing',
456
- message: `Field '${branch.alias}' is required for ${normalizedOptions.operation}`,
457
- });
458
- continue;
459
- }
460
- const valueToCheck = parsed.success ? data[branch.alias] : filteredPayload[branch.alias];
461
- if (isMissingRequiredValue(valueToCheck)) {
462
- requiredFieldsMissing.push(branch.alias);
431
+ return { filteredPayload, unknownAliases, unknownDetails: details };
432
+ }
433
+ function collectZodIssueDetails(seed, issues, filteredPayload, normalizedOptions) {
434
+ const unknownAliases = [];
435
+ const details = [];
436
+ const dangerousFields = [];
437
+ for (const issue of issues) {
438
+ if (issue.code === 'unrecognized_keys') {
439
+ for (const alias of issue.keys) {
440
+ unknownAliases.push(alias);
463
441
  details.push({
464
- field: branch.alias,
465
- expected: 'required-field',
466
- received: 'empty',
467
- message: `Field '${branch.alias}' cannot be empty for ${normalizedOptions.operation}`,
442
+ field: alias,
443
+ expected: 'known-seed-alias',
444
+ received: 'unknown-alias',
445
+ message: `Field '${alias}' is not defined in seed '${seed.slug}'`,
468
446
  });
469
447
  }
448
+ continue;
449
+ }
450
+ if (issue.message === 'Required' && normalizedOptions.enforceRequiredFields) {
451
+ continue; // Let enforceRequiredFields logic handle it properly
452
+ }
453
+ const field = String(issue.path[0] ?? 'payload');
454
+ const receivedValue = filteredPayload[field];
455
+ const expected = typeof issue.message === 'string' && issue.message.startsWith('Expected ')
456
+ ? issue.message.replace('Expected ', '')
457
+ : 'valid-field-value';
458
+ if (issue.params?.dangerous === true) {
459
+ dangerousFields.push(field);
460
+ }
461
+ details.push(makeDetail(field, expected, receivedValue));
462
+ }
463
+ return { unknownAliases, zodDetails: details, dangerousFields };
464
+ }
465
+ function enforceRequiredFields(seed, payload, filteredPayload, data, isSuccess, normalizedOptions) {
466
+ const requiredFieldsMissing = [];
467
+ const details = [];
468
+ for (const branch of seed.branches) {
469
+ const isRequired = normalizedOptions.operation === 'create' ? branch.requiredOnCreate : branch.requiredOnUpdate;
470
+ if (!isRequired)
471
+ continue;
472
+ const hasProvidedAlias = Object.hasOwn(payload, branch.alias);
473
+ if (!hasProvidedAlias) {
474
+ requiredFieldsMissing.push(branch.alias);
475
+ details.push({
476
+ field: branch.alias,
477
+ expected: 'required-field',
478
+ received: 'missing',
479
+ message: `Field '${branch.alias}' is required for ${normalizedOptions.operation}`,
480
+ });
481
+ continue;
482
+ }
483
+ const valueToCheck = isSuccess ? data[branch.alias] : filteredPayload[branch.alias];
484
+ if (isMissingRequiredValue(valueToCheck)) {
485
+ requiredFieldsMissing.push(branch.alias);
486
+ details.push({
487
+ field: branch.alias,
488
+ expected: 'required-field',
489
+ received: 'empty',
490
+ message: `Field '${branch.alias}' cannot be empty for ${normalizedOptions.operation}`,
491
+ });
470
492
  }
471
493
  }
494
+ return { requiredFieldsMissing, requiredDetails: details };
495
+ }
496
+ /**
497
+ * Common foundation for schema-driven validation and sanitization of payloads.
498
+ * Used by the Public API and reusable in the Botanical Engine.
499
+ *
500
+ * Mandatory execution order at the time of writing:
501
+ * validate raw → hash (privacy policy) → store
502
+ * Hashing occurs AFTER validation, not before.
503
+ * This ensures that the validated value is the original raw value,
504
+ * not the digest — avoiding false failures on fields with formats (e.g., email).
505
+ */
506
+ export function validateAndSanitizeSeedPayload(seed, payload, options = {}) {
507
+ const normalizedOptions = {
508
+ allowNull: options.allowNull ?? false,
509
+ operation: options.operation ?? 'create',
510
+ requireAtLeastOneValidField: options.requireAtLeastOneValidField ?? true,
511
+ enforceRequiredFields: options.enforceRequiredFields ?? true,
512
+ maxTextLength: options.maxTextLength ?? DEFAULT_MAX_TEXT_LENGTH,
513
+ };
514
+ const { filteredPayload, unknownAliases: initialUnknown, unknownDetails } = filterPayloadAliases(seed, payload);
515
+ const schema = compileSeedSchema(seed, normalizedOptions);
516
+ const parsed = schema.safeParse(filteredPayload);
517
+ const data = parsed.success ? { ...parsed.data } : {};
518
+ const { unknownAliases: zodUnknown, zodDetails, dangerousFields } = parsed.success
519
+ ? { unknownAliases: [], zodDetails: [], dangerousFields: [] }
520
+ : collectZodIssueDetails(seed, parsed.error.issues, filteredPayload, normalizedOptions);
521
+ const { requiredFieldsMissing, requiredDetails } = normalizedOptions.enforceRequiredFields
522
+ ? enforceRequiredFields(seed, payload, filteredPayload, data, parsed.success, normalizedOptions)
523
+ : { requiredFieldsMissing: [], requiredDetails: [] };
524
+ const details = [...unknownDetails, ...zodDetails, ...requiredDetails];
472
525
  if (normalizedOptions.requireAtLeastOneValidField && Object.keys(data).length === 0) {
473
526
  details.push({
474
527
  field: 'data',
@@ -480,7 +533,7 @@ export function validateAndSanitizeSeedPayload(seed, payload, options = {}) {
480
533
  return {
481
534
  data,
482
535
  details,
483
- unknownAliases: [...new Set(unknownAliases)],
536
+ unknownAliases: [...new Set([...initialUnknown, ...zodUnknown])],
484
537
  dangerousFields: [...new Set(dangerousFields)],
485
538
  requiredFieldsMissing,
486
539
  hasAnyValidField: Object.keys(data).length > 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beechcms/core",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",