@adminiumjs/manifest 0.3.0-rc.2 → 0.3.0-rc.4

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":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js CHANGED
@@ -167,6 +167,184 @@ export const COLUMN_SEMANTICS = [
167
167
  ];
168
168
  /** Structural role markers. */
169
169
  export const COLUMN_ROLES = ['pk', 'created_at', 'updated_at'];
170
+ /** A snake_case identifier: a table or column ref. */
171
+ const refSchema = z.string().regex(/^[a-z][a-z0-9_]*$/, 'must be a snake_case identifier');
172
+ /** A BCP 47 tag, the way every label map in a manifest is keyed (`de-DE`). */
173
+ const bcp47TagSchema = z.string().regex(/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/, 'keyed by BCP 47 tag');
174
+ /** A label in several languages. US English is the one every reader falls back to. */
175
+ export const labelsSchema = z
176
+ .record(bcp47TagSchema, z.string().min(1).max(120))
177
+ .refine((labels) => labels['en-US'] !== undefined, { message: 'labels must include en-US' });
178
+ /** A text that is either one string, or the same text in several languages. */
179
+ const textOrLabels = z.union([z.string().min(1).max(256), labelsSchema]);
180
+ /**
181
+ * A number the manifest states, or one the app's own settings row holds — so
182
+ * a venue can change its capacity without a new release. `{table, column}`
183
+ * reads the one row of that (one-row) table at write time.
184
+ */
185
+ const numberOrSetting = z.union([
186
+ z.number().int().nonnegative(),
187
+ z.object({ table: refSchema, column: refSchema }).strict(),
188
+ ]);
189
+ /**
190
+ * The rules an app asks Adminium to keep on a column (written as column-rule
191
+ * overrides at install). The first five are the rules an operator can set in
192
+ * the column inspector; the rest are the ones Adminium DECIDES for a public
193
+ * write, so a browser never picks a price, a number or a code:
194
+ *
195
+ * - `copy`: take the value from the linked row (`via` is this table's
196
+ * foreign-key column, `from` a column of the row it points at).
197
+ * - `sequence`: the next number in this column's own counter.
198
+ * - `code`: a short random code (Crockford base 32), unique in the column.
199
+ * - `rollup`: a total over child rows, kept in step as they change.
200
+ * - `venueLocal`: a wall time with no zone is read in the venue's zone.
201
+ * - `personal`: whether the column is personal data, overriding the guess
202
+ * Adminium makes from its name.
203
+ */
204
+ export const columnRulesSchema = z
205
+ .object({
206
+ options: z
207
+ .union([
208
+ z.object({ list: z.string().min(1).max(120) }).strict(),
209
+ z
210
+ .object({
211
+ values: z
212
+ .array(z
213
+ .object({ value: z.string().min(1).max(256), label: textOrLabels.optional(), tone: z.string().max(32).optional() })
214
+ .strict())
215
+ .min(1)
216
+ .max(500),
217
+ })
218
+ .strict(),
219
+ ])
220
+ .optional(),
221
+ enumLabels: z
222
+ .object({
223
+ labels: z.record(z.string().min(1), textOrLabels),
224
+ tones: z.record(z.string().min(1), z.string().max(32)).optional(),
225
+ })
226
+ .strict()
227
+ .optional(),
228
+ required: z.literal(true).optional(),
229
+ validation: z
230
+ .object({
231
+ format: z.enum(['email', 'url', 'phone']).optional(),
232
+ min: z.number().optional(),
233
+ max: z.number().optional(),
234
+ minLength: z.number().int().nonnegative().optional(),
235
+ maxLength: z.number().int().positive().optional(),
236
+ })
237
+ .strict()
238
+ .optional(),
239
+ copy: z
240
+ .object({ via: refSchema, from: refSchema, mode: z.enum(['default', 'always']).optional() })
241
+ .strict()
242
+ .optional(),
243
+ sequence: z.object({ start: z.number().int().min(1).optional() }).strict().optional(),
244
+ code: z
245
+ .object({
246
+ prefix: z.string().regex(/^[A-Z][A-Z0-9]{0,5}-?$/, 'an upper-case prefix, e.g. MR-').optional(),
247
+ length: z.number().int().min(4).max(12),
248
+ })
249
+ .strict()
250
+ .optional(),
251
+ rollup: z
252
+ .object({
253
+ /** The child table, its foreign key back to this row, and what to add up. */
254
+ from: refSchema,
255
+ via: refSchema,
256
+ sum: refSchema,
257
+ /** Multiplied into `sum` per child row, e.g. `qty`. */
258
+ times: refSchema.optional(),
259
+ /** A child row whose column holds a value is left out — a voided line (`voided_at`). */
260
+ unlessSet: refSchema.optional(),
261
+ })
262
+ .strict()
263
+ .optional(),
264
+ venueLocal: z.literal(true).optional(),
265
+ /**
266
+ * Whether the column holds personal data, when the app knows better than
267
+ * a guess from its name: a venue's own `phone` and `address` are a
268
+ * business's, and its guest page may show them. The operator can still
269
+ * mark it otherwise.
270
+ */
271
+ personal: z.boolean().optional(),
272
+ })
273
+ .strict();
274
+ /**
275
+ * A limit on how much of a slot rows may take — the booking guard. Only rows
276
+ * whose `countWhere` column holds one of its values count (a cancelled booking
277
+ * holds no seats).
278
+ */
279
+ export const capacitySchema = z
280
+ .object({
281
+ slot: refSchema,
282
+ amount: refSchema,
283
+ perSlot: numberOrSetting,
284
+ countWhere: z.object({ column: refSchema, values: z.array(z.string().min(1)).min(1) }).strict().optional(),
285
+ slotMinutes: numberOrSetting,
286
+ windowDays: numberOrSetting.optional(),
287
+ opens: z.union([z.string().regex(/^\d{2}:\d{2}$/), z.object({ table: refSchema, column: refSchema }).strict()]).optional(),
288
+ closes: z.union([z.string().regex(/^\d{2}:\d{2}$/), z.object({ table: refSchema, column: refSchema }).strict()]).optional(),
289
+ /** A table, a room: the limit applies per value of this column too. */
290
+ resource: refSchema.optional(),
291
+ /**
292
+ * How many hours before its time a guest may still cancel through the
293
+ * public API; later, only the venue can. Staff are never held to it.
294
+ */
295
+ cancelHours: numberOrSetting.optional(),
296
+ })
297
+ .strict();
298
+ /** The longest `maxLength` a text column may ask for (see `maxLength` below). */
299
+ export const MAX_TEXT_LENGTH = 1000;
300
+ /**
301
+ * Why a column's `default` cannot be created, or `null` when it can.
302
+ *
303
+ * The rules are the ones every one of the three databases can honour with the
304
+ * same meaning, so a manifest that validates installs the same everywhere:
305
+ *
306
+ * - `now` only on a `timestamptz`, and a timestamp takes nothing else. A
307
+ * literal timestamp default is a fixed moment, which is never what a
308
+ * manifest author means.
309
+ * - `text` needs `maxLength`: MySQL gives an unbounded TEXT column no literal
310
+ * default, and a manifest must not install on two engines and fail on the
311
+ * third.
312
+ * - `json`, `blob`, `date`, keys and foreign keys take none.
313
+ * - an enum's default is one of its values, a number is a number, a boolean a
314
+ * boolean.
315
+ */
316
+ export function defaultIssue(c) {
317
+ const value = c.default;
318
+ if (value === undefined)
319
+ return null;
320
+ if (c.role === 'pk')
321
+ return 'a primary key takes no default; an int key numbers itself';
322
+ switch (c.type) {
323
+ case 'timestamptz':
324
+ return value === 'now' ? null : 'a timestamptz default must be "now"';
325
+ case 'text':
326
+ if (typeof value !== 'string')
327
+ return 'a text default must be a string';
328
+ if (c.maxLength === undefined)
329
+ return 'a text default needs maxLength (MySQL gives TEXT no default)';
330
+ return value.length <= c.maxLength ? null : 'the default is longer than maxLength';
331
+ case 'enum':
332
+ return typeof value === 'string' && (c.enum ?? []).includes(value)
333
+ ? null
334
+ : 'an enum default must be one of its values';
335
+ case 'int':
336
+ case 'bigint':
337
+ return typeof value === 'number' && Number.isInteger(value) ? null : 'an integer default must be a whole number';
338
+ case 'decimal':
339
+ case 'money':
340
+ case 'float':
341
+ return typeof value === 'number' ? null : 'a numeric default must be a number';
342
+ case 'bool':
343
+ return typeof value === 'boolean' ? null : 'a bool default must be true or false';
344
+ default:
345
+ return `a ${c.type} column takes no default`;
346
+ }
347
+ }
170
348
  export const requiredColumnSchema = z
