@adminiumjs/engine 0.1.0-rc.1

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 (94) hide show
  1. package/LICENSE +661 -0
  2. package/dist/adapter-registry.d.ts +62 -0
  3. package/dist/adapter-registry.d.ts.map +1 -0
  4. package/dist/adapter-registry.js +75 -0
  5. package/dist/adapter-registry.js.map +1 -0
  6. package/dist/adapter.d.ts +384 -0
  7. package/dist/adapter.d.ts.map +1 -0
  8. package/dist/adapter.js +54 -0
  9. package/dist/adapter.js.map +1 -0
  10. package/dist/capabilities.d.ts +57 -0
  11. package/dist/capabilities.d.ts.map +1 -0
  12. package/dist/capabilities.js +131 -0
  13. package/dist/capabilities.js.map +1 -0
  14. package/dist/classify/columns.d.ts +57 -0
  15. package/dist/classify/columns.d.ts.map +1 -0
  16. package/dist/classify/columns.js +535 -0
  17. package/dist/classify/columns.js.map +1 -0
  18. package/dist/classify/index.d.ts +29 -0
  19. package/dist/classify/index.d.ts.map +1 -0
  20. package/dist/classify/index.js +44 -0
  21. package/dist/classify/index.js.map +1 -0
  22. package/dist/classify/names.d.ts +11 -0
  23. package/dist/classify/names.d.ts.map +1 -0
  24. package/dist/classify/names.js +19 -0
  25. package/dist/classify/names.js.map +1 -0
  26. package/dist/classify/pii.d.ts +29 -0
  27. package/dist/classify/pii.d.ts.map +1 -0
  28. package/dist/classify/pii.js +55 -0
  29. package/dist/classify/pii.js.map +1 -0
  30. package/dist/classify/tables.d.ts +64 -0
  31. package/dist/classify/tables.d.ts.map +1 -0
  32. package/dist/classify/tables.js +303 -0
  33. package/dist/classify/tables.js.map +1 -0
  34. package/dist/config-schema/envelope.d.ts +83 -0
  35. package/dist/config-schema/envelope.d.ts.map +1 -0
  36. package/dist/config-schema/envelope.js +87 -0
  37. package/dist/config-schema/envelope.js.map +1 -0
  38. package/dist/config-schema/index.d.ts +14 -0
  39. package/dist/config-schema/index.d.ts.map +1 -0
  40. package/dist/config-schema/index.js +15 -0
  41. package/dist/config-schema/index.js.map +1 -0
  42. package/dist/config-schema/migrations.d.ts +44 -0
  43. package/dist/config-schema/migrations.d.ts.map +1 -0
  44. package/dist/config-schema/migrations.js +62 -0
  45. package/dist/config-schema/migrations.js.map +1 -0
  46. package/dist/generate/archetype.d.ts +76 -0
  47. package/dist/generate/archetype.d.ts.map +1 -0
  48. package/dist/generate/archetype.js +250 -0
  49. package/dist/generate/archetype.js.map +1 -0
  50. package/dist/generate/crud.d.ts +36 -0
  51. package/dist/generate/crud.d.ts.map +1 -0
  52. package/dist/generate/crud.js +45 -0
  53. package/dist/generate/crud.js.map +1 -0
  54. package/dist/generate/dashboard.d.ts +43 -0
  55. package/dist/generate/dashboard.d.ts.map +1 -0
  56. package/dist/generate/dashboard.js +61 -0
  57. package/dist/generate/dashboard.js.map +1 -0
  58. package/dist/generate/domains.d.ts +29 -0
  59. package/dist/generate/domains.d.ts.map +1 -0
  60. package/dist/generate/domains.js +145 -0
  61. package/dist/generate/domains.js.map +1 -0
  62. package/dist/generate/index.d.ts +78 -0
  63. package/dist/generate/index.d.ts.map +1 -0
  64. package/dist/generate/index.js +301 -0
  65. package/dist/generate/index.js.map +1 -0
  66. package/dist/generate/util.d.ts +46 -0
  67. package/dist/generate/util.d.ts.map +1 -0
  68. package/dist/generate/util.js +123 -0
  69. package/dist/generate/util.js.map +1 -0
  70. package/dist/index.d.ts +8 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +8 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/schema-model.d.ts +1853 -0
  75. package/dist/schema-model.d.ts.map +1 -0
  76. package/dist/schema-model.js +463 -0
  77. package/dist/schema-model.js.map +1 -0
  78. package/dist/snapshot/diff.d.ts +258 -0
  79. package/dist/snapshot/diff.d.ts.map +1 -0
  80. package/dist/snapshot/diff.js +151 -0
  81. package/dist/snapshot/diff.js.map +1 -0
  82. package/dist/snapshot/hash.d.ts +23 -0
  83. package/dist/snapshot/hash.d.ts.map +1 -0
  84. package/dist/snapshot/hash.js +47 -0
  85. package/dist/snapshot/hash.js.map +1 -0
  86. package/dist/snapshot/index.d.ts +28 -0
  87. package/dist/snapshot/index.d.ts.map +1 -0
  88. package/dist/snapshot/index.js +26 -0
  89. package/dist/snapshot/index.js.map +1 -0
  90. package/dist/snapshot/sha256.d.ts +14 -0
  91. package/dist/snapshot/sha256.d.ts.map +1 -0
  92. package/dist/snapshot/sha256.js +99 -0
  93. package/dist/snapshot/sha256.js.map +1 -0
  94. package/package.json +37 -0
