@happyvertical/smrt-core 0.55.10 → 0.55.12

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 (87) hide show
  1. package/AGENTS.md +2 -0
  2. package/agents/build-knowledge.md +40 -0
  3. package/agents/cookbook-engine.md +102 -0
  4. package/agents/cookbook.md +74 -0
  5. package/dist/consumer-plugin/artifact-publication.js +3 -3
  6. package/dist/consumer-plugin/artifact-publication.js.map +1 -1
  7. package/dist/consumer-plugin/hosted-sti-collections.d.ts +10 -0
  8. package/dist/consumer-plugin/hosted-sti-collections.d.ts.map +1 -0
  9. package/dist/consumer-plugin/hosted-sti-collections.js +96 -0
  10. package/dist/consumer-plugin/hosted-sti-collections.js.map +1 -0
  11. package/dist/consumer-plugin/index.d.ts +1 -1
  12. package/dist/consumer-plugin/index.d.ts.map +1 -1
  13. package/dist/consumer-plugin/index.js +76 -51
  14. package/dist/consumer-plugin/index.js.map +1 -1
  15. package/dist/cookbook/engine/commands.d.ts +37 -0
  16. package/dist/cookbook/engine/commands.d.ts.map +1 -0
  17. package/dist/cookbook/engine/commands.js +275 -0
  18. package/dist/cookbook/engine/commands.js.map +1 -0
  19. package/dist/cookbook/engine/defaults.d.ts +10 -0
  20. package/dist/cookbook/engine/defaults.d.ts.map +1 -0
  21. package/dist/cookbook/engine/defaults.js +49 -0
  22. package/dist/cookbook/engine/defaults.js.map +1 -0
  23. package/dist/cookbook/engine/document.d.ts +66 -0
  24. package/dist/cookbook/engine/document.d.ts.map +1 -0
  25. package/dist/cookbook/engine/document.js +357 -0
  26. package/dist/cookbook/engine/document.js.map +1 -0
  27. package/dist/cookbook/engine/engine.d.ts +49 -0
  28. package/dist/cookbook/engine/engine.d.ts.map +1 -0
  29. package/dist/cookbook/engine/engine.js +399 -0
  30. package/dist/cookbook/engine/engine.js.map +1 -0
  31. package/dist/cookbook/engine/index.d.ts +14 -0
  32. package/dist/cookbook/engine/index.d.ts.map +1 -0
  33. package/dist/cookbook/engine/index.js +8 -0
  34. package/dist/cookbook/engine/nav.d.ts +45 -0
  35. package/dist/cookbook/engine/nav.d.ts.map +1 -0
  36. package/dist/cookbook/engine/nav.js +191 -0
  37. package/dist/cookbook/engine/nav.js.map +1 -0
  38. package/dist/cookbook/engine/schemas.d.ts +29 -0
  39. package/dist/cookbook/engine/schemas.d.ts.map +1 -0
  40. package/dist/cookbook/engine/schemas.js +363 -0
  41. package/dist/cookbook/engine/schemas.js.map +1 -0
  42. package/dist/cookbook/engine/types.d.ts +331 -0
  43. package/dist/cookbook/engine/types.d.ts.map +1 -0
  44. package/dist/cookbook/engine/types.js +10 -0
  45. package/dist/cookbook/engine/types.js.map +1 -0
  46. package/dist/cookbook/engine.d.ts +2 -0
  47. package/dist/cookbook/engine.d.ts.map +1 -0
  48. package/dist/cookbook/engine.js +9 -0
  49. package/dist/cookbook/index.d.ts +6 -0
  50. package/dist/cookbook/index.d.ts.map +1 -0
  51. package/dist/cookbook/v1.schema.json +131 -0
  52. package/dist/cookbook/validate.d.ts +37 -0
  53. package/dist/cookbook/validate.d.ts.map +1 -0
  54. package/dist/cookbook/validate.js +172 -0
  55. package/dist/cookbook/validate.js.map +1 -0
  56. package/dist/cookbook.d.ts +7 -0
  57. package/dist/cookbook.d.ts.map +1 -0
  58. package/dist/cookbook.js +2 -0
  59. package/dist/manifest/static-manifest.js +1 -1
  60. package/dist/manifest/static-manifest.js.map +1 -1
  61. package/dist/manifest/store.js +1 -1
  62. package/dist/manifest.json +1 -1
  63. package/dist/prebuild/index.js +13 -13
  64. package/dist/prebuild/index.js.map +1 -1
  65. package/dist/scanner/types.d.ts +8 -0
  66. package/dist/scanner/types.d.ts.map +1 -1
  67. package/dist/scanner/types.js.map +1 -1
  68. package/dist/smrt-knowledge.json +23 -7
  69. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  70. package/dist/vite-plugin/sveltekit-generator.js +4 -1
  71. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  72. package/dist/vite-plugin/sync-apply-route.d.ts.map +1 -1
  73. package/dist/vite-plugin/sync-apply-route.js +1 -0
  74. package/dist/vite-plugin/sync-apply-route.js.map +1 -1
  75. package/dist/vite-plugin/web-collections.d.ts +5 -0
  76. package/dist/vite-plugin/web-collections.d.ts.map +1 -1
  77. package/dist/vite-plugin/web-collections.js +1 -1
  78. package/dist/vite-plugin/web-collections.js.map +1 -1
  79. package/dist/vite-preset/cookbook-exposure.d.ts +11 -0
  80. package/dist/vite-preset/cookbook-exposure.d.ts.map +1 -0
  81. package/dist/vite-preset/cookbook-exposure.js +95 -0
  82. package/dist/vite-preset/cookbook-exposure.js.map +1 -0
  83. package/dist/vite-preset/index.d.ts +9 -0
  84. package/dist/vite-preset/index.d.ts.map +1 -1
  85. package/dist/vite-preset/index.js +17 -7
  86. package/dist/vite-preset/index.js.map +1 -1
  87. package/package.json +18 -6