171
349
  .object({
172
350
  ref: z.string().regex(/^[a-z][a-z0-9_]*$/, 'column ref must be a snake_case identifier'),
@@ -177,6 +355,33 @@ export const requiredColumnSchema = z
177
355
  // enum values when `type: 'enum'`; fk target ref when `type: 'fk'`.
178
356
  enum: z.array(z.string().min(1)).optional(),
179
357
  references: z.string().optional(),
358
+ /**
359
+ * The value the DATABASE fills when an insert leaves the column out. A
360
+ * literal of the column's own type, or the string `now` on a
361
+ * `timestamptz` column. Without one, a NOT NULL column refuses every insert
362
+ * that omits it — which is every insert an operator makes from a form that
363
+ * does not show that column.
364
+ *
365
+ * Additive and optional: an older server refuses a manifest carrying it
366
+ * (every block is `.strict()`), so an app that uses it raises
367
+ * `minAdminiumVersion` to the release that reads it.
368
+ */
369
+ default: z.union([z.string(), z.number().finite(), z.boolean()]).optional(),
370
+ /**
371
+ * `text` only: a `varchar(n)` instead of unbounded `text`. Short text is
372
+ * what a form, a unique index and MySQL's key limit all want. At most 1000
373
+ * characters — MySQL counts four bytes per character against one 65,535-byte
374
+ * row, so a few long columns would refuse the table.
375
+ */
376
+ maxLength: z.number().int().min(1).max(MAX_TEXT_LENGTH).optional(),
377
+ /** Rules Adminium keeps on the column once installed (see `columnRulesSchema`). */
378
+ rules: columnRulesSchema.optional(),
379
+ /**
380
+ * What a person calls the column — a form's field, a list's heading — in
381
+ * every language the app speaks. Installed as the column's label, which
382
+ * the operator can rename like any other.
383
+ */
384
+ label: textOrLabels.optional(),
180
385
  })