@@ -0,0 +1,87 @@
1
+ import { layoutItemSchema, pageLayoutSchema, queryDescriptorSchema } from '@adminium/widgets/page-config';
2
+ import { z } from 'zod';
3
+ /**
4
+ * The config envelope every stored config document uses (01-architecture.md
5
+ * §6.1, 07-meta-store.md §3.17). The envelope persists verbatim into
6
+ * `adminium_pages.config`; the stored version path the config-migration
7
+ * runner keys on is `config.v`.
8
+ */
9
+ export const CONFIG_KINDS = ['page', 'dashboard', 'view', 'nav', 'manifest-module'];
10
+ export const configKindSchema = z.enum(CONFIG_KINDS);
11
+ /**
12
+ * Prefixed document id: `page_`/`view_`/`nav_` + slug or ULID suffix.
13
+ * Engine-generated ids carry ULID suffixes (`page_01HZX…`); hand-authored and
14
+ * seeded documents may use readable slugs (`page_customers`, per the §3.17
15
+ * examples), so the suffix alphabet is not restricted to Crockford base32.
16
+ */
17
+ export const configIdPattern = /^(page|view|nav)_[A-Za-z0-9][A-Za-z0-9_-]*$/;
18
+ const kebabCasePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
19
+ /** Nav placement block (01-architecture.md §6.1). */
20
+ export const navConfigSchema = z.object({
21
+ group: z.string().min(1),
22
+ icon: z.string().min(1), // lucide-react icon name
23
+ order: z.number().int(),
24
+ slug: z.string().regex(kebabCasePattern, 'must be kebab-case').optional(),
25
+ badge: z.string().min(1).optional(),
26
+ });
27
+ const envelopeShape = z.object({
28
+ v: z.literal(1), // config schema version (integer, 01-architecture.md §8.2)
29
+ kind: configKindSchema,
30
+ id: z
31
+ .string()
32
+ .regex(configIdPattern, 'must be a prefixed document id (page_* / view_* / nav_*)'),
33
+ template: z.string().regex(kebabCasePattern, 'must be a kebab-case Registry id'),
34
+ title: z.object({ key: z.string().min(1), fallback: z.string().min(1) }),
35
+ // Data-scope defaults for widgets/bindings on this page.
36
+ source: z.object({
37
+ connectionId: z.string().nullable(),
38
+ table: z.string().nullable(), // "public.orders" — primary table for record pages
39
+ }),
40
+ nav: navConfigSchema,
41
+ access: z.object({ minRole: z.string().min(1), permissions: z.array(z.string()) }),
42
+ // Per-template body. Unknown fields are preserved on round-trip
43
+ // (forward compatibility, 01-architecture.md §6.2); per-template schemas
44
+ // live in @adminium/widgets/page-config and are applied by kind below.
45
+ // `config.templateVersion` (stamped by composeTemplate from the manifest) is
46
+ // ADVISORY-ONLY until the 04-T15 per-template migrations/ mechanism lands:
47
+ // nothing validates or migrates on it — the migration chain keys solely on
48
+ // the envelope `v` above, and stored pre-stamp documents render fine because
49
+ // layouts are self-contained. 04 §10's "version bumps let H5 migrate old
50
+ // configs deliberately" gets its enforcement surface with 04-T15.
51
+ config: z.record(z.string(), z.unknown()),
52
+ });
53
+ export const pageEnvelopeSchema = envelopeShape.superRefine((doc, ctx) => {
54
+ if (doc.kind !== 'dashboard')
55
+ return;
56
+ const layout = pageLayoutSchema.safeParse(doc.config['layout']);
57
+ if (layout.success)
58
+ return;
59
+ for (const issue of layout.error.issues) {
60
+ ctx.addIssue({
61
+ code: 'custom',
62
+ message: issue.message,
63
+ path: ['config', 'layout', ...issue.path],
64
+ });
65
+ }
66
+ });
67
+ /**
68
+ * A validated dashboard widget instance (01-architecture.md §6.1): a grid
69
+ * layout item whose `config.binding`, when present, must be a declarative
70
+ * query descriptor (04-widget-registry.md §5.1).
71
+ */
72
+ export const widgetConfigSchema = layoutItemSchema.superRefine((item, ctx) => {
73
+ const binding = item.config['binding'];
74
+ if (binding === undefined)
75
+ return;
76
+ const descriptor = queryDescriptorSchema.safeParse(binding);
77
+ if (descriptor.success)
78
+ return;
79
+ for (const issue of descriptor.error.issues) {
80
+ ctx.addIssue({
81
+ code: 'custom',
82
+ message: issue.message,
83
+ path: ['config', 'binding', ...issue.path],
84
+ });
85
+ }
86
+ });
87
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/config-schema/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @adminium/engine/config — browser-safe subpath.
3
+ *
4
+ * The single validation authority for stored config documents: the envelope
5
+ * schema, nav/widget schemas, and the config-migration runner. Also
6
+ * re-exports the `@adminium/widgets/page-config` pure-Zod leaf so consumers
7
+ * (dashboard, manifest, server routes) have one import surface
8
+ * (07-meta-store.md §3.17). No node: imports anywhere in this directory —
9
+ * enforced by test/browser-safe.test.ts and the dependency-cruiser gate.
10
+ */
11
+ export { CONFIG_KINDS, configIdPattern, configKindSchema, navConfigSchema, pageEnvelopeSchema, widgetConfigSchema, type ConfigKind, type NavConfig, type PageConfig, type PageEnvelope, type WidgetConfig, } from './envelope.js';
12
+ export { CONFIG_VERSION, ConfigMigrationError, configMigrations, latestConfigVersion, runConfigMigrations, type ConfigDocument, type ConfigMigration, } from './migrations.js';
13
+ export { DATA_SHAPES, aggregationSchema, bucketUnitSchema, dataShapeSchema, filterSchema, layoutItemSchema, pageLayoutSchema, queryDescriptorSchema, type Aggregation, type BucketUnit, type DataShape, type LayoutItem, type PageLayout, type QueryDescriptor, type QueryFilter, } from '@adminium/widgets/page-config';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config-schema/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @adminium/engine/config — browser-safe subpath.
3
+ *
4
+ * The single validation authority for stored config documents: the envelope
5
+ * schema, nav/widget schemas, and the config-migration runner. Also
6
+ * re-exports the `@adminium/widgets/page-config` pure-Zod leaf so consumers
7
+ * (dashboard, manifest, server routes) have one import surface
8
+ * (07-meta-store.md §3.17). No node: imports anywhere in this directory —
9
+ * enforced by test/browser-safe.test.ts and the dependency-cruiser gate.
10
+ */
11
+ export { CONFIG_KINDS, configIdPattern, configKindSchema, navConfigSchema, pageEnvelopeSchema, widgetConfigSchema, } from './envelope.js';
12
+ export { CONFIG_VERSION, ConfigMigrationError, configMigrations, latestConfigVersion, runConfigMigrations, } from './migrations.js';
13
+ // Assembled surface: the per-template leaf schemas (04-widget-registry.md §5.1, §6.1).
14
+ export { DATA_SHAPES, aggregationSchema, bucketUnitSchema, dataShapeSchema, filterSchema, layoutItemSchema, pageLayoutSchema, queryDescriptorSchema, } from '@adminium/widgets/page-config';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config-schema/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,GAMnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,iBAAiB,CAAC;AACzB,uFAAuF;AACvF,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,GAQtB,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Config-migration runner (01-architecture.md §8.2).
3
+ *
4
+ * Each migration is a pure function `(doc) => doc` upgrading one version
5
+ * step. The server runs the chain at boot and lazily on read; zip import
6
+ * replays the same path so old exports always upgrade, never silently drop.
7
+ *
8
+ * Browser-safe: no node: imports (this module ships in
9
+ * `@adminium/engine/config`).
10
+ */
11
+ /** A stored config document: the envelope with its integer version at `v`. */
12
+ export interface ConfigDocument {
13
+ v: number;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface ConfigMigration {
17
+ /** Version this migration upgrades from. */
18
+ readonly from: number;
19
+ /** Version this migration produces (`from + 1` by convention). */
20
+ readonly to: number;
21
+ /** Pure upgrade function; must not rely on mutating its input. */
22
+ migrate(doc: ConfigDocument): ConfigDocument;
23
+ }
24
+ /** The current (latest) config schema version shipped with this build. */
25
+ export declare const CONFIG_VERSION = 1;
26
+ /**
27
+ * Registered migrations, ordered by `from`. Empty while v1 is current; the
28
+ * first real entry arrives with the v1→v2 bump.
29
+ */
30
+ export declare const configMigrations: readonly ConfigMigration[];
31
+ export declare class ConfigMigrationError extends Error {
32
+ readonly name = "ConfigMigrationError";
33
+ }
34
+ /** Latest version reachable through `migrations` (>= CONFIG_VERSION). */
35
+ export declare function latestConfigVersion(migrations?: readonly ConfigMigration[]): number;
36
+ /**
37
+ * Upgrades `doc.v` to the latest version by running the migration chain.
38
+ * Returns a new document — the input is never mutated. Throws
39
+ * `ConfigMigrationError` when the document has no usable version, is newer
40
+ * than this build understands (the boot downgrade guard's condition,
41
+ * 01-architecture.md §8.1), or a step in the chain is missing.
42
+ */
43
+ export declare function runConfigMigrations(doc: unknown, migrations?: readonly ConfigMigration[]): ConfigDocument;
44
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/config-schema/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,cAAc,CAAC;CAC9C;AAED,0EAA0E;AAC1E,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAAO,CAAC;AAE/D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAkB,IAAI,0BAA0B;CACjD;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CACjC,UAAU,GAAE,SAAS,eAAe,EAAqB,GACxD,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,UAAU,GAAE,SAAS,eAAe,EAAqB,GACxD,cAAc,CAuChB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Config-migration runner (01-architecture.md §8.2).
3
+ *
4
+ * Each migration is a pure function `(doc) => doc` upgrading one version
5
+ * step. The server runs the chain at boot and lazily on read; zip import
6
+ * replays the same path so old exports always upgrade, never silently drop.
7
+ *
8
+ * Browser-safe: no node: imports (this module ships in
9
+ * `@adminium/engine/config`).
10
+ */
11
+ /** The current (latest) config schema version shipped with this build. */
12
+ export const CONFIG_VERSION = 1;
13
+ /**
14
+ * Registered migrations, ordered by `from`. Empty while v1 is current; the
15
+ * first real entry arrives with the v1→v2 bump.
16
+ */
17
+ export const configMigrations = [];
18
+ export class ConfigMigrationError extends Error {
19
+ name = 'ConfigMigrationError';
20
+ }
21
+ /** Latest version reachable through `migrations` (>= CONFIG_VERSION). */
22
+ export function latestConfigVersion(migrations = configMigrations) {
23
+ return migrations.reduce((max, m) => Math.max(max, m.to), CONFIG_VERSION);
24
+ }
25
+ /**
26
+ * Upgrades `doc.v` to the latest version by running the migration chain.
27
+ * Returns a new document — the input is never mutated. Throws
28
+ * `ConfigMigrationError` when the document has no usable version, is newer
29
+ * than this build understands (the boot downgrade guard's condition,
30
+ * 01-architecture.md §8.1), or a step in the chain is missing.
31
+ */
32
+ export function runConfigMigrations(doc, migrations = configMigrations) {
33
+ if (typeof doc !== 'object' || doc === null || Array.isArray(doc)) {
34
+ throw new ConfigMigrationError('config document must be an object');
35
+ }
36
+ const version = doc['v'];
37
+ if (typeof version !== 'number' || !Number.isInteger(version) || version < 1) {
38
+ throw new ConfigMigrationError(`config document has no valid version at "v" (got ${JSON.stringify(version)})`);
39
+ }
40
+ const target = latestConfigVersion(migrations);
41
+ if (version > target) {
42
+ throw new ConfigMigrationError(`config document version ${String(version)} is newer than the latest supported version ` +
43
+ `${String(target)} — upgrade Adminium to open it`);
44
+ }
45
+ let current = { ...doc, v: version };
46
+ while (current.v < target) {
47
+ const from = current.v;
48
+ const step = migrations.find((m) => m.from === from);
49
+ if (!step) {
50
+ throw new ConfigMigrationError(`no config migration registered from version ${String(from)}`);
51
+ }
52
+ if (!Number.isInteger(step.to) || step.to <= step.from) {
53
+ throw new ConfigMigrationError(`invalid migration step v${String(step.from)}→v${String(step.to)}`);
54
+ }
55
+ // Clone before handing to the migration so a misbehaving (mutating)
56
+ // migration can never corrupt the caller's document.
57
+ const upgraded = step.migrate(structuredClone(current));
58
+ current = { ...upgraded, v: step.to };
59
+ }
60
+ return current;
61
+ }
62
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/config-schema/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAiBH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA+B,EAAE,CAAC;AAE/D,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC3B,IAAI,GAAG,sBAAsB,CAAC;CACjD;AAED,yEAAyE;AACzE,MAAM,UAAU,mBAAmB,CACjC,aAAyC,gBAAgB;IAEzD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAY,EACZ,aAAyC,gBAAgB;IAEzD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,oBAAoB,CAAC,mCAAmC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,OAAO,GAAI,GAA+B,CAAC,GAAG,CAAC,CAAC;IACtD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC7E,MAAM,IAAI,oBAAoB,CAC5B,oDAAoD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAC/E,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC;QACrB,MAAM,IAAI,oBAAoB,CAC5B,2BAA2B,MAAM,CAAC,OAAO,CAAC,8CAA8C;YACtF,GAAG,MAAM,CAAC,MAAM,CAAC,gCAAgC,CACpD,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,GAAI,GAA+B,EAAE,CAAC,EAAE,OAAO,EAAoB,CAAC;IACpF,OAAO,OAAO,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC;QACvB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,oBAAoB,CAC5B,+CAA+C,MAAM,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACvD,MAAM,IAAI,oBAAoB,CAC5B,2BAA2B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CACnE,CAAC;QACJ,CAAC;QACD,oEAAoE;QACpE,qDAAqD;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,OAAO,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The §14 page-archetype step — hooks **H1/H2/H4** of the auto-instantiation
3
+ * pipeline as the Engine drives them (04-widget-registry.md §8):
4
+ *
5
+ * H1/H2 `emitCandidates` + `selectArchetype` (`@adminium/widgets/generate`)
6
+ * H4 `composeTemplate(templateId, candidates, ctx)` → the in-memory
7
+ * intermediate, which THIS module wraps into the 01-architecture.md
8
+ * §6.1 page envelope that `generatePages()` persists.
9
+ *
10
+ * research/widget-registry.md §15 step 3 in full: "Per table emit: `page-crud`
11
+ * always; **plus the highest-scoring archetype from §14 triggers**; plus KPI
12
+ * candidates and 2–4 chart candidates". `./crud.ts` + `./dashboard.ts` deliver
13
+ * the first and last clauses through the same leaf (`composeCrudBody`,
14
+ * `emitDomainDashboardCandidates`), fed by this module's adapter; this module
15
+ * adds the middle clause. Archetype pages are **purely additive** — a table
16
+ * that earns one keeps its `page-crud` unchanged, and a table that earns none
17
+ * loses nothing.
18
+ *
19
+ * WHERE THE RULES LIVE: in `@adminium/widgets`, not here — 04 §8 assigns the
20
+ * catalog and its triggers to the Registry ("so the catalog and its trigger
21
+ * logic never drift apart") and only the pipeline to the Engine. That package
22
+ * cannot see `TableModel`/`ClassifiedTable` (01 §2.3 forbids widgets → engine
23
+ * beyond the config leaf), so it declares the fields its rules read as its own
24
+ * structural contract and this module is the **adapter**: `toCandidateModel`
25
+ * below is the single place the two vocabularies meet, and it is compile-time
26
+ * checked against both.
27
+ */
28
+ import { type ArchetypeSelection, type CandidateTableInput, type ComposeWarning, type WidgetCandidate } from '@adminium/widgets/generate';
29
+ import { type ClassifiedTable } from '../classify/index.js';
30
+ import type { DatabaseModel, TableModel } from '../schema-model.js';
31
+ /**
32
+ * Adapt a classified model into the rules' input. `tables` is the *included*
33
+ * set (`settings.includedTables` has already been applied upstream, and system
34
+ * / join tables have already been split out) — the cross-table §14 triggers only
35
+ * ever pair tables that will actually get pages.
36
+ */
37
+ export declare function toCandidateModel(model: DatabaseModel, tables: readonly TableModel[], classified: ReadonlyMap<string, ClassifiedTable>): CandidateTableInput[];
38
+ export interface ArchetypeBuildContext {
39
+ connectionId: string;
40
+ /** Unique, already-claimed slug for this page. */
41
+ slug: string;
42
+ /**
43
+ * Explicit page id — the 06 §8.3 materialization path targets an existing
44
+ * `page_<sha30>` row. Defaults to `pageIdFor(connectionId, slug)`.
45
+ */
46
+ id?: string | undefined;
47
+ navOrder: number;
48
+ /** Live registry membership test, threaded to H1 and H4 (04 §10). */
49
+ isRegistered?: ((widgetId: string) => boolean) | undefined;
50
+ }
51
+ export interface ArchetypeBuildResult {
52
+ /**
53
+ * Unhashed, unvalidated envelope — `generatePages` stamps + validates it.
54
+ * `null` ⇔ composition failed (a `required` slot had no accepted candidate),
55
+ * the `buildDashboardEnvelope` → null + caller-records-a-warning idiom. The
56
+ * table simply keeps just its `page-crud`.
57
+ */
58
+ envelope: Record<string, unknown> | null;
59
+ warnings: readonly ComposeWarning[];
60
+ }
61
+ /** Compose one archetype page for a table and wrap it into the §6.1 envelope. */
62
+ export declare function buildArchetypeEnvelope(table: TableModel, selection: ArchetypeSelection, candidates: readonly WidgetCandidate[], ctx: ArchetypeBuildContext): ArchetypeBuildResult;
63
+ /**
64
+ * Compose one REQUESTED §14 archetype page — the 06-llm-assist.md §8.3
65
+ * materialization path: an accepted LLM template suggestion seeds a page row
66
+ * carrying only `{type, table, source: 'llm'}`, and the regeneration hook
67
+ * expands it here from the active snapshot. Nothing is scored — the template
68
+ * id was chosen upstream — but the candidates, the manifest and the
69
+ * required-slot failure mode are exactly the §15 pass's. Returns a null
70
+ * envelope when the table is missing/system/join or composition fails; the
71
+ * caller records a warning and the seed row stays as it was.
72
+ */
73
+ export declare function composeRequestedArchetype(model: DatabaseModel, tableId: string, template: string, ctx: ArchetypeBuildContext): ArchetypeBuildResult;
74
+ /** Slug for a table's archetype page, inside the {@link ID_SLUG_BUDGET}. */
75
+ export declare function archetypeSlug(tableSlug: string, template: string): string;
76
+ //# sourceMappingURL=archetype.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archetype.d.ts","sourceRoot":"","sources":["../../src/generate/archetype.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAIL,KAAK,kBAAkB,EAGvB,KAAK,mBAAmB,EAExB,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,KAAK,EAAmB,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAqIrF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GAC/C,mBAAmB,EAAE,CAWvB;AAkBD,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CAC5D;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;CACrC;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,kBAAkB,EAC7B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,qBAAqB,GACzB,oBAAoB,CAyCtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,qBAAqB,GACzB,oBAAoB,CA0BtB;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIzE"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * The §14 page-archetype step — hooks **H1/H2/H4** of the auto-instantiation
3
+ * pipeline as the Engine drives them (04-widget-registry.md §8):
4
+ *
5
+ * H1/H2 `emitCandidates` + `selectArchetype` (`@adminium/widgets/generate`)
6
+ * H4 `composeTemplate(templateId, candidates, ctx)` → the in-memory
7
+ * intermediate, which THIS module wraps into the 01-architecture.md
8
+ * §6.1 page envelope that `generatePages()` persists.
9
+ *
10
+ * research/widget-registry.md §15 step 3 in full: "Per table emit: `page-crud`
11
+ * always; **plus the highest-scoring archetype from §14 triggers**; plus KPI
12
+ * candidates and 2–4 chart candidates". `./crud.ts` + `./dashboard.ts` deliver
13
+ * the first and last clauses through the same leaf (`composeCrudBody`,
14
+ * `emitDomainDashboardCandidates`), fed by this module's adapter; this module
15
+ * adds the middle clause. Archetype pages are **purely additive** — a table
16
+ * that earns one keeps its `page-crud` unchanged, and a table that earns none
17
+ * loses nothing.
18
+ *
19
+ * WHERE THE RULES LIVE: in `@adminium/widgets`, not here — 04 §8 assigns the
20
+ * catalog and its triggers to the Registry ("so the catalog and its trigger
21
+ * logic never drift apart") and only the pipeline to the Engine. That package
22
+ * cannot see `TableModel`/`ClassifiedTable` (01 §2.3 forbids widgets → engine
23
+ * beyond the config leaf), so it declares the fields its rules read as its own
24
+ * structural contract and this module is the **adapter**: `toCandidateModel`
25
+ * below is the single place the two vocabularies meet, and it is compile-time
26
+ * checked against both.
27
+ */
28
+ import { composeTemplate, emitCandidates, isRegisteredWidgetId, } from '@adminium/widgets/generate';
29
+ import { classifyModel } from '../classify/index.js';
30
+ import { ID_SLUG_BUDGET, humanize, pageIdFor } from './util.js';
31
+ const ARCHETYPE_NAV = {
32
+ 'page-board': { group: 'planning', icon: 'kanban-square', slugSuffix: 'board' },
33
+ 'page-calendar': { group: 'planning', icon: 'calendar', slugSuffix: 'calendar' },
34
+ 'page-scheduler': { group: 'planning', icon: 'calendar-clock', slugSuffix: 'schedule' },
35
+ 'page-directory': { group: 'people', icon: 'users', slugSuffix: 'directory' },
36
+ 'page-chat': { group: 'people', icon: 'message-square', slugSuffix: 'chat' },
37
+ 'page-queue-inbox': { group: 'workspace', icon: 'inbox', slugSuffix: 'queue' },
38
+ 'page-log-viewer': { group: 'library', icon: 'scroll-text', slugSuffix: 'log' },
39
+ 'page-files': { group: 'library', icon: 'folder', slugSuffix: 'files' },
40
+ 'page-master-detail': { group: 'library', icon: 'layout-list', slugSuffix: 'detail' },
41
+ };
42
+ /** Human-readable page-title suffix per archetype. */
43
+ const ARCHETYPE_TITLE = {
44
+ 'page-board': 'Board',
45
+ 'page-calendar': 'Calendar',
46
+ 'page-scheduler': 'Schedule',
47
+ 'page-directory': 'Directory',
48
+ 'page-chat': 'Chat',
49
+ 'page-queue-inbox': 'Queue',
50
+ 'page-log-viewer': 'Log',
51
+ 'page-files': 'Files',
52
+ 'page-master-detail': 'Detail',
53
+ };
54
+ /**
55
+ * Archetype slugs are built inside `pageIdFor`'s slug budget (`./util.ts`) so the
56
+ * page id stays a readable 1:1 image of the (unique) slug rather than the
57
+ * digest-suffixed form an over-budget slug earns. Either way the id is unique —
58
+ * `pageIdFor` is injective — but a nav-visible archetype page reads better as
59
+ * `page_<scope>_orders-board` than `page_<scope>_orders-bo-1f4c9ab2`.
60
+ */
61
+ /* ---------------------------------------------------------------- adapter */
62
+ /** Resolve a column's enum values (the rules match on the value vocabulary). */
63
+ function enumValuesFor(model, column) {
64
+ if (column.enumRef === null)
65
+ return undefined;
66
+ return model.enums.find((e) => e.id === column.enumRef)?.values;
67
+ }
68
+ /**
69
+ * `TableModel` → the rules' structural table contract. Beyond what the §14
70
+ * triggers read, the mirror carries the crud-body facts (`ordinal`,
71
+ * `defaultKind`, `isGenerated`, `maxLength`, `primaryKey`) — `composeCrudBody`
72
+ * reproduces the bespoke builder byte-for-byte only when these map exactly
73
+ * (undefined ⇔ the engine's null for `enumValues`; `default?.kind ?? null`).
74
+ */
75
+ function toCandidateTable(model, table) {
76
+ const activity = table.activity;
77
+ return {
78
+ id: table.id,
79
+ schema: table.schema,
80
+ name: table.name,
81
+ label: table.label,
82
+ kind: table.kind,
83
+ rowCountEstimate: table.rowCountEstimate,
84
+ writeVelocity: activity === null ? null : activity.inserts + activity.updates + activity.deletes,
85
+ primaryKey: table.primaryKey,
86
+ columns: table.columns.map((column) => ({
87
+ name: column.name,
88
+ ordinal: column.ordinal,
89
+ logicalType: column.logicalType,
90
+ nullable: column.nullable,
91
+ isPrimaryKey: column.isPrimaryKey,
92
+ isUnique: column.isUnique,
93
+ isGenerated: column.isGenerated,
94
+ defaultKind: column.default?.kind ?? null,
95
+ maxLength: column.maxLength,
96
+ enumValues: enumValuesFor(model, column),
97
+ references: column.references,
98
+ })),
99
+ };
100
+ }
101
+ /**
102
+ * `ClassifiedTable` → the rules' structural classification contract.
103
+ *
104
+ * SEMANTIC SOURCE (05 §7 "overrides always win"): recomputed heuristics are
105
+ * authoritative for the model *as generated* — post `includedTables` filtering,
106
+ * a join table whose partner is excluded genuinely stops being a join table,
107
+ * and its columns reclassify on the filtered model (deliberate change from the
108
+ * bespoke dashboard builder, which read full-model stamps). But a column
109
+ * stamped `source: 'llm' | 'override'` is an explicit enrichment, not a
110
+ * heuristic, so it beats the recomputed tag — the same rule
111
+ * `applyClassification` uses when stamping the model. Table semantics carry no
112
+ * `source`, so roles stay recomputed-only.
113
+ */
114
+ function toClassifiedInput(table, classified) {
115
+ const stampedByName = new Map(table.columns.map((c) => [c.name, c.semantics]));
116
+ const semanticsFor = (column, recomputed) => {
117
+ const stamped = stampedByName.get(column);
118
+ return stamped !== null && stamped !== undefined && stamped.source !== 'heuristic'
119
+ ? stamped
120
+ : recomputed;
121
+ };
122
+ return {
123
+ tableId: classified.tableId,
124
+ shape: classified.shape.kind,
125
+ role: classified.semantics.role,
126
+ displayColumn: classified.displayColumn,
127
+ naturalKey: classified.naturalKey,
128
+ hierarchyColumn: classified.semantics.hierarchy?.parentColumn ?? null,
129
+ columns: classified.columns.map((column) => {
130
+ const semantics = semanticsFor(column.column, column.semantics);
131
+ return {
132
+ column: column.column,
133
+ semantic: semantics.primary,
134
+ format: semantics.format,
135
+ secret: semantics.flags.secret,
136
+ pii: semantics.flags.pii,
137
+ maskedByDefault: semantics.flags.maskedByDefault,
138
+ pair: semantics.pair,
139
+ };
140
+ }),
141
+ };
142
+ }
143
+ /**
144
+ * Adapt a classified model into the rules' input. `tables` is the *included*
145
+ * set (`settings.includedTables` has already been applied upstream, and system
146
+ * / join tables have already been split out) — the cross-table §14 triggers only
147
+ * ever pair tables that will actually get pages.
148
+ */
149
+ export function toCandidateModel(model, tables, classified) {
150
+ const out = [];
151
+ for (const table of tables) {
152
+ const info = classified.get(table.id);
153
+ if (info === undefined)
154
+ continue;
155
+ out.push({
156
+ table: toCandidateTable(model, table),
157
+ classified: toClassifiedInput(table, info),
158
+ });
159
+ }
160
+ return out;
161
+ }
162
+ /**
163
+ * A candidate as `composeTemplate` takes it: the binding moves inside `config`,
164
+ * which is where the stored layout item carries it (01 §6.1 / 04 §5.1 — exactly
165
+ * as `buildDashboardEnvelope` writes it today).
166
+ */
167
+ function toTemplateCandidate(candidate) {
168
+ return {
169
+ widget: candidate.widget,
170
+ shape: candidate.shape,
171
+ score: candidate.score,
172
+ config: { ...candidate.config, binding: candidate.binding },
173
+ };
174
+ }
175
+ /** Compose one archetype page for a table and wrap it into the §6.1 envelope. */
176
+ export function buildArchetypeEnvelope(table, selection, candidates, ctx) {
177
+ const nav = ARCHETYPE_NAV[selection.template];
178
+ if (nav === undefined) {
179
+ // Unreachable via `selectArchetype` (its ids are a subset of ARCHETYPE_NAV's,
180
+ // asserted by generate-archetypes.test.ts) — a marketplace template reaching
181
+ // here would have no nav placement, so it gets no page rather than a bad one.
182
+ return { envelope: null, warnings: [] };
183
+ }
184
+ const composed = composeTemplate(selection.template, candidates.map(toTemplateCandidate), ctx.isRegistered === undefined ? {} : { isRegistered: ctx.isRegistered });
185
+ if (composed.page === null)
186
+ return { envelope: null, warnings: composed.warnings };
187
+ const suffix = ARCHETYPE_TITLE[selection.template] ?? 'Page';
188
+ const title = `${table.label ?? humanize(table.name)} ${suffix}`;
189
+ return {
190
+ warnings: composed.warnings,
191
+ envelope: {
192
+ v: 1,
193
+ kind: composed.page.type,
194
+ id: ctx.id ?? pageIdFor(ctx.connectionId, ctx.slug),
195
+ template: composed.page.template,
196
+ title: { key: `nav.${ctx.slug}`, fallback: title },
197
+ source: { connectionId: ctx.connectionId, table: table.id },
198
+ nav: { group: nav.group, icon: nav.icon, order: ctx.navOrder, slug: ctx.slug },
199
+ access: { minRole: 'viewer', permissions: [`table:${table.id}:read`] },
200
+ config: {
201
+ templateVersion: composed.page.templateVersion,
202
+ toolbar: composed.page.toolbar,
203
+ overlays: composed.page.overlays,
204
+ // Why this table earned this template — the Studio "why this page?"
205
+ // panel and the H3 LLM prompt read it back off the stored document.
206
+ archetype: { score: selection.score, reasons: selection.reasons },
207
+ layout: composed.page.layout,
208
+ },
209
+ },
210
+ };
211
+ }
212
+ /**
213
+ * Compose one REQUESTED §14 archetype page — the 06-llm-assist.md §8.3
214
+ * materialization path: an accepted LLM template suggestion seeds a page row
215
+ * carrying only `{type, table, source: 'llm'}`, and the regeneration hook
216
+ * expands it here from the active snapshot. Nothing is scored — the template
217
+ * id was chosen upstream — but the candidates, the manifest and the
218
+ * required-slot failure mode are exactly the §15 pass's. Returns a null
219
+ * envelope when the table is missing/system/join or composition fails; the
220
+ * caller records a warning and the seed row stays as it was.
221
+ */
222
+ export function composeRequestedArchetype(model, tableId, template, ctx) {
223
+ const classified = new Map(classifyModel(model).tables.map((t) => [t.tableId, t]));
224
+ // The same include rule as generatePages' splitTables: system and join
225
+ // tables never earn a page (05 §8.2).
226
+ const tables = [...model.tables]
227
+ .filter((table) => {
228
+ const role = classified.get(table.id)?.semantics.role ?? table.semantics?.role ?? 'entity';
229
+ return !table.system && role !== 'system' && role !== 'join-table';
230
+ })
231
+ .sort((a, b) => a.id.localeCompare(b.id));
232
+ const table = tables.find((t) => t.id === tableId);
233
+ if (table === undefined)
234
+ return { envelope: null, warnings: [] };
235
+ const isRegistered = ctx.isRegistered ?? isRegisteredWidgetId;
236
+ const candidateModel = toCandidateModel(model, tables, classified);
237
+ const entry = candidateModel.find((e) => e.table.id === tableId);
238
+ if (entry === undefined)
239
+ return { envelope: null, warnings: [] };
240
+ const candidateCtx = { connectionId: ctx.connectionId, model: candidateModel, isRegistered };
241
+ const candidates = emitCandidates(entry.table, entry.classified, candidateCtx);
242
+ return buildArchetypeEnvelope(table, { template, score: 0, reasons: ['accepted LLM suggestion (06 §8.3)'] }, candidates, { ...ctx, isRegistered });
243
+ }
244
+ /** Slug for a table's archetype page, inside the {@link ID_SLUG_BUDGET}. */
245
+ export function archetypeSlug(tableSlug, template) {
246
+ const suffix = ARCHETYPE_NAV[template]?.slugSuffix ?? 'page';
247
+ const head = tableSlug.slice(0, Math.max(1, ID_SLUG_BUDGET - suffix.length - 1));
248
+ return `${head.replace(/-+$/, '')}-${suffix}`;
249
+ }
250
+ //# sourceMappingURL=archetype.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archetype.js","sourceRoot":"","sources":["../../src/generate/archetype.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `page-crud` envelope generation — one per included table (research/
3
+ * widget-registry.md §14: "Every included table"; 01-architecture.md §6.1
4
+ * fixes the config body shape: `columns[]`, `defaultSort`, `pageSize`,
5
+ * `detail`).
6
+ *
7
+ * The body vocabulary — column selection, tones, form-field mapping — lives in
8
+ * `@adminium/widgets/generate` (`composeCrudBody`; 04 §8: the Registry owns
9
+ * what a generated page contains). This module keeps only what the leaf cannot
10
+ * know: slug/id allocation, nav placement, and the §6.1 envelope wrap. Inputs
11
+ * arrive pre-adapted through `./archetype.ts`'s `toCandidateModel` — the single
12
+ * place the engine and registry vocabularies meet.
13
+ */
14
+ import { type CandidateRelation, type CandidateTableInput } from '@adminium/widgets/generate';
15
+ /**
16
+ * The §7.1 rule-7 tone map moved into the leaf with the rest of the body
17
+ * vocabulary; re-exported because the generate surface is public API of the
18
+ * self-host package (`@adminium/engine` root re-exports this module).
19
+ */
20
+ export { enumTones, type CrudEnumTone } from '@adminium/widgets/generate';
21
+ export interface CrudBuildContext {
22
+ connectionId: string | null;
23
+ slug: string;
24
+ navGroup: 'workspace' | 'library' | 'planning' | 'people' | 'account';
25
+ navIcon: string;
26
+ navOrder: number;
27
+ /** read-only-analytics intent, no-PK tables, and views render read-only. */
28
+ readOnly: boolean;
29
+ /** Tables included in this generation run (detail tabs only link these). */
30
+ includedTableIds: ReadonlySet<string>;
31
+ /** Every model relation — the leaf derives detail tabs from the inbound ones. */
32
+ relations: readonly CandidateRelation[];
33
+ }
34
+ /** Build the (unhashed, unvalidated) `page-crud` envelope for one table. */
35
+ export declare function buildCrudEnvelope(entry: CandidateTableInput, ctx: CrudBuildContext): Record<string, unknown>;
36
+ //# sourceMappingURL=crud.d.ts.map