@@ -0,0 +1,275 @@
1
+ import { validateCookbook } from "../validate.js";
2
+ import { buildNav, findModel, humanize, modelLabel, withHidden, withItemRenamed, withSectionRenamed } from "./nav.js";
3
+ import { canonical, clone, coveredModels, describeTheme, diagnose, isEmptyCookbook, mergeChanges, prune, readSettings, withFeaturesChanged, withRecipesAdded, withRecipesRemoved, withRequirements, withThemePatch, writeSettings } from "./document.js";
4
+ //#region src/cookbook/engine/commands.ts
5
+ var fail = (code, message, extra = {}) => ({
6
+ ok: false,
7
+ error: {
8
+ code,
9
+ message,
10
+ ...extra
11
+ }
12
+ });
13
+ var done = (state, summary = "", extra = {}) => ({
14
+ ok: true,
15
+ state,
16
+ summary,
17
+ ...extra
18
+ });
19
+ var REPLACE_NEEDED = "This replaces the recipes, options, menu and look. Send replace: true to confirm.";
20
+ var list = (values) => values.join(", ");
21
+ /** The file name an export gets: a slug of the app name. */
22
+ function exportFileName(name) {
23
+ return `${(name ?? "").normalize("NFD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "my-app"}.cookbook.json`;
24
+ }
25
+ var serializeCookbook = (doc) => `${JSON.stringify(doc, null, 2)}\n`;
26
+ /**
27
+ * A document from outside (a library entry, an import, a restored state) as
28
+ * the engine holds it: requirements included, options pruned to what is
29
+ * covered. Recipe and feature ids the catalog lacks stay, reported as
30
+ * `unavailable`, so a round trip loses nothing.
31
+ */
32
+ function adopt(catalog, doc) {
33
+ const byId = new Map(catalog.recipes.map((r) => [r.id, r]));
34
+ const known = doc.recipes.filter((id) => byId.has(id));
35
+ const unknown = doc.recipes.filter((id) => !byId.has(id));
36
+ return canonical(prune(catalog, {
37
+ ...clone(doc),
38
+ recipes: [...withRequirements(known, byId), ...unknown]
39
+ }));
40
+ }
41
+ function libraryName(catalog, id) {
42
+ return id ? catalog.cookbooks?.find((c) => c.id === id)?.name : void 0;
43
+ }
44
+ var describeChange = (catalog, changes) => {
45
+ const label = (id) => catalog.recipes.find((r) => r.id === id)?.label ?? id;
46
+ return [
47
+ changes.added.length ? `Added ${list(changes.added.map(label))}.` : "",
48
+ changes.removed.length ? `Removed ${list(changes.removed.map(label))}.` : "",
49
+ changes.kept.length ? `Kept ${list(changes.kept.map(label))} (needed).` : ""
50
+ ].filter(Boolean).join(" ");
51
+ };
52
+ var describeFeatures = (catalog, changes) => [changes.added.length ? `Added ${list(changes.added.map((id) => modelLabel(catalog, id)))}.` : "", changes.removed.length ? `Removed ${list(changes.removed.map((id) => modelLabel(catalog, id)))}.` : ""].filter(Boolean).join(" ");
53
+ var percent = (fraction) => `${Number((fraction * 100).toFixed(4))}%`;
54
+ var withDoc = (state, doc) => ({
55
+ ...state,
56
+ doc: canonical(doc)
57
+ });
58
+ function navOf(catalog, doc) {
59
+ const sections = buildNav(catalog, doc);
60
+ return {
61
+ sections,
62
+ section: (id) => sections.find((s) => s.id === id),
63
+ item: (id) => sections.flatMap((s) => s.items).find((i) => i.id === id)
64
+ };
65
+ }
66
+ var setLayout = (doc, layout) => {
67
+ const next = { ...doc };
68
+ if (layout) next.layout = layout;
69
+ else delete next.layout;
70
+ return next;
71
+ };
72
+ var handlers = {
73
+ add_recipes(catalog, state, { ids }) {
74
+ const missing = ids.filter((id) => !catalog.recipes.some((r) => r.id === id));
75
+ if (missing.length) return fail("not_found", `No such recipe: ${list(missing)}.`, { path: "input.ids" });
76
+ const { doc, changes } = withRecipesAdded(catalog, state.doc, ids);
77
+ return done(withDoc(state, doc), describeChange(catalog, changes), { changes });
78
+ },
79
+ remove_recipes(catalog, state, { ids }) {
80
+ const { doc, changes } = withRecipesRemoved(catalog, state.doc, ids);
81
+ return done(withDoc(state, doc), describeChange(catalog, changes), { changes });
82
+ },
83
+ add_features(catalog, state, { ids }) {
84
+ const missing = ids.filter((id) => !findModel(catalog, id)?.exposed);
85
+ if (missing.length) return fail("not_found", `No such model to add: ${list(missing)}.`, { path: "input.ids" });
86
+ const { doc, changes } = withFeaturesChanged(catalog, state.doc, ids, true);
87
+ return done(withDoc(state, doc), describeFeatures(catalog, changes), { changes });
88
+ },
89
+ remove_features(catalog, state, { ids }) {
90
+ const { doc, changes } = withFeaturesChanged(catalog, state.doc, ids, false);
91
+ return done(withDoc(state, doc), describeFeatures(catalog, changes), { changes });
92
+ },
93
+ add_cookbook(catalog, state, { id }) {
94
+ const book = catalog.cookbooks?.find((c) => c.id === id);
95
+ if (!book) return fail("not_found", `No cookbook "${id}".`, { path: "input.id" });
96
+ const recipes = withRecipesAdded(catalog, state.doc, book.document.recipes);
97
+ const features = withFeaturesChanged(catalog, recipes.doc, book.document.features.filter((f) => findModel(catalog, f)?.exposed), true);
98
+ const changes = mergeChanges(recipes.changes, features.changes);
99
+ return done(withDoc(state, features.doc), changes.added.length ? `Added the ${book.name} cookbook.` : "", { changes });
100
+ },
101
+ remove_cookbook(catalog, state, { id }) {
102
+ const book = catalog.cookbooks?.find((c) => c.id === id);
103
+ if (!book) return fail("not_found", `No cookbook "${id}".`, { path: "input.id" });
104
+ const recipes = withRecipesRemoved(catalog, state.doc, book.document.recipes);
105
+ const features = withFeaturesChanged(catalog, recipes.doc, book.document.features, false);
106
+ const changes = mergeChanges(recipes.changes, features.changes);
107
+ return done(withDoc(state, features.doc), [describeChange(catalog, recipes.changes), describeFeatures(catalog, features.changes)].filter(Boolean).join(" "), { changes });
108
+ },
109
+ apply_cookbook(catalog, state, { id, replace }) {
110
+ const book = catalog.cookbooks?.find((c) => c.id === id);
111
+ if (!book) return fail("not_found", `No cookbook "${id}".`, { path: "input.id" });
112
+ if (!replace && !isEmptyCookbook(state.doc)) return fail("confirmation_required", REPLACE_NEEDED);
113
+ return done({
114
+ doc: adopt(catalog, book.document),
115
+ applied: id
116
+ }, `${book.name} set up.`);
117
+ },
118
+ import_cookbook(catalog, state, { document, replace }) {
119
+ const checked = validateCookbook(document);
120
+ if (!checked.ok) return fail("invalid_input", checked.errors[0] ?? "Not a cookbook.", {
121
+ path: "input.document",
122
+ details: { errors: checked.errors }
123
+ });
124
+ if (!replace && !isEmptyCookbook(state.doc)) return fail("confirmation_required", REPLACE_NEEDED);
125
+ const n = checked.cookbook.recipes.length;
126
+ return done({
127
+ doc: adopt(catalog, checked.cookbook),
128
+ applied: null
129
+ }, `Imported ${n} ${n === 1 ? "recipe" : "recipes"}.`, checked.warnings.length ? { warnings: checked.warnings } : {});
130
+ },
131
+ set_settings(catalog, state, input) {
132
+ const before = readSettings(catalog, state.doc);
133
+ const next = { ...before };
134
+ const parts = [];
135
+ if (input.currency !== void 0) {
136
+ const code = input.currency.trim().toUpperCase();
137
+ if (catalog.currencies && !catalog.currencies.includes(code)) return fail("invalid_input", `${code} is not a known currency.`, { path: "input.currency" });
138
+ if (!/^[A-Z]{3}$/.test(code)) return fail("invalid_input", "currency must be a three-letter code.", { path: "input.currency" });
139
+ if (code !== before.currency) {
140
+ next.currency = code;
141
+ parts.push(`currency ${code}`);
142
+ }
143
+ }
144
+ if (input.taxRate !== void 0) {
145
+ const fraction = Number((input.taxRate / 100).toFixed(6));
146
+ if (fraction !== before.taxRate) {
147
+ next.taxRate = fraction;
148
+ parts.push(`tax ${percent(fraction)}`);
149
+ }
150
+ }
151
+ if (input.paymentTerms !== void 0) {
152
+ const terms = [...input.paymentTerms].map((ch) => ch.charCodeAt(0) < 32 || ch.charCodeAt(0) === 127 ? " " : ch).join("").trim();
153
+ if (!terms) return fail("invalid_input", "paymentTerms must not be empty.", { path: "input.paymentTerms" });
154
+ if (terms !== before.paymentTerms) {
155
+ next.paymentTerms = terms;
156
+ parts.push(`terms ${terms}`);
157
+ }
158
+ }
159
+ if (!parts.length) return done(state);
160
+ const text = parts.join(", ");
161
+ return done(withDoc(state, writeSettings(catalog, state.doc, next)), `${text[0].toUpperCase()}${text.slice(1)}.`);
162
+ },
163
+ set_policy(catalog, state, input) {
164
+ const model = findModel(catalog, input.model);
165
+ if (!model) return fail("not_found", `No such model: ${input.model}.`, { path: "input.model" });
166
+ if (model.fields) {
167
+ const field = model.fields.find((f) => f.name === input.field);
168
+ if (!field || field.system) return fail("not_found", `${model.name} has no field ${input.field}.`, { path: "input.field" });
169
+ }
170
+ if (!coveredModels(catalog, state.doc).has(model.id)) return fail("not_found", `${humanize(model.name)} is not in the app yet; add its recipe or feature first.`, { path: "input.model" });
171
+ if (state.doc.recipes.some((id) => catalog.recipes.find((r) => r.id === id)?.options?.[model.id]?.fields?.[input.field]?.locked)) return fail("failed", `${input.field} is locked by its recipe.`, { path: "input.field" });
172
+ const rows = state.doc.policies.map((row) => ({ ...row }));
173
+ const existing = rows.find((r) => r.objectRef === model.id && r.fieldName === input.field);
174
+ const row = existing ?? {
175
+ objectRef: model.id,
176
+ fieldName: input.field,
177
+ scopeType: "app"
178
+ };
179
+ const before = JSON.stringify(row);
180
+ for (const key of [
181
+ "visibility",
182
+ "label",
183
+ "help"
184
+ ]) {
185
+ const value = input[key];
186
+ if (value === void 0) continue;
187
+ if (value === null) delete row[key];
188
+ else row[key] = value;
189
+ }
190
+ if (input.defaultValue !== void 0) if (input.defaultValue === null) delete row.defaultValue;
191
+ else {
192
+ const encoded = JSON.stringify(input.defaultValue);
193
+ if (encoded === void 0) return fail("invalid_input", "defaultValue is not a JSON value.", { path: "input.defaultValue" });
194
+ row.defaultValue = encoded;
195
+ }
196
+ const empty = Object.keys(row).length <= 3;
197
+ if (JSON.stringify(row) === before || empty && !existing) return done(state);
198
+ const rest = rows.filter((r) => r !== existing);
199
+ return done(withDoc(state, {
200
+ ...state.doc,
201
+ policies: empty ? rest : [...rest, row]
202
+ }), `Updated ${humanize(model.name)} ${input.field}.`);
203
+ },
204
+ set_theme(_catalog, state, input) {
205
+ const doc = withThemePatch(state.doc, input);
206
+ if (JSON.stringify(canonical(doc).theme ?? null) === JSON.stringify(state.doc.theme ?? null)) return done(state);
207
+ return done(withDoc(state, doc), `Theme: ${describeTheme(canonical(doc).theme)}.`);
208
+ },
209
+ reset_theme(_catalog, state) {
210
+ if (!state.doc.theme) return done(state);
211
+ const doc = { ...state.doc };
212
+ delete doc.theme;
213
+ return done(withDoc(state, doc), "Theme: default.");
214
+ },
215
+ set_name(_catalog, state, input) {
216
+ const doc = { ...state.doc };
217
+ for (const key of ["name", "description"]) {
218
+ const value = input[key];
219
+ if (value === void 0) continue;
220
+ const clean = value?.trim();
221
+ if (clean) doc[key] = clean;
222
+ else delete doc[key];
223
+ }
224
+ if (JSON.stringify(canonical(doc)) === JSON.stringify(state.doc)) return done(state);
225
+ return done(withDoc(state, doc), input.name ? `Named the app ${input.name.trim()}.` : "Updated the app details.");
226
+ },
227
+ rename_section(catalog, state, { id, label }) {
228
+ const section = navOf(catalog, state.doc).section(id);
229
+ if (!section) return fail("not_found", `No menu section "${id}".`, { path: "input.id" });
230
+ const layout = withSectionRenamed(state.doc.layout, section, label);
231
+ return JSON.stringify(layout ?? null) === JSON.stringify(state.doc.layout ?? null) ? done(state) : done(withDoc(state, setLayout(state.doc, layout)), `Renamed the section to ${label.trim()}.`);
232
+ },
233
+ rename_item(catalog, state, { id, label }) {
234
+ const item = navOf(catalog, state.doc).item(id);
235
+ if (!item) return fail("not_found", `No menu entry "${id}".`, { path: "input.id" });
236
+ const layout = withItemRenamed(state.doc.layout, item, label);
237
+ return JSON.stringify(layout ?? null) === JSON.stringify(state.doc.layout ?? null) ? done(state) : done(withDoc(state, setLayout(state.doc, layout)), label ? `Renamed the entry to ${label.trim()}.` : "Entry name restored.");
238
+ },
239
+ hide(catalog, state, { id }) {
240
+ const nav = navOf(catalog, state.doc);
241
+ if (!(nav.section(id) ?? nav.item(id))) return fail("not_found", `No menu section or entry "${id}".`, { path: "input.id" });
242
+ if (state.doc.layout?.hidden?.includes(id)) return done(state);
243
+ return done(withDoc(state, setLayout(state.doc, withHidden(state.doc.layout, id, true))), "Hidden.");
244
+ },
245
+ show(catalog, state, { id }) {
246
+ const nav = navOf(catalog, state.doc);
247
+ if (!nav.section(id) && !nav.item(id)) return fail("not_found", `No menu section or entry "${id}".`, { path: "input.id" });
248
+ if (!state.doc.layout?.hidden?.includes(id)) return done(state);
249
+ return done(withDoc(state, setLayout(state.doc, withHidden(state.doc.layout, id, false))), "Shown.");
250
+ },
251
+ validate(catalog, state) {
252
+ const diagnostics = diagnose(catalog, state.doc);
253
+ return done(state, "", { data: {
254
+ ok: !diagnostics.some((d) => d.severity === "error"),
255
+ diagnostics
256
+ } });
257
+ },
258
+ export_cookbook(catalog, state, { name }) {
259
+ return done(state, "", { data: {
260
+ fileName: exportFileName(name ?? state.doc.name ?? libraryName(catalog, state.applied)),
261
+ text: serializeCookbook(state.doc),
262
+ cookbook: clone(state.doc)
263
+ } });
264
+ }
265
+ };
266
+ /** Run one validated command over a state. Pure: returns the next state, never mutates. */
267
+ function execute(catalog, state, name, input) {
268
+ const handler = handlers[name];
269
+ if (!handler) return fail("unknown_command", `No command "${name}".`);
270
+ return handler(catalog, state, input);
271
+ }
272
+ //#endregion
273
+ export { adopt, execute, exportFileName, fail, libraryName, serializeCookbook };
274
+
275
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","names":[],"sources":["../../../src/cookbook/engine/commands.ts"],"sourcesContent":["import type { Cookbook, CookbookPolicyRow } from '@happyvertical/smrt-types';\nimport { validateCookbook } from '../validate.js';\nimport {\n type AppSettings,\n canonical,\n clone,\n coveredModels,\n describeTheme,\n diagnose,\n isEmptyCookbook,\n mergeChanges,\n prune,\n readSettings,\n withFeaturesChanged,\n withRecipesAdded,\n withRecipesRemoved,\n withRequirements,\n withThemePatch,\n writeSettings,\n} from './document.js';\nimport {\n buildNav,\n findModel,\n humanize,\n modelLabel,\n withHidden,\n withItemRenamed,\n withSectionRenamed,\n} from './nav.js';\nimport type {\n CommandError,\n CommandErrorCode,\n CommandInputs,\n CommandName,\n EngineCatalog,\n ExportData,\n RecipeChanges,\n ValidateData,\n} from './types.js';\n\n/** What the engine holds besides its counters: the document and where it came from. */\nexport interface PlanState {\n doc: Cookbook;\n /** The library cookbook the plan was last set up from. */\n applied: string | null;\n}\n\nexport type Outcome =\n | {\n ok: true;\n state: PlanState;\n summary: string;\n changes?: RecipeChanges;\n data?: unknown;\n warnings?: string[];\n }\n | { ok: false; error: CommandError };\n\nexport const fail = (\n code: CommandErrorCode,\n message: string,\n extra: { path?: string; details?: Record<string, unknown> } = {},\n): Outcome => ({ ok: false, error: { code, message, ...extra } });\n\nconst done = (\n state: PlanState,\n summary = '',\n extra: Partial<Extract<Outcome, { ok: true }>> = {},\n): Outcome => ({ ok: true, state, summary, ...extra });\n\nconst REPLACE_NEEDED =\n 'This replaces the recipes, options, menu and look. Send replace: true to confirm.';\n\nconst list = (values: readonly string[]) => values.join(', ');\n\n/** The file name an export gets: a slug of the app name. */\nexport function exportFileName(name?: string): string {\n const slug = (name ?? '')\n .normalize('NFD')\n .replace(/\\p{M}/gu, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return `${slug || 'my-app'}.cookbook.json`;\n}\n\nexport const serializeCookbook = (doc: Cookbook): string =>\n `${JSON.stringify(doc, null, 2)}\\n`;\n\n/**\n * A document from outside (a library entry, an import, a restored state) as\n * the engine holds it: requirements included, options pruned to what is\n * covered. Recipe and feature ids the catalog lacks stay, reported as\n * `unavailable`, so a round trip loses nothing.\n */\nexport function adopt(catalog: EngineCatalog, doc: Cookbook): Cookbook {\n const byId = new Map(catalog.recipes.map((r) => [r.id, r]));\n const known = doc.recipes.filter((id) => byId.has(id));\n const unknown = doc.recipes.filter((id) => !byId.has(id));\n return canonical(\n prune(catalog, {\n ...clone(doc),\n recipes: [...withRequirements(known, byId), ...unknown],\n }),\n );\n}\n\nexport function libraryName(\n catalog: EngineCatalog,\n id: string | null,\n): string | undefined {\n return id ? catalog.cookbooks?.find((c) => c.id === id)?.name : undefined;\n}\n\nconst describeChange = (catalog: EngineCatalog, changes: RecipeChanges) => {\n const label = (id: string) =>\n catalog.recipes.find((r) => r.id === id)?.label ?? id;\n return [\n changes.added.length ? `Added ${list(changes.added.map(label))}.` : '',\n changes.removed.length\n ? `Removed ${list(changes.removed.map(label))}.`\n : '',\n changes.kept.length\n ? `Kept ${list(changes.kept.map(label))} (needed).`\n : '',\n ]\n .filter(Boolean)\n .join(' ');\n};\n\nconst describeFeatures = (catalog: EngineCatalog, changes: RecipeChanges) =>\n [\n changes.added.length\n ? `Added ${list(changes.added.map((id) => modelLabel(catalog, id)))}.`\n : '',\n changes.removed.length\n ? `Removed ${list(changes.removed.map((id) => modelLabel(catalog, id)))}.`\n : '',\n ]\n .filter(Boolean)\n .join(' ');\n\nconst percent = (fraction: number) => `${Number((fraction * 100).toFixed(4))}%`;\n\ntype Handler<N extends CommandName> = (\n catalog: EngineCatalog,\n state: PlanState,\n input: CommandInputs[N],\n) => Outcome;\n\nconst withDoc = (state: PlanState, doc: Cookbook): PlanState => ({\n ...state,\n doc: canonical(doc),\n});\n\nfunction navOf(catalog: EngineCatalog, doc: Cookbook) {\n const sections = buildNav(catalog, doc);\n return {\n sections,\n section: (id: string) => sections.find((s) => s.id === id),\n item: (id: string) =>\n sections.flatMap((s) => s.items).find((i) => i.id === id),\n };\n}\n\nconst setLayout = (doc: Cookbook, layout: Cookbook['layout']): Cookbook => {\n const next = { ...doc };\n if (layout) next.layout = layout;\n else delete next.layout;\n return next;\n};\n\nconst handlers: { [N in CommandName]?: Handler<N> } = {\n add_recipes(catalog, state, { ids }) {\n const missing = ids.filter(\n (id) => !catalog.recipes.some((r) => r.id === id),\n );\n if (missing.length) {\n return fail('not_found', `No such recipe: ${list(missing)}.`, {\n path: 'input.ids',\n });\n }\n const { doc, changes } = withRecipesAdded(catalog, state.doc, ids);\n return done(withDoc(state, doc), describeChange(catalog, changes), {\n changes,\n });\n },\n remove_recipes(catalog, state, { ids }) {\n const { doc, changes } = withRecipesRemoved(catalog, state.doc, ids);\n return done(withDoc(state, doc), describeChange(catalog, changes), {\n changes,\n });\n },\n add_features(catalog, state, { ids }) {\n const missing = ids.filter((id) => !findModel(catalog, id)?.exposed);\n if (missing.length) {\n return fail('not_found', `No such model to add: ${list(missing)}.`, {\n path: 'input.ids',\n });\n }\n const { doc, changes } = withFeaturesChanged(catalog, state.doc, ids, true);\n return done(withDoc(state, doc), describeFeatures(catalog, changes), {\n changes,\n });\n },\n remove_features(catalog, state, { ids }) {\n const { doc, changes } = withFeaturesChanged(\n catalog,\n state.doc,\n ids,\n false,\n );\n return done(withDoc(state, doc), describeFeatures(catalog, changes), {\n changes,\n });\n },\n add_cookbook(catalog, state, { id }) {\n const book = catalog.cookbooks?.find((c) => c.id === id);\n if (!book)\n return fail('not_found', `No cookbook \"${id}\".`, { path: 'input.id' });\n const recipes = withRecipesAdded(catalog, state.doc, book.document.recipes);\n const features = withFeaturesChanged(\n catalog,\n recipes.doc,\n book.document.features.filter((f) => findModel(catalog, f)?.exposed),\n true,\n );\n const changes = mergeChanges(recipes.changes, features.changes);\n return done(\n withDoc(state, features.doc),\n changes.added.length ? `Added the ${book.name} cookbook.` : '',\n { changes },\n );\n },\n remove_cookbook(catalog, state, { id }) {\n const book = catalog.cookbooks?.find((c) => c.id === id);\n if (!book)\n return fail('not_found', `No cookbook \"${id}\".`, { path: 'input.id' });\n const recipes = withRecipesRemoved(\n catalog,\n state.doc,\n book.document.recipes,\n );\n const features = withFeaturesChanged(\n catalog,\n recipes.doc,\n book.document.features,\n false,\n );\n const changes = mergeChanges(recipes.changes, features.changes);\n return done(\n withDoc(state, features.doc),\n [\n describeChange(catalog, recipes.changes),\n describeFeatures(catalog, features.changes),\n ]\n .filter(Boolean)\n .join(' '),\n { changes },\n );\n },\n apply_cookbook(catalog, state, { id, replace }) {\n const book = catalog.cookbooks?.find((c) => c.id === id);\n if (!book)\n return fail('not_found', `No cookbook \"${id}\".`, { path: 'input.id' });\n if (!replace && !isEmptyCookbook(state.doc)) {\n return fail('confirmation_required', REPLACE_NEEDED);\n }\n return done(\n { doc: adopt(catalog, book.document), applied: id },\n `${book.name} set up.`,\n );\n },\n import_cookbook(catalog, state, { document, replace }) {\n const checked = validateCookbook(document);\n if (!checked.ok) {\n return fail('invalid_input', checked.errors[0] ?? 'Not a cookbook.', {\n path: 'input.document',\n details: { errors: checked.errors },\n });\n }\n if (!replace && !isEmptyCookbook(state.doc)) {\n return fail('confirmation_required', REPLACE_NEEDED);\n }\n const n = checked.cookbook.recipes.length;\n return done(\n { doc: adopt(catalog, checked.cookbook), applied: null },\n `Imported ${n} ${n === 1 ? 'recipe' : 'recipes'}.`,\n checked.warnings.length ? { warnings: checked.warnings } : {},\n );\n },\n set_settings(catalog, state, input) {\n const before = readSettings(catalog, state.doc);\n const next: AppSettings = { ...before };\n const parts: string[] = [];\n if (input.currency !== undefined) {\n const code = input.currency.trim().toUpperCase();\n if (catalog.currencies && !catalog.currencies.includes(code)) {\n return fail('invalid_input', `${code} is not a known currency.`, {\n path: 'input.currency',\n });\n }\n if (!/^[A-Z]{3}$/.test(code)) {\n return fail('invalid_input', 'currency must be a three-letter code.', {\n path: 'input.currency',\n });\n }\n if (code !== before.currency) {\n next.currency = code;\n parts.push(`currency ${code}`);\n }\n }\n if (input.taxRate !== undefined) {\n const fraction = Number((input.taxRate / 100).toFixed(6));\n if (fraction !== before.taxRate) {\n next.taxRate = fraction;\n parts.push(`tax ${percent(fraction)}`);\n }\n }\n if (input.paymentTerms !== undefined) {\n const terms = [...input.paymentTerms]\n .map((ch) =>\n ch.charCodeAt(0) < 32 || ch.charCodeAt(0) === 127 ? ' ' : ch,\n )\n .join('')\n .trim();\n if (!terms) {\n return fail('invalid_input', 'paymentTerms must not be empty.', {\n path: 'input.paymentTerms',\n });\n }\n if (terms !== before.paymentTerms) {\n next.paymentTerms = terms;\n parts.push(`terms ${terms}`);\n }\n }\n if (!parts.length) return done(state);\n const text = parts.join(', ');\n return done(\n withDoc(state, writeSettings(catalog, state.doc, next)),\n `${text[0].toUpperCase()}${text.slice(1)}.`,\n );\n },\n set_policy(catalog, state, input) {\n const model = findModel(catalog, input.model);\n if (!model)\n return fail('not_found', `No such model: ${input.model}.`, {\n path: 'input.model',\n });\n if (model.fields) {\n const field = model.fields.find((f) => f.name === input.field);\n if (!field || field.system) {\n return fail('not_found', `${model.name} has no field ${input.field}.`, {\n path: 'input.field',\n });\n }\n }\n if (!coveredModels(catalog, state.doc).has(model.id)) {\n return fail(\n 'not_found',\n `${humanize(model.name)} is not in the app yet; add its recipe or feature first.`,\n { path: 'input.model' },\n );\n }\n const locked = state.doc.recipes.some(\n (id) =>\n catalog.recipes.find((r) => r.id === id)?.options?.[model.id]?.fields?.[\n input.field\n ]?.locked,\n );\n if (locked)\n return fail('failed', `${input.field} is locked by its recipe.`, {\n path: 'input.field',\n });\n const rows = state.doc.policies.map((row) => ({ ...row }));\n const existing = rows.find(\n (r) => r.objectRef === model.id && r.fieldName === input.field,\n );\n const row: CookbookPolicyRow = existing ?? {\n objectRef: model.id,\n fieldName: input.field,\n scopeType: 'app',\n };\n const before = JSON.stringify(row);\n for (const key of ['visibility', 'label', 'help'] as const) {\n const value = input[key];\n if (value === undefined) continue;\n if (value === null) delete row[key];\n else (row as unknown as Record<string, unknown>)[key] = value;\n }\n if (input.defaultValue !== undefined) {\n if (input.defaultValue === null) delete row.defaultValue;\n else {\n const encoded = JSON.stringify(input.defaultValue);\n if (encoded === undefined) {\n return fail('invalid_input', 'defaultValue is not a JSON value.', {\n path: 'input.defaultValue',\n });\n }\n row.defaultValue = encoded;\n }\n }\n // A row with only its identity says nothing: it is removed, not stored.\n const empty = Object.keys(row).length <= 3;\n if (JSON.stringify(row) === before || (empty && !existing))\n return done(state);\n const rest = rows.filter((r) => r !== existing);\n return done(\n withDoc(state, { ...state.doc, policies: empty ? rest : [...rest, row] }),\n `Updated ${humanize(model.name)} ${input.field}.`,\n );\n },\n set_theme(_catalog, state, input) {\n const doc = withThemePatch(state.doc, input);\n if (\n JSON.stringify(canonical(doc).theme ?? null) ===\n JSON.stringify(state.doc.theme ?? null)\n ) {\n return done(state);\n }\n return done(\n withDoc(state, doc),\n `Theme: ${describeTheme(canonical(doc).theme)}.`,\n );\n },\n reset_theme(_catalog, state) {\n if (!state.doc.theme) return done(state);\n const doc = { ...state.doc };\n delete doc.theme;\n return done(withDoc(state, doc), 'Theme: default.');\n },\n set_name(_catalog, state, input) {\n const doc = { ...state.doc };\n for (const key of ['name', 'description'] as const) {\n const value = input[key];\n if (value === undefined) continue;\n const clean = value?.trim();\n if (clean) doc[key] = clean;\n else delete doc[key];\n }\n if (JSON.stringify(canonical(doc)) === JSON.stringify(state.doc))\n return done(state);\n return done(\n withDoc(state, doc),\n input.name\n ? `Named the app ${input.name.trim()}.`\n : 'Updated the app details.',\n );\n },\n rename_section(catalog, state, { id, label }) {\n const section = navOf(catalog, state.doc).section(id);\n if (!section)\n return fail('not_found', `No menu section \"${id}\".`, {\n path: 'input.id',\n });\n const layout = withSectionRenamed(state.doc.layout, section, label);\n return JSON.stringify(layout ?? null) ===\n JSON.stringify(state.doc.layout ?? null)\n ? done(state)\n : done(\n withDoc(state, setLayout(state.doc, layout)),\n `Renamed the section to ${label.trim()}.`,\n );\n },\n rename_item(catalog, state, { id, label }) {\n const item = navOf(catalog, state.doc).item(id);\n if (!item)\n return fail('not_found', `No menu entry \"${id}\".`, { path: 'input.id' });\n const layout = withItemRenamed(state.doc.layout, item, label);\n return JSON.stringify(layout ?? null) ===\n JSON.stringify(state.doc.layout ?? null)\n ? done(state)\n : done(\n withDoc(state, setLayout(state.doc, layout)),\n label\n ? `Renamed the entry to ${label.trim()}.`\n : 'Entry name restored.',\n );\n },\n hide(catalog, state, { id }) {\n const nav = navOf(catalog, state.doc);\n const target = nav.section(id) ?? nav.item(id);\n if (!target)\n return fail('not_found', `No menu section or entry \"${id}\".`, {\n path: 'input.id',\n });\n if (state.doc.layout?.hidden?.includes(id)) return done(state);\n return done(\n withDoc(\n state,\n setLayout(state.doc, withHidden(state.doc.layout, id, true)),\n ),\n 'Hidden.',\n );\n },\n show(catalog, state, { id }) {\n const nav = navOf(catalog, state.doc);\n if (!nav.section(id) && !nav.item(id)) {\n return fail('not_found', `No menu section or entry \"${id}\".`, {\n path: 'input.id',\n });\n }\n if (!state.doc.layout?.hidden?.includes(id)) return done(state);\n return done(\n withDoc(\n state,\n setLayout(state.doc, withHidden(state.doc.layout, id, false)),\n ),\n 'Shown.',\n );\n },\n validate(catalog, state) {\n const diagnostics = diagnose(catalog, state.doc);\n const data: ValidateData = {\n ok: !diagnostics.some((d) => d.severity === 'error'),\n diagnostics,\n };\n return done(state, '', { data });\n },\n export_cookbook(catalog, state, { name }) {\n const fileName = exportFileName(\n name ?? state.doc.name ?? libraryName(catalog, state.applied),\n );\n const data: ExportData = {\n fileName,\n text: serializeCookbook(state.doc),\n cookbook: clone(state.doc),\n };\n return done(state, '', { data });\n },\n};\n\n/** Run one validated command over a state. Pure: returns the next state, never mutates. */\nexport function execute<N extends CommandName>(\n catalog: EngineCatalog,\n state: PlanState,\n name: N,\n input: CommandInputs[N],\n): Outcome {\n const handler = handlers[name] as Handler<N> | undefined;\n if (!handler) return fail('unknown_command', `No command \"${name}\".`);\n return handler(catalog, state, input);\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { SettingTargets } from './types.js';
2
+ /** smrt-ui's built-in presets (kept as data so the engine imports no UI package). */
3
+ export declare const DEFAULT_THEME_PRESETS: readonly string[];
4
+ export declare const DEFAULT_PRESET = "smrt";
5
+ export declare const DEFAULT_COLOR_SCHEME = "system";
6
+ export declare const DEFAULT_APP_NAME = "my-app";
7
+ export declare const MAX_TERMS_LENGTH = 40;
8
+ /** The commerce fields the app settings are the defaults of. */
9
+ export declare const COMMERCE_SETTING_TARGETS: SettingTargets;
10
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAC;AACF,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAC7C,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAInC,gEAAgE;AAChE,eAAO,MAAM,wBAAwB,EAAE,cAmBtC,CAAC"}
@@ -0,0 +1,49 @@
1
+ //#region src/cookbook/engine/defaults.ts
2
+ /** smrt-ui's built-in presets (kept as data so the engine imports no UI package). */
3
+ var DEFAULT_THEME_PRESETS = [
4
+ "material",
5
+ "glass",
6
+ "studio",
7
+ "smrt",
8
+ "happyvertical"
9
+ ];
10
+ var DEFAULT_PRESET = "smrt";
11
+ var DEFAULT_COLOR_SCHEME = "system";
12
+ var DEFAULT_APP_NAME = "my-app";
13
+ var MAX_TERMS_LENGTH = 40;
14
+ var C = "@happyvertical/smrt-commerce:";
15
+ /** The commerce fields the app settings are the defaults of. */
16
+ var COMMERCE_SETTING_TARGETS = {
17
+ currency: [
18
+ "Order",
19
+ "PurchaseOrder",
20
+ "WholesaleOrder",
21
+ "Estimate",
22
+ "Invoice",
23
+ "Agreement"
24
+ ].map((model) => ({
25
+ model: `${C}${model}`,
26
+ field: "currency"
27
+ })),
28
+ taxRate: ["InvoiceLineItem", "ContractLineItem"].map((model) => ({
29
+ model: `${C}${model}`,
30
+ field: "taxRate"
31
+ })),
32
+ paymentTerms: [...[
33
+ "Order",
34
+ "WholesaleOrder",
35
+ "Estimate",
36
+ "Invoice",
37
+ "Agreement"
38
+ ].map((model) => ({
39
+ model: `${C}${model}`,
40
+ field: "terms"
41
+ })), {
42
+ model: `${C}Customer`,
43
+ field: "paymentTerms"
44
+ }]
45
+ };
46
+ //#endregion
47
+ export { COMMERCE_SETTING_TARGETS, DEFAULT_APP_NAME, DEFAULT_COLOR_SCHEME, DEFAULT_PRESET, DEFAULT_THEME_PRESETS, MAX_TERMS_LENGTH };
48
+
49
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","names":[],"sources":["../../../src/cookbook/engine/defaults.ts"],"sourcesContent":["import type { SettingTargets } from './types.js';\n\n/** smrt-ui's built-in presets (kept as data so the engine imports no UI package). */\nexport const DEFAULT_THEME_PRESETS: readonly string[] = [\n 'material',\n 'glass',\n 'studio',\n 'smrt',\n 'happyvertical',\n];\nexport const DEFAULT_PRESET = 'smrt';\nexport const DEFAULT_COLOR_SCHEME = 'system';\nexport const DEFAULT_APP_NAME = 'my-app';\nexport const MAX_TERMS_LENGTH = 40;\n\nconst C = '@happyvertical/smrt-commerce:';\n\n/** The commerce fields the app settings are the defaults of. */\nexport const COMMERCE_SETTING_TARGETS: SettingTargets = {\n currency: [\n 'Order',\n 'PurchaseOrder',\n 'WholesaleOrder',\n 'Estimate',\n 'Invoice',\n 'Agreement',\n ].map((model) => ({ model: `${C}${model}`, field: 'currency' })),\n taxRate: ['InvoiceLineItem', 'ContractLineItem'].map((model) => ({\n model: `${C}${model}`,\n field: 'taxRate',\n })),\n paymentTerms: [\n ...['Order', 'WholesaleOrder', 'Estimate', 'Invoice', 'Agreement'].map(\n (model) => ({ model: `${C}${model}`, field: 'terms' }),\n ),\n { model: `${C}Customer`, field: 'paymentTerms' },\n ],\n};\n"],"mappings":";;AAGA,IAAa,wBAA2C;CACtD;CACA;CACA;CACA;CACA;AACF;AACA,IAAa,iBAAiB;AAC9B,IAAa,uBAAuB;AACpC,IAAa,mBAAmB;AAChC,IAAa,mBAAmB;AAEhC,IAAM,IAAI;;AAGV,IAAa,2BAA2C;CACtD,UAAU;EACR;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,WAAW;EAAE,OAAO,GAAG,IAAI;EAAS,OAAO;CAAW,EAAE;CAC/D,SAAS,CAAC,mBAAmB,kBAAkB,CAAC,CAAC,KAAK,WAAW;EAC/D,OAAO,GAAG,IAAI;EACd,OAAO;CACT,EAAE;CACF,cAAc,CACZ,GAAG;EAAC;EAAS;EAAkB;EAAY;EAAW;CAAW,CAAC,CAAC,KAChE,WAAW;EAAE,OAAO,GAAG,IAAI;EAAS,OAAO;CAAQ,EACtD,GACA;EAAE,OAAO,GAAG,EAAE;EAAW,OAAO;CAAe,CACjD;AACF"}
@@ -0,0 +1,66 @@
1
+ import type { Cookbook, CookbookTheme } from '@happyvertical/smrt-types';
2
+ import type { Diagnostic, EngineCatalog, EngineRecipe, RecipeChanges, SettingTargets } from './types.js';
3
+ export declare const clone: <T>(value: T) => T;
4
+ export declare const same: (a: unknown, b: unknown) => boolean;
5
+ export declare const emptyCookbook: () => Cookbook;
6
+ /** Does the document hold nothing yet (so replacing it needs no say-so)? */
7
+ export declare function isEmptyCookbook(doc: Cookbook): boolean;
8
+ /**
9
+ * The document in its stable shape: sorted ids, sorted policies, empty optional
10
+ * sections absent, key order fixed. Unknown top-level keys are kept (additive
11
+ * fields in v1). Two engines given the same commands export identical text.
12
+ */
13
+ export declare function canonical(doc: Cookbook): Cookbook;
14
+ /** `ids` plus everything they transitively require, as a sorted set. */
15
+ export declare function withRequirements(ids: Iterable<string>, recipes: ReadonlyMap<string, EngineRecipe>): string[];
16
+ /** Models the added recipes and features cover. */
17
+ export declare function coveredModels(catalog: EngineCatalog, doc: Cookbook): Set<string>;
18
+ export declare function settingTargets(catalog: EngineCatalog): SettingTargets;
19
+ /** Drop options for models nothing covers any more (settings rows stay). */
20
+ export declare function prune(catalog: EngineCatalog, doc: Cookbook): Cookbook;
21
+ export declare function withRecipesAdded(catalog: EngineCatalog, doc: Cookbook, ids: readonly string[]): {
22
+ doc: Cookbook;
23
+ changes: RecipeChanges;
24
+ };
25
+ export declare function withRecipesRemoved(catalog: EngineCatalog, doc: Cookbook, ids: readonly string[]): {
26
+ doc: Cookbook;
27
+ changes: RecipeChanges;
28
+ };
29
+ export declare function withFeaturesChanged(catalog: EngineCatalog, doc: Cookbook, ids: readonly string[], on: boolean): {
30
+ doc: Cookbook;
31
+ changes: RecipeChanges;
32
+ };
33
+ export declare const mergeChanges: (a: RecipeChanges, b: RecipeChanges) => RecipeChanges;
34
+ export interface AppSettings {
35
+ currency: string;
36
+ /** A fraction: 0.0825 is 8.25%. */
37
+ taxRate: number;
38
+ paymentTerms: string;
39
+ }
40
+ export declare const DEFAULT_SETTINGS: Readonly<AppSettings>;
41
+ /** The app's settings: the first stored row of each, else the defaults. */
42
+ export declare function readSettings(catalog: EngineCatalog, doc: Cookbook): AppSettings;
43
+ /**
44
+ * The document with the settings written as app-scope policy rows. A row is
45
+ * written for every model a setting covers (covered or not, so a recipe added
46
+ * later picks it up) and only where the value differs from what the model
47
+ * starts as; otherwise the row's default is removed. Other row keys are kept.
48
+ */
49
+ export declare function writeSettings(catalog: EngineCatalog, doc: Cookbook, settings: AppSettings): Cookbook;
50
+ export declare function compactTheme(theme: CookbookTheme | undefined): CookbookTheme | undefined;
51
+ export declare function describeTheme(theme: CookbookTheme | undefined): string;
52
+ /** A preset replaces a brand colour; a brand colour sits on the preset; the scheme is kept. */
53
+ export declare function withThemePatch(doc: Cookbook, patch: {
54
+ preset?: string;
55
+ primary?: string;
56
+ colorScheme?: CookbookTheme['colorScheme'];
57
+ }): Cookbook;
58
+ /**
59
+ * Check a document against the catalog. Structural errors come from
60
+ * `validateCookbook`; the rest need the catalog: unknown ids, unmet `requires`,
61
+ * policy targets nothing covers, layout ids the menu does not have, theme
62
+ * values. Errors mean the app would not build as written; warnings mean
63
+ * something is carried but unused.
64
+ */
65
+ export declare function diagnose(catalog: EngineCatalog, input: Cookbook): Diagnostic[];
66
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/cookbook/engine/document.ts"],"names":[],"mappings":"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"}