181
386
  .strict()
182
387
  .refine((c) => c.type !== 'enum' || (c.enum !== undefined && c.enum.length > 0), {
@@ -186,17 +391,56 @@ export const requiredColumnSchema = z
186
391
  .refine((c) => c.type !== 'fk' || c.references !== undefined, {
187
392
  message: 'a fk column must name its references target',
188
393
  path: ['references'],
394
+ })
395
+ .refine((c) => c.maxLength === undefined || c.type === 'text', {
396
+ message: 'maxLength applies to a text column only',
397
+ path: ['maxLength'],
398
+ })
399
+ .superRefine((c, ctx) => {
400
+ const issue = defaultIssue(c);
401
+ if (issue !== null)
402
+ ctx.addIssue({ code: 'custom', message: issue, path: ['default'] });
189
403
  });
190
404
  export const requiredTableSchema = z
191
405
  .object({
192
406
  ref: z.string().regex(/^[a-z][a-z0-9_]*$/, 'table ref must be a snake_case identifier'),
193
407
  columns: z.array(requiredColumnSchema).min(1),
408
+ /**
409
+ * A shape other apps may share, `<name>@<version>` (`menu@1`). Two apps
410
+ * that declare the same shape can use one table between them.
411
+ */
412
+ shape: z.string().regex(/^[a-z][a-z0-9-]*@\d+$/, 'a shape is <name>@<version>').optional(),
413
+ capacity: capacitySchema.optional(),
414
+ /**
415
+ * What a person calls ONE row ("Category") and the table ("Categories"),
416
+ * in every language the app speaks: a form's title and button, a page's
417
+ * empty state, a link's field. Installed as the table's label. Without
418
+ * them Adminium names the table from its real name (`pos_menu_categories`).
419
+ */
420
+ label: textOrLabels.optional(),
421
+ labelPlural: textOrLabels.optional(),
422
+ /** The column that names a row wherever another table links to it (a category's `name`). */
423
+ keyField: z.string().regex(/^[a-z][a-z0-9_]*$/, 'a column ref').optional(),
194
424
  })
195
425
  .strict()
196
- .refine((t) => new Set(t.columns.map((c) => c.ref)).size === t.columns.length, { message: 'duplicate column ref in table', path: ['columns'] });
426
+ .refine((t) => new Set(t.columns.map((c) => c.ref)).size === t.columns.length, { message: 'duplicate column ref in table', path: ['columns'] })
427
+ .refine((t) => t.keyField === undefined || t.columns.some((c) => c.ref === t.keyField), {
428
+ message: 'keyField must name one of the table’s columns',
429
+ path: ['keyField'],
430
+ })
431
+ .refine((t) => t.labelPlural === undefined || t.label !== undefined, {
432
+ message: 'labelPlural needs a label',
433
+ path: ['labelPlural'],
434
+ });
197
435
  export const requiredSchemaSchema = z
198
436
  .object({
199
437
  tables: z.array(requiredTableSchema).min(1),
438
+ /**
439
+ * Adminium names every table `<app key>_<ref>` (`pos_tickets`), and tells
440
+ * the app the real names at boot. Opt-in, because an app built before it
441
+ * hard-codes its table names. Apps only: an add-on uses its host's tables.
442
+ */
443
+ prefixed: z.literal(true).optional(),
200
444
  })
201
445
  .strict()
202
446
  .refine((s) => new Set(s.tables.map((t) => t.ref)).size === s.tables.length, {
@@ -220,6 +464,14 @@ export const pageSchema = z
220
464
  // page-local table ref → requiredSchema table ref (resolved at install).
221
465
  bindings: z.record(z.string(), z.string()).optional(),
222
466
  config: z.record(z.string(), z.unknown()).optional(),
467
+ /**
468
+ * The page's title in other languages, keyed by BCP 47 tag (`de-DE`)
469
+ *. `title.fallback` stays the English; the sidebar shows the
470
+ * operator's language until the operator renames the page.
471
+ */
472
+ titles: z
473
+ .record(z.string().regex(/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/, 'titles are keyed by BCP 47 tag'), z.string().min(1).max(120))
474
+ .optional(),
223
475
  })
224
476
  .strict();
225
477
  // ── roles ────────────────────────────────────────────────────────────────────
@@ -230,6 +482,8 @@ export const roleSchema = z
230
482
  cloneFrom: z.string().optional(),
231
483
  // grant strings validated against the RBAC grammar at install time.
232
484
  permissions: z.array(z.string().min(1)).optional(),
485
+ /** Opens the app's own screens and never the dashboard (a till cashier). */
486
+ screensOnly: z.boolean().optional(),
233
487
  })
234
488
  .strict();
235
489
  // ── settings ─────────────────────────────────────────────────────────────────
@@ -334,6 +588,93 @@ export const frontendSchema = z
334
588
  * permanently uncheckable.
335
589
  */
336
590
  routes: z.record(z.string(), z.string()).optional(),
591
+ /**
592
+ * Where a STAFF side opens by default: inside the dashboard, or on its own
593
+ * address (a till). The operator can change it; absent means inside.
594
+ */
595
+ placement: z.enum(['internal', 'external']).optional(),
596
+ /** Whether the side starts switched on. Absent means on. */
597
+ enabled: z.boolean().optional(),
598
+ })
599
+ .strict();
600
+ // ── the app's sidebar, public access and sample data ─────────────────────────
601
+ /** A heading in the app's own sidebar section; pages name it in `nav.group`. */
602
+ /**
603
+ * A list of answers the app ships, for a column's `options: {list}`. Installed
604
+ * as the option list `<appKey>-<name>`, which the operator can then edit like
605
+ * any other; a list of that key they already made is left alone.
606
+ */
607
+ export const optionListSchema = z
608
+ .object({
609
+ label: textOrLabels,
610
+ values: z
611
+ .array(z
612
+ .object({ value: z.string().min(1).max(256), label: textOrLabels.optional(), tone: z.string().max(32).optional() })
613
+ .strict())
614
+ .min(1)
615
+ .max(500),
616
+ })
617
+ .strict();
618
+ export const navGroupSchema = z
619
+ .object({
620
+ key: z.string().regex(/^[a-z][a-z0-9-]*$/, 'a nav group key is kebab-case'),
621
+ label: labelsSchema,
622
+ order: z.number().int(),
623
+ })
624
+ .strict();
625
+ /**
626
+ * What the app's public screens may do with one table, through the one
627
+ * browser key the install creates. `GET` reads, `POST` creates; `PATCH` only
628
+ * behind a claim (a guest changing their own booking), on a narrow writable
629
+ * list. `availability` answers free or full per slot and never a row.
630
+ */
631
+ export const publicAccessSchema = z
632
+ .object({
633
+ table: refSchema,
634
+ kind: z.enum(['records', 'availability']).optional(),
635
+ methods: z.array(z.enum(['GET', 'POST', 'PATCH'])).min(1),
636
+ select: z.array(refSchema).optional(),
637
+ writable: z.array(refSchema).optional(),
638
+ filters: z
639
+ .array(z
640
+ .object({
641
+ column: refSchema,
642
+ op: z.enum(['eq', 'neq', 'in', 'gte', 'lte']),
643
+ value: z.union([z.string(), z.number(), z.boolean(), z.array(z.union([z.string(), z.number()]))]),
644
+ })
645
+ .strict())
646
+ .optional(),
647
+ /** Values the server writes, whatever the browser sends (`status: confirmed`). */
648
+ defaults: z.record(refSchema, z.union([z.string(), z.number(), z.boolean()])).optional(),
649
+ /** Proving you know a row's details, e.g. `{match: [code, mobile]}`. */
650
+ claim: z.object({ match: z.array(refSchema).min(1).max(3) }).strict().optional(),
651
+ /**
652
+ * The confirmation Adminium emails when a guest creates a row here: the
653
+ * column holding their address, the columns the email shows, the app's
654
+ * one-row venue table, and the path under the guest side that manages it.
655
+ */
656
+ confirm: z
657
+ .object({
658
+ template: z.enum(['booking-confirmation']),
659
+ to: refSchema,
660
+ code: refSchema.optional(),
661
+ when: refSchema.optional(),
662
+ party: refSchema.optional(),
663
+ name: refSchema.optional(),
664
+ venue: z
665
+ .object({ table: refSchema, name: refSchema.optional(), address: refSchema.optional(), phone: refSchema.optional() })
666
+ .strict()
667
+ .optional(),
668
+ link: z.string().max(200).optional(),
669
+ })
670
+ .strict()
671
+ .optional(),
672
+ })
673
+ .strict();
674
+ /** The bundled sample data file, inside the package's `seeds/` folder. */
675
+ export const sampleDataSchema = z
676
+ .object({
677
+ file: z.string().regex(/^seeds\/[a-z0-9][a-z0-9._-]*\.json$/, 'a file in seeds/, ending .json'),
337
678
  })
338
679
  .strict();
339
680
  /** Hosted-only and offline-required are mutually exclusive. */
@@ -371,6 +712,146 @@ const SIDES_MESSAGE = {
371
712
  message: 'each side may appear at most once in `frontends`',
372
713
  path: ['frontends'],
373
714
  };
715
+ /** The prefix Adminium gives an app's tables: its key, `-` as `_`, then `_`. */
716
+ export function prefixFor(appKey) {
717
+ return `${appKey.replace(/-/g, '_')}_`;
718
+ }
719
+ /** The longest real table name every engine accepts (Postgres: 63 bytes). */
720
+ export const MAX_TABLE_NAME = 63;
721
+ /**
722
+ * Every name a manifest's own blocks use must name something the manifest
723
+ * declares: a rule's columns, a capacity's columns, a public table and the
724
+ * columns it reads and writes. Checked here so an app's CI refuses a typo long
725
+ * before an operator's install would.
726
+ */
727
+ export function appReferenceIssues(m) {
728
+ const out = [];
729
+ const tables = new Map(m.requiredSchema.tables.map((t) => [t.ref, t]));
730
+ const has = (table, column) => tables.get(table)?.columns.some((c) => c.ref === column) ?? false;
731
+ m.requiredSchema.tables.forEach((table, t) => {
732
+ const at = (...rest) => ['requiredSchema', 'tables', t, ...rest];
733
+ if (m.requiredSchema.prefixed === true && prefixFor(m.key).length + table.ref.length > MAX_TABLE_NAME) {
734
+ out.push({ path: at('ref'), message: `"${prefixFor(m.key)}${table.ref}" is longer than ${String(MAX_TABLE_NAME)} characters` });
735
+ }
736
+ table.columns.forEach((column, c) => {
737
+ const rules = column.rules;
738
+ if (rules === undefined)
739
+ return;
740
+ const here = (...rest) => at('columns', c, 'rules', ...rest);
741
+ // A list the app ships, or one Adminium has built in; nothing else exists
742
+ // on every install.
743
+ if (rules.options !== undefined && 'list' in rules.options) {
744
+ const list = rules.options.list;
745
+ if (!list.startsWith('builtin:') && m.optionLists?.[list] === undefined) {
746
+ out.push({ path: here('options', 'list'), message: `"${list}" is not one of the app's option lists` });
747
+ }
748
+ }
749
+ if (rules.copy !== undefined) {
750
+ const via = table.columns.find((x) => x.ref === rules.copy.via);
751
+ if (via?.type !== 'fk' || via.references === undefined) {
752
+ out.push({ path: here('copy', 'via'), message: `"${rules.copy.via}" is not a foreign key of "${table.ref}"` });
753
+ }
754
+ else if (!has(via.references, rules.copy.from)) {
755
+ out.push({ path: here('copy', 'from'), message: `"${via.references}" has no column "${rules.copy.from}"` });
756
+ }
757
+ }
758
+ if (rules.rollup !== undefined) {
759
+ const r = rules.rollup;
760
+ const child = tables.get(r.from);
761
+ const via = child?.columns.find((x) => x.ref === r.via);
762
+ if (child === undefined) {
763
+ out.push({ path: here('rollup', 'from'), message: `"${r.from}" is not a table of this app` });
764
+ }
765
+ else if (via?.type !== 'fk' || via.references !== table.ref) {
766
+ out.push({ path: here('rollup', 'via'), message: `"${r.from}.${r.via}" does not point at "${table.ref}"` });
767
+ }
768
+ else {
769
+ for (const name of [r.sum, ...(r.times === undefined ? [] : [r.times]), ...(r.unlessSet === undefined ? [] : [r.unlessSet])]) {
770
+ if (!has(r.from, name))
771
+ out.push({ path: here('rollup'), message: `"${r.from}" has no column "${name}"` });
772
+ }
773
+ }
774
+ }
775
+ if ((rules.sequence !== undefined || rules.code !== undefined) && column.role === 'pk') {
776
+ out.push({ path: here(), message: 'a primary key numbers itself; it takes no sequence or code rule' });
777
+ }
778
+ });
779
+ const cap = table.capacity;
780
+ if (cap !== undefined) {
781
+ for (const [name, value] of [['slot', cap.slot], ['amount', cap.amount], ['resource', cap.resource], ['countWhere', cap.countWhere?.column]]) {
782
+ if (value !== undefined && !has(table.ref, value)) {
783
+ out.push({ path: at('capacity', name), message: `"${table.ref}" has no column "${value}"` });
784
+ }
785
+ }
786
+ for (const [name, value] of Object.entries(cap)) {
787
+ if (typeof value === 'object' && value !== null && 'table' in value && 'column' in value) {
788
+ const setting = value;
789
+ if (!has(setting.table, setting.column)) {
790
+ out.push({ path: at('capacity', name), message: `"${setting.table}" has no column "${setting.column}"` });
791
+ }
792
+ }
793
+ }
794
+ }
795
+ });
796
+ (m.publicAccess ?? []).forEach((entry, i) => {
797
+ const at = (...rest) => ['publicAccess', i, ...rest];
798
+ const table = tables.get(entry.table);
799
+ if (table === undefined) {
800
+ out.push({ path: at('table'), message: `"${entry.table}" is not a table of this app` });
801
+ return;
802
+ }
803
+ for (const list of ['select', 'writable']) {
804
+ for (const column of entry[list] ?? []) {
805
+ if (!has(entry.table, column))
806
+ out.push({ path: at(list), message: `"${entry.table}" has no column "${column}"` });
807
+ }
808
+ }
809
+ for (const column of [...(entry.claim?.match ?? []), ...(entry.filters ?? []).map((f) => f.column), ...Object.keys(entry.defaults ?? {})]) {
810
+ if (!has(entry.table, column))
811
+ out.push({ path: at(), message: `"${entry.table}" has no column "${column}"` });
812
+ }
813
+ // A change to an existing row, from a browser, only behind a claim: the
814
+ // guest reaches their own row and nothing else.
815
+ if (entry.methods.includes('PATCH') && entry.claim === undefined) {
816
+ out.push({ path: at('methods'), message: 'PATCH is allowed only with a claim' });
817
+ }
818
+ // Nothing a server decides may be written by a browser.
819
+ for (const column of entry.writable ?? []) {
820
+ const rules = table.columns.find((c) => c.ref === column)?.rules;
821
+ if (rules?.copy !== undefined || rules?.sequence !== undefined || rules?.code !== undefined || rules?.rollup !== undefined) {
822
+ out.push({ path: at('writable'), message: `"${column}" is decided by Adminium and cannot be written publicly` });
823
+ }
824
+ }
825
+ if (entry.confirm !== undefined) {
826
+ const c = entry.confirm;
827
+ for (const [name, column] of [['to', c.to], ['code', c.code], ['when', c.when], ['party', c.party], ['name', c.name]]) {
828
+ if (column !== undefined && !has(entry.table, column))
829
+ out.push({ path: at('confirm', name), message: `"${entry.table}" has no column "${column}"` });
830
+ }
831
+ if (!entry.methods.includes('POST'))
832
+ out.push({ path: at('confirm'), message: 'a confirmation is sent on a create, and this entry creates nothing' });
833
+ if (c.venue !== undefined) {
834
+ if (!tables.has(c.venue.table)) {
835
+ out.push({ path: at('confirm', 'venue', 'table'), message: `"${c.venue.table}" is not a table of this app` });
836
+ }
837
+ else {
838
+ for (const [name, column] of [['name', c.venue.name], ['address', c.venue.address], ['phone', c.venue.phone]]) {
839
+ if (column !== undefined && !has(c.venue.table, column)) {
840
+ out.push({ path: at('confirm', 'venue', name), message: `"${c.venue.table}" has no column "${column}"` });
841
+ }
842
+ }
843
+ }
844
+ }
845
+ }
846
+ if (entry.kind === 'availability') {
847
+ if (table.capacity === undefined)
848
+ out.push({ path: at('kind'), message: `"${entry.table}" declares no capacity to answer from` });
849
+ if (entry.methods.some((method) => method !== 'GET'))
850
+ out.push({ path: at('methods'), message: 'availability is read-only' });
851
+ }
852
+ });
853
+ return out;
854
+ }
374
855
  export const appManifestSchema = z
375
856
  .object({
376
857
  kind: z.literal('app'),
@@ -394,11 +875,21 @@ export const appManifestSchema = z
394
875
  * required-singular shape however their `requiredSchema` was repaired.
395
876
  */
396
877
  frontends: z.array(frontendSchema).min(1),
878
+ navGroups: z.array(navGroupSchema).max(12).optional(),
879
+ /** Keyed by a kebab-case name; a column names one with `options: {list: name}`. */
880
+ optionLists: z.record(z.string().regex(/^[a-z][a-z0-9-]*$/, 'a list name is kebab-case'), optionListSchema).optional(),
881
+ publicAccess: z.array(publicAccessSchema).max(32).optional(),
882
+ sampleData: sampleDataSchema.optional(),
397
883
  })
398
884
  .strict()
399
885
  .refine(capabilitiesNotContradictory, { ...CAPS_MESSAGE, path: [...CAPS_MESSAGE.path] })
400
886
  .refine(compatibilityWindowOrdered, { ...WINDOW_MESSAGE, path: [...WINDOW_MESSAGE.path] })
401
- .refine(sidesAreDistinct, { ...SIDES_MESSAGE, path: [...SIDES_MESSAGE.path] });
887
+ .refine(sidesAreDistinct, { ...SIDES_MESSAGE, path: [...SIDES_MESSAGE.path] })
888
+ .superRefine((m, ctx) => {
889
+ for (const issue of appReferenceIssues(m)) {
890
+ ctx.addIssue({ code: 'custom', message: issue.message, path: issue.path });
891
+ }
892
+ });
402
893
  /**
403
894
  * `pages`, `roles` and `frontends` are absent from this branch on purpose, and
404
895
  * leaving the fields off a `.strict()` schema entirely is a stronger guarantee
@@ -431,7 +922,11 @@ export const addOnManifestSchema = z
431
922
  })
432
923
  .strict()
433
924
  .refine(capabilitiesNotContradictory, { ...CAPS_MESSAGE, path: [...CAPS_MESSAGE.path] })
434
- .refine(compatibilityWindowOrdered, { ...WINDOW_MESSAGE, path: [...WINDOW_MESSAGE.path] });
925
+ .refine(compatibilityWindowOrdered, { ...WINDOW_MESSAGE, path: [...WINDOW_MESSAGE.path] })
926
+ .refine((m) => m.requiredSchema?.prefixed !== true, {
927
+ message: 'an add-on uses its host app\'s tables, so its own cannot be prefixed',
928
+ path: ['requiredSchema', 'prefixed'],
929
+ });
435
930
  /**
436
931
  * The envelope. A document with no `kind` is treated as an app before the union
437
932
  * discriminates, which is what keeps every pre-wave-4 manifest valid.