@happyvertical/smrt-core 0.45.3 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/AGENTS.md +39 -0
  2. package/agents/generators.md +0 -1
  3. package/dist/browser.d.ts +2 -1
  4. package/dist/browser.d.ts.map +1 -1
  5. package/dist/decorators/compatibility.d.ts +46 -0
  6. package/dist/decorators/compatibility.d.ts.map +1 -1
  7. package/dist/decorators/compatibility.js +48 -5
  8. package/dist/decorators/compatibility.js.map +1 -1
  9. package/dist/decorators/index.d.ts +119 -1
  10. package/dist/decorators/index.d.ts.map +1 -1
  11. package/dist/decorators/index.js +52 -8
  12. package/dist/decorators/index.js.map +1 -1
  13. package/dist/embedded-write-queue.d.ts.map +1 -1
  14. package/dist/embedded-write-queue.js +20 -1
  15. package/dist/embedded-write-queue.js.map +1 -1
  16. package/dist/generators/custom-action.d.ts +450 -41
  17. package/dist/generators/custom-action.d.ts.map +1 -1
  18. package/dist/generators/custom-action.js +765 -56
  19. package/dist/generators/custom-action.js.map +1 -1
  20. package/dist/generators/index.d.ts +1 -3
  21. package/dist/generators/index.d.ts.map +1 -1
  22. package/dist/generators/index.js +3 -4
  23. package/dist/generators/mcp.d.ts.map +1 -1
  24. package/dist/generators/mcp.js +1 -1
  25. package/dist/generators/mcp.js.map +1 -1
  26. package/dist/generators/preflight-route.d.ts +12 -10
  27. package/dist/generators/preflight-route.d.ts.map +1 -1
  28. package/dist/generators/preflight-route.js +46 -14
  29. package/dist/generators/preflight-route.js.map +1 -1
  30. package/dist/generators/rest.d.ts +44 -0
  31. package/dist/generators/rest.d.ts.map +1 -1
  32. package/dist/generators/rest.js +84 -9
  33. package/dist/generators/rest.js.map +1 -1
  34. package/dist/generators/tenant-gate.d.ts +33 -9
  35. package/dist/generators/tenant-gate.d.ts.map +1 -1
  36. package/dist/generators/tenant-gate.js +2 -1
  37. package/dist/generators/tenant-gate.js.map +1 -1
  38. package/dist/generators.js +3 -4
  39. package/dist/index.d.ts +5 -3
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +6 -6
  42. package/dist/knowledge.d.ts.map +1 -1
  43. package/dist/knowledge.js +87 -31
  44. package/dist/knowledge.js.map +1 -1
  45. package/dist/manifest/static-manifest.d.ts.map +1 -1
  46. package/dist/manifest/static-manifest.js +125 -53
  47. package/dist/manifest/static-manifest.js.map +1 -1
  48. package/dist/manifest/store.js +1 -1
  49. package/dist/manifest/store.js.map +1 -1
  50. package/dist/manifest.json +184 -53
  51. package/dist/migrations/framework-base-tables.d.ts +148 -0
  52. package/dist/migrations/framework-base-tables.d.ts.map +1 -0
  53. package/dist/migrations/framework-base-tables.js +419 -0
  54. package/dist/migrations/framework-base-tables.js.map +1 -0
  55. package/dist/migrations/index.d.ts +1 -0
  56. package/dist/migrations/index.d.ts.map +1 -1
  57. package/dist/migrations/index.js +2 -1
  58. package/dist/migrations.js +2 -1
  59. package/dist/postgres-permissions.d.ts +45 -0
  60. package/dist/postgres-permissions.d.ts.map +1 -0
  61. package/dist/postgres-permissions.js +424 -0
  62. package/dist/postgres-permissions.js.map +1 -0
  63. package/dist/registry/framework-base-classes.d.ts.map +1 -1
  64. package/dist/registry/framework-base-classes.js +4 -1
  65. package/dist/registry/framework-base-classes.js.map +1 -1
  66. package/dist/registry/index.d.ts +1 -1
  67. package/dist/registry/index.d.ts.map +1 -1
  68. package/dist/registry/shared-state.d.ts +19 -0
  69. package/dist/registry/shared-state.d.ts.map +1 -1
  70. package/dist/registry/shared-state.js +16 -1
  71. package/dist/registry/shared-state.js.map +1 -1
  72. package/dist/registry.d.ts +136 -1
  73. package/dist/registry.d.ts.map +1 -1
  74. package/dist/registry.js +231 -1
  75. package/dist/registry.js.map +1 -1
  76. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  77. package/dist/scanner/manifest-generator.js +18 -16
  78. package/dist/scanner/manifest-generator.js.map +1 -1
  79. package/dist/scanner/types.d.ts +59 -6
  80. package/dist/scanner/types.d.ts.map +1 -1
  81. package/dist/scanner/types.js.map +1 -1
  82. package/dist/scripts/create-wrappers.js +0 -5
  83. package/dist/smrt-knowledge.json +35 -35
  84. package/dist/testing/database.d.ts +6 -1
  85. package/dist/testing/database.d.ts.map +1 -1
  86. package/dist/testing/database.js +9 -1
  87. package/dist/testing/database.js.map +1 -1
  88. package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
  89. package/dist/vite-plugin/api-client-entries.js +23 -19
  90. package/dist/vite-plugin/api-client-entries.js.map +1 -1
  91. package/dist/vite-plugin/index.d.ts.map +1 -1
  92. package/dist/vite-plugin/index.js +3 -167
  93. package/dist/vite-plugin/index.js.map +1 -1
  94. package/dist/vite-plugin/sveltekit-generator.d.ts +31 -4
  95. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  96. package/dist/vite-plugin/sveltekit-generator.js +137 -71
  97. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  98. package/dist/vite-plugin/templates/default-ui.ts +22 -1
  99. package/dist/vite-plugin/web-collections.d.ts.map +1 -1
  100. package/dist/vite-plugin/web-collections.js +1 -1
  101. package/dist/vite-plugin/web-collections.js.map +1 -1
  102. package/package.json +10 -10
  103. package/dist/generators/cli.d.ts +0 -155
  104. package/dist/generators/cli.d.ts.map +0 -1
  105. package/dist/generators/cli.js +0 -473
  106. package/dist/generators/cli.js.map +0 -1
@@ -136,19 +136,72 @@ export interface FieldDefinition {
136
136
  */
137
137
  exported?: boolean;
138
138
  }
139
+ export interface MethodParameterDefinition {
140
+ name: string;
141
+ type: string;
142
+ optional: boolean;
143
+ default?: unknown;
144
+ /**
145
+ * The declared annotation -- or a member of an inline object literal inside
146
+ * it -- was syntax the scanner could not express as a string (intersection,
147
+ * tuple, conditional, mapped, `typeof`, indexed access).
148
+ *
149
+ * `type` still reads `'any'` for compatibility, so this flag is the ONLY
150
+ * thing separating "the author wrote `any`" from "the scanner gave up".
151
+ * Anything that must fail closed on an uncertain type -- notably the API
152
+ * wire-ability gate in `generators/custom-action.ts` -- reads this (#2686).
153
+ */
154
+ typeUnresolved?: boolean;
155
+ /**
156
+ * Resolved member types of an INLINE object-literal annotation, flattened
157
+ * across nested literals, arrays, unions, and type arguments.
158
+ *
159
+ * The manifest records an inline literal as the single string `'object'`,
160
+ * which hides exactly the members that decide whether the bag can cross a
161
+ * wire (a callback, a model instance). NAMED bags -- an interface, type
162
+ * alias, `Partial<>`/`Pick<>` -- are deliberately absent here and accepted
163
+ * heuristically instead; expanding them needs cross-file type resolution the
164
+ * AST scanner does not perform (#2686).
165
+ */
166
+ memberTypes?: string[];
167
+ /**
168
+ * For a top-level UNION, each branch with the inline members IT declared.
169
+ *
170
+ * `memberTypes` above flattens across branches, which lets one branch veto
171
+ * another: `{ callback: () => void } | string` is wire-able through its
172
+ * string branch, but the flattened `Function` rejected the whole parameter.
173
+ * A consumer that understands this field MUST prefer it over `memberTypes`
174
+ * for unions. Absent on a non-union parameter and on manifests generated
175
+ * before #2686.
176
+ */
177
+ unionBranches?: ParameterTypeBranch[];
178
+ }
179
+ /** One branch of a top-level union parameter type (#2686). */
180
+ export interface ParameterTypeBranch {
181
+ /** The branch's own type name, e.g. `string` or `object`. */
182
+ type: string;
183
+ /** Inline object members declared by THIS branch only. */
184
+ memberTypes?: string[];
185
+ }
139
186
  export interface MethodDefinition {
140
187
  name: string;
141
188
  async: boolean;
142
- parameters: Array<{
143
- name: string;
144
- type: string;
145
- optional: boolean;
146
- default?: unknown;
147
- }>;
189
+ parameters: MethodParameterDefinition[];
148
190
  returnType: string;
149
191
  description?: string;
150
192
  isStatic: boolean;
151
193
  isPublic: boolean;
194
+ /**
195
+ * Config object of an `@method()` decorator declared on this method.
196
+ *
197
+ * `{}` for a bare `@method()`; absent when the method carries no `@method()`
198
+ * at all. Typed loosely on purpose: this is SCANNED config that reached the
199
+ * manifest as JSON, so consumers narrow it defensively through
200
+ * `readMethodDecoratorConfig` in `generators/custom-action.ts` rather than
201
+ * trusting a compile-time shape. The authoring type is `MethodOptions` in
202
+ * `decorators/index.ts` (#2686).
203
+ */
204
+ decoratorConfig?: Record<string, unknown>;
152
205
  }
153
206
  /**
154
207
  * Pre-generated schema column definition for manifest
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/scanner/types.ts"],"sourcesContent":["/**\n * Type definitions for AST scanning and manifest generation\n */\n\nimport type { SmartObjectConfig } from '../registry.js';\n\n/**\n * Qualified class name in format \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n */\nexport type QualifiedClassName = `${string}:${string}`;\n\n/**\n * Static per-field UI hints authored via `@field({ ui })` (#2046).\n *\n * A pure presentation seed for the field-policy rail (epic #2045): it rides the\n * manifest under the field's `_meta.ui` (never promoted to a top-level\n * `FieldDefinition` key), reaches runtime at `field._meta.ui` via\n * `ObjectRegistry.getAllFields()`, and is emitted to the browser in generated\n * web-collection definitions. It has NO schema, persistence, or security\n * effect — `sensitive`/`readPermission` remain the security rail.\n */\nexport interface FieldUIHints {\n /**\n * Seed the field into the \"basic\" visibility tier (shown before the\n * advanced disclosure). Unmarked fields default per the cold-start rule:\n * an object with no basic markers renders everything basic; once any field\n * is marked, unmarked fields default to advanced.\n */\n basic?: boolean;\n /** Grouping key for form section/grouping (consumer-defined label). */\n group?: string;\n /** Relative sort order within the form/group (ascending). */\n order?: number;\n /**\n * Seed the field's policy as locked: org/user policy tiers may not\n * override it unless an org admin explicitly unlocks it.\n */\n locked?: boolean;\n}\n\n/**\n * Structured metadata attached to a field definition under `_meta`.\n *\n * Captures the field-helper options the scanner and schema/manifest\n * generators read off a field (`sqlType`, `nullable`, `__tenancy`, …). The\n * index signature keeps the bag open for forward-compatible keys without\n * forcing every consumer through `any`.\n */\nexport interface FieldMeta {\n /** Explicit SQL type override (e.g. 'UUID') applied during schema generation. */\n sqlType?: string;\n /** Storage type for cross-package reference ids ('text' forces TEXT). */\n idType?: 'uuid' | 'text';\n /** When true, the column is nullable regardless of `required`. */\n nullable?: boolean;\n /** Mirror of the field's required flag captured at registration. */\n required?: boolean;\n /** Default value carried in metadata for runtime-registry generation. */\n default?: unknown;\n /** Marks the field as the primary key column. */\n primaryKey?: boolean;\n /** Marks the column as unique. */\n unique?: boolean;\n /** Column description carried into generated schema. */\n description?: string;\n /** Static per-field UI hints authored via `@field({ ui })` (#2046). */\n ui?: FieldUIHints;\n /** Opt-in column/JSON-path indexing flag. */\n indexed?: boolean;\n /** Foreign-key delete action carried in metadata. */\n onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';\n /** Configures physical DDL while retaining FK relationship metadata. */\n constraint?:\n | boolean\n | { engines: Array<'postgres' | 'sqlite' | 'duckdb' | 'json'> };\n /** Excludes the field from persistence when true. */\n transient?: boolean;\n /** Numeric/length validation bounds and pattern. */\n min?: number;\n max?: number;\n minLength?: number;\n maxLength?: number;\n /**\n * Validation regex. A string source, a `RegExp`, or — when a manifest was\n * JSON-serialized and a `RegExp` collapsed to `{}` — an opaque object. Read\n * sites must narrow before accessing `.source`.\n */\n pattern?: unknown;\n /** Tenancy metadata injected for tenant-scoped models. */\n __tenancy?: {\n isTenantIdField?: boolean;\n /** Populated by the tenancy beforeSave interceptor when enabled. */\n autoPopulate?: boolean;\n [key: string]: unknown;\n };\n /** Report-aggregate metadata injected by the report normalizer. */\n __report?: {\n kind?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Controls how a class is exposed in manifests and across packages\n */\nexport type SmrtVisibility =\n | 'public' // Included in published manifest, available to all consumers\n | 'internal' // Package-only, excluded from published manifest\n | 'test'; // Test-only, never in any published manifest\n\nexport interface FieldDefinition {\n type:\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef' // Cross-package reference — UUID id column by default, no DDL FK\n | 'oneToMany'\n | 'manyToMany'\n | 'meta'; // STI meta fields (_meta_type, _meta_data)\n required?: boolean;\n default?: unknown;\n min?: number;\n max?: number;\n maxLength?: number;\n minLength?: number;\n related?: string; // For foreignKey, crossPackageRef, oneToMany, manyToMany\n description?: string;\n _meta?: FieldMeta;\n transient?: boolean; // Field not persisted to database\n /**\n * Sensitive value (API secrets, credentials, tax IDs). Still persisted, but\n * excluded from `toPublicJSON()` (generated REST/MCP/SvelteKit responses) and\n * rejected as a `where` filter key.\n */\n sensitive?: boolean;\n /**\n * Read-only over generated write surfaces. Stripped from create/update\n * request bodies so callers cannot mass-assign it.\n */\n readonly?: boolean;\n /**\n * Permission slug required to include this field in public/read responses.\n * Omitted unless the serializer is given a resolved permission set that\n * includes this slug. `sensitive` still wins and hides the field for all\n * callers.\n */\n readPermission?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\nexport interface MethodDefinition {\n name: string;\n async: boolean;\n parameters: Array<{\n name: string;\n type: string;\n optional: boolean;\n default?: unknown;\n }>;\n returnType: string;\n description?: string;\n isStatic: boolean;\n isPublic: boolean;\n}\n\n/**\n * Pre-generated schema column definition for manifest\n */\nexport interface ManifestColumnDefinition {\n type: string; // SQL type: TEXT, INTEGER, DECIMAL, BOOLEAN, DATETIME, JSON\n primaryKey?: boolean;\n /**\n * Non-DDL marker for SMRT-owned identifier/reference columns.\n */\n referenceKind?: 'id' | 'foreignKey' | 'crossPackageRef' | 'tenantId';\n notNull?: boolean;\n unique?: boolean;\n default?: unknown;\n /** Same-package FK only. Cross-package references never populate this. */\n foreignKey?: import('../schema/types.js').ColumnDefinition['foreignKey'];\n}\n\n/**\n * Pre-generated schema index definition for manifest\n */\nexport interface ManifestIndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n where?: string;\n /**\n * Expression-based index target — when set, the DDL strategy renders the\n * index over a JSON path inside `column` (dialect-specific syntax).\n */\n jsonPath?: {\n column: string;\n path: string;\n };\n}\n\n/**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator, stored in manifest.json\n */\nexport interface ManifestSchema {\n tableName: string;\n /**\n * Engine-neutral CREATE TABLE preview. Not executable as-is: no indexes,\n * abstract SQL types. Consumers render `columns` + `indexes` through the\n * engine DDL strategy (see `schema/manifest-schema.ts`, #2358).\n */\n ddl: string;\n columns: Record<string, ManifestColumnDefinition>;\n indexes: ManifestIndexDefinition[];\n version: string; // Hash of schema definition for migration tracking\n}\n\n/**\n * Validation rule type for pre-computed validators\n * These are serializable rules extracted from field definitions at build time,\n * eliminating the need to compile validator closures at runtime.\n */\nexport type ValidationRuleType =\n | 'required'\n | 'min'\n | 'max'\n | 'minLength'\n | 'maxLength'\n | 'pattern';\n\n/**\n * Pre-computed validation rule for a field\n * Generated at build time by ManifestGenerator, stored in manifest.json\n *\n * These rules are evaluated at runtime without creating closure functions,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n */\nexport interface ValidationRule {\n /** Field name to validate */\n field: string;\n /** Type of validation rule */\n rule: ValidationRuleType;\n /** Value for the rule (number for min/max/minLength/maxLength, string for pattern) */\n value?: number | string;\n /** Field type for context (text, integer, decimal, etc.) */\n fieldType?: string;\n}\n\n// ── Agent manifest types ────────────────────────────────────────────────\n\n/**\n * Permission declared by an agent\n * Generated from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n */\nexport interface AgentPermission {\n id: string;\n label: string;\n category: 'slot' | 'method';\n defaultGranted?: boolean;\n}\n\n/**\n * Feature declared by an agent\n */\nexport interface AgentFeature {\n id: string;\n label: string;\n description?: string;\n type: 'slot' | 'method';\n}\n\n/**\n * Menu item derived from agent uiSlots\n */\nexport interface AgentMenuItem {\n id: string;\n label: string;\n icon?: string;\n order: number;\n path: string;\n requiredPermission?: string;\n}\n\n/**\n * Component export declaration derived from package.json exports\n */\nexport interface AgentComponentDeclaration {\n exportPath: string;\n type: string;\n}\n\n/**\n * UI slot definition captured from static uiSlots on Agent subclasses\n */\nexport interface AgentUISlotManifest {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n order?: number;\n disabled?: boolean;\n /** Durable owner for settings written through this slot. */\n scope?: 'agent' | 'persona';\n /** Optional fallback form contract for host applications. */\n settingsSchema?: {\n version: number;\n fields: Array<{\n id: string;\n label: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'textarea' | 'json';\n description?: string;\n required?: boolean;\n default?: unknown;\n placeholder?: string;\n options?: Array<{ value: string; label: string }>;\n min?: number;\n max?: number;\n }>;\n };\n}\n\n/**\n * Admin route declared by an agent via static adminRoutes\n * Consumed by vitePluginAgentRoutes to register admin routes with SvelteKit\n */\nexport interface AgentAdminRouteManifest {\n /** Route path relative to agent root (e.g., 'sources/[sourceId]') */\n path: string;\n /** Component export name from the agent's admin entry point */\n component: string;\n /** Optional: export name for server load function */\n load?: string;\n}\n\n/**\n * Auto-generated agent manifest section\n * Produced by the manifest build pipeline for any class with `agent` decorator config\n */\nexport interface AgentManifest {\n name: string;\n slug: string;\n icon?: string;\n tier: 'free' | 'standard' | 'premium';\n description?: string;\n uiSlots: Record<string, AgentUISlotManifest>;\n adminRoutes?: AgentAdminRouteManifest[];\n /** Default signal subscriptions declared by this agent */\n signalSubscriptions?: string[];\n permissions: AgentPermission[];\n features: AgentFeature[];\n menuItems: AgentMenuItem[];\n components: AgentComponentDeclaration[];\n}\n\n// ── Core manifest types ─────────────────────────────────────────────────\n\nexport interface SmartObjectDefinition {\n /**\n * Qualified name in format \"@package/name:ClassName\"\n * This is the PRIMARY KEY for manifest lookups.\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * Optional during transition - will be required in future versions.\n */\n qualifiedName?: QualifiedClassName;\n\n /**\n * Simple class name (PascalCase)\n * Example: \"Product\"\n */\n className: string;\n\n /**\n * Package name where this class is defined.\n * Example: \"@happyvertical/smrt-core\"\n *\n * Optional during transition - will be required in future versions.\n */\n packageName?: string;\n\n /**\n * Visibility control for manifest inclusion\n * - 'public': Included in published manifest (default)\n * - 'internal': Package-only, excluded from published manifest\n * - 'test': Test-only, never in any published manifest\n *\n * Defaults to 'public' if not specified.\n */\n visibility?: SmrtVisibility;\n\n /**\n * @deprecated Use qualifiedName instead. Kept for transition period.\n * Lowercase class name, formerly used as manifest key.\n */\n name: string;\n\n collection: string; // Pluralized name for endpoints\n filePath: string;\n packageVersion?: string; // Package version for external manifest loading\n importPath?: string; // Import path for dynamic loading (e.g., \"@pkg/objects\")\n modulePath?: string; // Relative module path within package\n exportName?: string; // Named export to use (defaults to className)\n collectionExportName?: string; // Collection class export name\n fields: Record<string, FieldDefinition>;\n methods: Record<string, MethodDefinition>;\n decoratorConfig: SmartObjectConfig;\n extends?: string; // Base class name (simple name, not qualified)\n extendsQualified?: string; // Base class qualified name\n extendsTypeArg?: string; // Generic type argument (e.g., \"Meeting\" from \"SmrtCollection<Meeting>\")\n tools?: Array<{\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n }>;\n /**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, consumers can use this pre-computed schema directly\n * without calling generateSchema() at runtime, eliminating latency.\n */\n schema?: ManifestSchema;\n\n /**\n * Pre-computed validation rules for efficient runtime validation\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, the registry uses these rules instead of compiling\n * validator closures at runtime, significantly reducing startup time.\n *\n * @see ValidationRule\n */\n validationRules?: ValidationRule[];\n\n /**\n * Static properties captured from the class definition\n * Currently used for `static uiSlots` on Agent subclasses\n */\n staticProperties?: Record<string, unknown>;\n\n /**\n * Auto-generated agent manifest\n * Only present for classes with `agent` in their decorator config\n * Generated at build time by ManifestGenerator fifth pass\n */\n agent?: AgentManifest;\n}\n\n/**\n * Fixed `timestamp` for every manifest that can reach build output.\n *\n * Manifests are inlined into bundles (`registerPackageManifest(JSON.parse(...))`),\n * so a wall-clock value changes the emitted bytes on every build. That changes\n * Vite's content hash, which changes `dist/`, which invalidates every\n * downstream package through `dependsOn: ['^build']` — one rebuilt package\n * churned 202 of 245 task hashes, and `typecheck` never reused a cache entry\n * across runs (#2223).\n *\n * Nothing reads the field: `getManifestTimestampsHash` invalidates on\n * filesystem mtimes, and `normalizeManifestForHash` deletes it before\n * comparing. A fixed value therefore costs no information.\n *\n * Genuine runtime caches that expire on elapsed time — the discovery cache in\n * `manifest/discover-smrt-packages.ts` — keep using the clock; they never\n * reach build output.\n */\nexport const MANIFEST_TIMESTAMP = 0;\n\n/**\n * Fixed `generatedAt` for knowledge artifacts emitted into `dist/`.\n *\n * Same reasoning as {@link MANIFEST_TIMESTAMP}: build output is compared\n * byte-for-byte, so it cannot carry the clock. The Unix epoch is used rather\n * than `0` because the field is an ISO-8601 string, and a parseable value\n * keeps any consumer that formats it working.\n *\n * The working copy under `.smrt/` keeps a real timestamp — it is useful to a\n * human there, and `preserveKnowledgeGeneratedAt` already stops it churning\n * across incremental rebuilds.\n */\nexport const DETERMINISTIC_GENERATED_AT = '1970-01-01T00:00:00.000Z';\n\nexport interface SmartObjectManifest {\n version: string;\n /** Always {@link MANIFEST_TIMESTAMP} for build-output manifests. */\n timestamp: number;\n packageName?: string; // Root package name (should be set for all new manifests)\n packageVersion?: string; // Root package version\n /**\n * Objects keyed by qualified name (e.g., \"@happyvertical/smrt-core:Product\")\n * Key is string for backward compatibility, but should be QualifiedClassName format.\n */\n objects: Record<string, SmartObjectDefinition>;\n moduleType?: string; // Module type identifier (e.g., \"smrt\") for package discovery\n smrtDependencies?: string[]; // Discovered SMRT packages from dependency tree\n}\n\nexport interface ScanResult {\n filePath: string;\n objects: SmartObjectDefinition[];\n errors: Array<{\n message: string;\n line?: number;\n column?: number;\n }>;\n}\n\nexport interface ScanOptions {\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n followImports?: boolean;\n baseClasses?: string[]; // Classes to consider as SMRT base classes\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAieA,IAAa,qBAAqB;;;;;;;;;;;;;AAclC,IAAa,6BAA6B"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/scanner/types.ts"],"sourcesContent":["/**\n * Type definitions for AST scanning and manifest generation\n */\n\nimport type { SmartObjectConfig } from '../registry.js';\n\n/**\n * Qualified class name in format \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n */\nexport type QualifiedClassName = `${string}:${string}`;\n\n/**\n * Static per-field UI hints authored via `@field({ ui })` (#2046).\n *\n * A pure presentation seed for the field-policy rail (epic #2045): it rides the\n * manifest under the field's `_meta.ui` (never promoted to a top-level\n * `FieldDefinition` key), reaches runtime at `field._meta.ui` via\n * `ObjectRegistry.getAllFields()`, and is emitted to the browser in generated\n * web-collection definitions. It has NO schema, persistence, or security\n * effect — `sensitive`/`readPermission` remain the security rail.\n */\nexport interface FieldUIHints {\n /**\n * Seed the field into the \"basic\" visibility tier (shown before the\n * advanced disclosure). Unmarked fields default per the cold-start rule:\n * an object with no basic markers renders everything basic; once any field\n * is marked, unmarked fields default to advanced.\n */\n basic?: boolean;\n /** Grouping key for form section/grouping (consumer-defined label). */\n group?: string;\n /** Relative sort order within the form/group (ascending). */\n order?: number;\n /**\n * Seed the field's policy as locked: org/user policy tiers may not\n * override it unless an org admin explicitly unlocks it.\n */\n locked?: boolean;\n}\n\n/**\n * Structured metadata attached to a field definition under `_meta`.\n *\n * Captures the field-helper options the scanner and schema/manifest\n * generators read off a field (`sqlType`, `nullable`, `__tenancy`, …). The\n * index signature keeps the bag open for forward-compatible keys without\n * forcing every consumer through `any`.\n */\nexport interface FieldMeta {\n /** Explicit SQL type override (e.g. 'UUID') applied during schema generation. */\n sqlType?: string;\n /** Storage type for cross-package reference ids ('text' forces TEXT). */\n idType?: 'uuid' | 'text';\n /** When true, the column is nullable regardless of `required`. */\n nullable?: boolean;\n /** Mirror of the field's required flag captured at registration. */\n required?: boolean;\n /** Default value carried in metadata for runtime-registry generation. */\n default?: unknown;\n /** Marks the field as the primary key column. */\n primaryKey?: boolean;\n /** Marks the column as unique. */\n unique?: boolean;\n /** Column description carried into generated schema. */\n description?: string;\n /** Static per-field UI hints authored via `@field({ ui })` (#2046). */\n ui?: FieldUIHints;\n /** Opt-in column/JSON-path indexing flag. */\n indexed?: boolean;\n /** Foreign-key delete action carried in metadata. */\n onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';\n /** Configures physical DDL while retaining FK relationship metadata. */\n constraint?:\n | boolean\n | { engines: Array<'postgres' | 'sqlite' | 'duckdb' | 'json'> };\n /** Excludes the field from persistence when true. */\n transient?: boolean;\n /** Numeric/length validation bounds and pattern. */\n min?: number;\n max?: number;\n minLength?: number;\n maxLength?: number;\n /**\n * Validation regex. A string source, a `RegExp`, or — when a manifest was\n * JSON-serialized and a `RegExp` collapsed to `{}` — an opaque object. Read\n * sites must narrow before accessing `.source`.\n */\n pattern?: unknown;\n /** Tenancy metadata injected for tenant-scoped models. */\n __tenancy?: {\n isTenantIdField?: boolean;\n /** Populated by the tenancy beforeSave interceptor when enabled. */\n autoPopulate?: boolean;\n [key: string]: unknown;\n };\n /** Report-aggregate metadata injected by the report normalizer. */\n __report?: {\n kind?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Controls how a class is exposed in manifests and across packages\n */\nexport type SmrtVisibility =\n | 'public' // Included in published manifest, available to all consumers\n | 'internal' // Package-only, excluded from published manifest\n | 'test'; // Test-only, never in any published manifest\n\nexport interface FieldDefinition {\n type:\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef' // Cross-package reference — UUID id column by default, no DDL FK\n | 'oneToMany'\n | 'manyToMany'\n | 'meta'; // STI meta fields (_meta_type, _meta_data)\n required?: boolean;\n default?: unknown;\n min?: number;\n max?: number;\n maxLength?: number;\n minLength?: number;\n related?: string; // For foreignKey, crossPackageRef, oneToMany, manyToMany\n description?: string;\n _meta?: FieldMeta;\n transient?: boolean; // Field not persisted to database\n /**\n * Sensitive value (API secrets, credentials, tax IDs). Still persisted, but\n * excluded from `toPublicJSON()` (generated REST/MCP/SvelteKit responses) and\n * rejected as a `where` filter key.\n */\n sensitive?: boolean;\n /**\n * Read-only over generated write surfaces. Stripped from create/update\n * request bodies so callers cannot mass-assign it.\n */\n readonly?: boolean;\n /**\n * Permission slug required to include this field in public/read responses.\n * Omitted unless the serializer is given a resolved permission set that\n * includes this slug. `sensitive` still wins and hides the field for all\n * callers.\n */\n readPermission?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\nexport interface MethodParameterDefinition {\n name: string;\n type: string;\n optional: boolean;\n default?: unknown;\n /**\n * The declared annotation -- or a member of an inline object literal inside\n * it -- was syntax the scanner could not express as a string (intersection,\n * tuple, conditional, mapped, `typeof`, indexed access).\n *\n * `type` still reads `'any'` for compatibility, so this flag is the ONLY\n * thing separating \"the author wrote `any`\" from \"the scanner gave up\".\n * Anything that must fail closed on an uncertain type -- notably the API\n * wire-ability gate in `generators/custom-action.ts` -- reads this (#2686).\n */\n typeUnresolved?: boolean;\n /**\n * Resolved member types of an INLINE object-literal annotation, flattened\n * across nested literals, arrays, unions, and type arguments.\n *\n * The manifest records an inline literal as the single string `'object'`,\n * which hides exactly the members that decide whether the bag can cross a\n * wire (a callback, a model instance). NAMED bags -- an interface, type\n * alias, `Partial<>`/`Pick<>` -- are deliberately absent here and accepted\n * heuristically instead; expanding them needs cross-file type resolution the\n * AST scanner does not perform (#2686).\n */\n memberTypes?: string[];\n /**\n * For a top-level UNION, each branch with the inline members IT declared.\n *\n * `memberTypes` above flattens across branches, which lets one branch veto\n * another: `{ callback: () => void } | string` is wire-able through its\n * string branch, but the flattened `Function` rejected the whole parameter.\n * A consumer that understands this field MUST prefer it over `memberTypes`\n * for unions. Absent on a non-union parameter and on manifests generated\n * before #2686.\n */\n unionBranches?: ParameterTypeBranch[];\n}\n\n/** One branch of a top-level union parameter type (#2686). */\nexport interface ParameterTypeBranch {\n /** The branch's own type name, e.g. `string` or `object`. */\n type: string;\n /** Inline object members declared by THIS branch only. */\n memberTypes?: string[];\n}\n\nexport interface MethodDefinition {\n name: string;\n async: boolean;\n parameters: MethodParameterDefinition[];\n returnType: string;\n description?: string;\n isStatic: boolean;\n isPublic: boolean;\n /**\n * Config object of an `@method()` decorator declared on this method.\n *\n * `{}` for a bare `@method()`; absent when the method carries no `@method()`\n * at all. Typed loosely on purpose: this is SCANNED config that reached the\n * manifest as JSON, so consumers narrow it defensively through\n * `readMethodDecoratorConfig` in `generators/custom-action.ts` rather than\n * trusting a compile-time shape. The authoring type is `MethodOptions` in\n * `decorators/index.ts` (#2686).\n */\n decoratorConfig?: Record<string, unknown>;\n}\n\n/**\n * Pre-generated schema column definition for manifest\n */\nexport interface ManifestColumnDefinition {\n type: string; // SQL type: TEXT, INTEGER, DECIMAL, BOOLEAN, DATETIME, JSON\n primaryKey?: boolean;\n /**\n * Non-DDL marker for SMRT-owned identifier/reference columns.\n */\n referenceKind?: 'id' | 'foreignKey' | 'crossPackageRef' | 'tenantId';\n notNull?: boolean;\n unique?: boolean;\n default?: unknown;\n /** Same-package FK only. Cross-package references never populate this. */\n foreignKey?: import('../schema/types.js').ColumnDefinition['foreignKey'];\n}\n\n/**\n * Pre-generated schema index definition for manifest\n */\nexport interface ManifestIndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n where?: string;\n /**\n * Expression-based index target — when set, the DDL strategy renders the\n * index over a JSON path inside `column` (dialect-specific syntax).\n */\n jsonPath?: {\n column: string;\n path: string;\n };\n}\n\n/**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator, stored in manifest.json\n */\nexport interface ManifestSchema {\n tableName: string;\n /**\n * Engine-neutral CREATE TABLE preview. Not executable as-is: no indexes,\n * abstract SQL types. Consumers render `columns` + `indexes` through the\n * engine DDL strategy (see `schema/manifest-schema.ts`, #2358).\n */\n ddl: string;\n columns: Record<string, ManifestColumnDefinition>;\n indexes: ManifestIndexDefinition[];\n version: string; // Hash of schema definition for migration tracking\n}\n\n/**\n * Validation rule type for pre-computed validators\n * These are serializable rules extracted from field definitions at build time,\n * eliminating the need to compile validator closures at runtime.\n */\nexport type ValidationRuleType =\n | 'required'\n | 'min'\n | 'max'\n | 'minLength'\n | 'maxLength'\n | 'pattern';\n\n/**\n * Pre-computed validation rule for a field\n * Generated at build time by ManifestGenerator, stored in manifest.json\n *\n * These rules are evaluated at runtime without creating closure functions,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n */\nexport interface ValidationRule {\n /** Field name to validate */\n field: string;\n /** Type of validation rule */\n rule: ValidationRuleType;\n /** Value for the rule (number for min/max/minLength/maxLength, string for pattern) */\n value?: number | string;\n /** Field type for context (text, integer, decimal, etc.) */\n fieldType?: string;\n}\n\n// ── Agent manifest types ────────────────────────────────────────────────\n\n/**\n * Permission declared by an agent\n * Generated from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n */\nexport interface AgentPermission {\n id: string;\n label: string;\n category: 'slot' | 'method';\n defaultGranted?: boolean;\n}\n\n/**\n * Feature declared by an agent\n */\nexport interface AgentFeature {\n id: string;\n label: string;\n description?: string;\n type: 'slot' | 'method';\n}\n\n/**\n * Menu item derived from agent uiSlots\n */\nexport interface AgentMenuItem {\n id: string;\n label: string;\n icon?: string;\n order: number;\n path: string;\n requiredPermission?: string;\n}\n\n/**\n * Component export declaration derived from package.json exports\n */\nexport interface AgentComponentDeclaration {\n exportPath: string;\n type: string;\n}\n\n/**\n * UI slot definition captured from static uiSlots on Agent subclasses\n */\nexport interface AgentUISlotManifest {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n order?: number;\n disabled?: boolean;\n /** Durable owner for settings written through this slot. */\n scope?: 'agent' | 'persona';\n /** Optional fallback form contract for host applications. */\n settingsSchema?: {\n version: number;\n fields: Array<{\n id: string;\n label: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'textarea' | 'json';\n description?: string;\n required?: boolean;\n default?: unknown;\n placeholder?: string;\n options?: Array<{ value: string; label: string }>;\n min?: number;\n max?: number;\n }>;\n };\n}\n\n/**\n * Admin route declared by an agent via static adminRoutes\n * Consumed by vitePluginAgentRoutes to register admin routes with SvelteKit\n */\nexport interface AgentAdminRouteManifest {\n /** Route path relative to agent root (e.g., 'sources/[sourceId]') */\n path: string;\n /** Component export name from the agent's admin entry point */\n component: string;\n /** Optional: export name for server load function */\n load?: string;\n}\n\n/**\n * Auto-generated agent manifest section\n * Produced by the manifest build pipeline for any class with `agent` decorator config\n */\nexport interface AgentManifest {\n name: string;\n slug: string;\n icon?: string;\n tier: 'free' | 'standard' | 'premium';\n description?: string;\n uiSlots: Record<string, AgentUISlotManifest>;\n adminRoutes?: AgentAdminRouteManifest[];\n /** Default signal subscriptions declared by this agent */\n signalSubscriptions?: string[];\n permissions: AgentPermission[];\n features: AgentFeature[];\n menuItems: AgentMenuItem[];\n components: AgentComponentDeclaration[];\n}\n\n// ── Core manifest types ─────────────────────────────────────────────────\n\nexport interface SmartObjectDefinition {\n /**\n * Qualified name in format \"@package/name:ClassName\"\n * This is the PRIMARY KEY for manifest lookups.\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * Optional during transition - will be required in future versions.\n */\n qualifiedName?: QualifiedClassName;\n\n /**\n * Simple class name (PascalCase)\n * Example: \"Product\"\n */\n className: string;\n\n /**\n * Package name where this class is defined.\n * Example: \"@happyvertical/smrt-core\"\n *\n * Optional during transition - will be required in future versions.\n */\n packageName?: string;\n\n /**\n * Visibility control for manifest inclusion\n * - 'public': Included in published manifest (default)\n * - 'internal': Package-only, excluded from published manifest\n * - 'test': Test-only, never in any published manifest\n *\n * Defaults to 'public' if not specified.\n */\n visibility?: SmrtVisibility;\n\n /**\n * @deprecated Use qualifiedName instead. Kept for transition period.\n * Lowercase class name, formerly used as manifest key.\n */\n name: string;\n\n collection: string; // Pluralized name for endpoints\n filePath: string;\n packageVersion?: string; // Package version for external manifest loading\n importPath?: string; // Import path for dynamic loading (e.g., \"@pkg/objects\")\n modulePath?: string; // Relative module path within package\n exportName?: string; // Named export to use (defaults to className)\n collectionExportName?: string; // Collection class export name\n fields: Record<string, FieldDefinition>;\n methods: Record<string, MethodDefinition>;\n decoratorConfig: SmartObjectConfig;\n extends?: string; // Base class name (simple name, not qualified)\n extendsQualified?: string; // Base class qualified name\n extendsTypeArg?: string; // Generic type argument (e.g., \"Meeting\" from \"SmrtCollection<Meeting>\")\n tools?: Array<{\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n }>;\n /**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, consumers can use this pre-computed schema directly\n * without calling generateSchema() at runtime, eliminating latency.\n */\n schema?: ManifestSchema;\n\n /**\n * Pre-computed validation rules for efficient runtime validation\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, the registry uses these rules instead of compiling\n * validator closures at runtime, significantly reducing startup time.\n *\n * @see ValidationRule\n */\n validationRules?: ValidationRule[];\n\n /**\n * Static properties captured from the class definition\n * Currently used for `static uiSlots` on Agent subclasses\n */\n staticProperties?: Record<string, unknown>;\n\n /**\n * Auto-generated agent manifest\n * Only present for classes with `agent` in their decorator config\n * Generated at build time by ManifestGenerator fifth pass\n */\n agent?: AgentManifest;\n}\n\n/**\n * Fixed `timestamp` for every manifest that can reach build output.\n *\n * Manifests are inlined into bundles (`registerPackageManifest(JSON.parse(...))`),\n * so a wall-clock value changes the emitted bytes on every build. That changes\n * Vite's content hash, which changes `dist/`, which invalidates every\n * downstream package through `dependsOn: ['^build']` — one rebuilt package\n * churned 202 of 245 task hashes, and `typecheck` never reused a cache entry\n * across runs (#2223).\n *\n * Nothing reads the field: `getManifestTimestampsHash` invalidates on\n * filesystem mtimes, and `normalizeManifestForHash` deletes it before\n * comparing. A fixed value therefore costs no information.\n *\n * Genuine runtime caches that expire on elapsed time — the discovery cache in\n * `manifest/discover-smrt-packages.ts` — keep using the clock; they never\n * reach build output.\n */\nexport const MANIFEST_TIMESTAMP = 0;\n\n/**\n * Fixed `generatedAt` for knowledge artifacts emitted into `dist/`.\n *\n * Same reasoning as {@link MANIFEST_TIMESTAMP}: build output is compared\n * byte-for-byte, so it cannot carry the clock. The Unix epoch is used rather\n * than `0` because the field is an ISO-8601 string, and a parseable value\n * keeps any consumer that formats it working.\n *\n * The working copy under `.smrt/` keeps a real timestamp — it is useful to a\n * human there, and `preserveKnowledgeGeneratedAt` already stops it churning\n * across incremental rebuilds.\n */\nexport const DETERMINISTIC_GENERATED_AT = '1970-01-01T00:00:00.000Z';\n\nexport interface SmartObjectManifest {\n version: string;\n /** Always {@link MANIFEST_TIMESTAMP} for build-output manifests. */\n timestamp: number;\n packageName?: string; // Root package name (should be set for all new manifests)\n packageVersion?: string; // Root package version\n /**\n * Objects keyed by qualified name (e.g., \"@happyvertical/smrt-core:Product\")\n * Key is string for backward compatibility, but should be QualifiedClassName format.\n */\n objects: Record<string, SmartObjectDefinition>;\n moduleType?: string; // Module type identifier (e.g., \"smrt\") for package discovery\n smrtDependencies?: string[]; // Discovered SMRT packages from dependency tree\n}\n\nexport interface ScanResult {\n filePath: string;\n objects: SmartObjectDefinition[];\n errors: Array<{\n message: string;\n line?: number;\n column?: number;\n }>;\n}\n\nexport interface ScanOptions {\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n followImports?: boolean;\n baseClasses?: string[]; // Classes to consider as SMRT base classes\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAwhBA,IAAa,qBAAqB;;;;;;;;;;;;;AAclC,IAAa,6BAA6B"}
@@ -36,11 +36,6 @@ const wrappers = [
36
36
  path: 'fields/index.js',
37
37
  exports: '*', // Re-export everything from fields
38
38
  },
39
- {
40
- path: 'generators/cli.js',
41
- exports: ['main'], // Import and run main for CLI
42
- isCLI: true,
43
- },
44
39
  {
45
40
  path: 'prebuild/cli.js',
46
41
  exports: '*', // Re-export everything for prebuild CLI
@@ -3,13 +3,13 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-core",
6
- "packageVersion": "0.45.3",
6
+ "packageVersion": "0.47.0",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "62a4d3896b74aeb744f1eccc297db6f9720bd065a0c81544aeabd0347826540d",
11
- "packageJson": "ae75c51728e810ce71638c123b8555fe638385e96e51ab8a70354e41188c1744",
12
- "agents": "c8f8d790e7b584166a7e45a71fb8af1d5259d41bb7557efc506ee9841a228164",
10
+ "manifest": "09b1222d77963a167626dcb90e2d6e93829a07befdbdd44e95e4afa1ce731ba5",
11
+ "packageJson": "1078007a3c26a95f16635249021728dc56ddb6c465eeebeb1e12dd52a05be2a3",
12
+ "agents": "7ffd32ceede67a125d3926fb27d19a36d6af540f649d42a6b48558f7d113bb73",
13
13
  "moduleDoc:agents/object-runtime.md": "4b6cc7930b071cf3310732f382fa06492d5eec3720fec24092ae21c207d91bfb",
14
14
  "moduleDoc:agents/revision-guard.md": "aa6b1ddb5b6b49fa27ebbe575ec7fcd6d5ceb35ee25acc702f877a226eb9a99a",
15
15
  "moduleDoc:agents/collection-reads.md": "4ce06e8b70b9ce9b77b47b3e2ed266c899bb7962ca015d4714f07a4aca10a865",
@@ -18,7 +18,7 @@
18
18
  "moduleDoc:agents/schema-paths.md": "72f56201086ca687b03a44df968605b6990391df65ebfff7e461596d3f53dba6",
19
19
  "moduleDoc:agents/change-feed.md": "c5921f2536c5f092690cc9ce5dcdf906376a34413d3c10613be6287c11f87f86",
20
20
  "moduleDoc:agents/change-signals.md": "d9cb6a5541728ffea46607a6b1d4fa61d4621849f2b4ea86a0645fbb0af892e9",
21
- "moduleDoc:agents/generators.md": "1c0243c353204b40ed4d5ad688cf812d8eb7e2bb45ffce7e3ce8dca894917b0a",
21
+ "moduleDoc:agents/generators.md": "aa65cadf76994b190f4379f5d3889833be8ea6fe34114d84cf677640a534f150",
22
22
  "moduleDoc:agents/build-knowledge.md": "5e67560801f22ccb1413a512452bcc5d29fafed9b4411561b8c8d9095eba50f3",
23
23
  "moduleDoc:agents/memory.md": "49334471e7a64199bb936756f3a2690ecdd9cff45f677557ea04e7c4b7c78559"
24
24
  },
@@ -27,7 +27,7 @@
27
27
  "./consumer-plugin",
28
28
  "./filesystem",
29
29
  "./generators",
30
- "./generators/cli",
30
+ "./generators/custom-action",
31
31
  "./generators/mcp",
32
32
  "./generators/rest",
33
33
  "./generators/swagger",
@@ -281,7 +281,7 @@
281
281
  "object: ModelType | string",
282
282
  "options?: object"
283
283
  ],
284
- "returns": "Promise<Array>"
284
+ "returns": "any"
285
285
  },
286
286
  {
287
287
  "name": "findSimilarToEmbedding",
@@ -290,7 +290,7 @@
290
290
  "embedding: number[]",
291
291
  "options?: object"
292
292
  ],
293
- "returns": "Promise<Array>"
293
+ "returns": "any"
294
294
  },
295
295
  {
296
296
  "name": "forget",
@@ -338,10 +338,10 @@
338
338
  "name": "getDiff",
339
339
  "async": true,
340
340
  "params": [
341
- "existing: SmrtObject | Record<string>",
342
- "data: Record<string>"
341
+ "existing: SmrtObject | Record<string, unknown>",
342
+ "data: Record<string, unknown>"
343
343
  ],
344
- "returns": "Promise<Record<string> | null>"
344
+ "returns": "Promise<Record<string, unknown> | null>"
345
345
  },
346
346
  {
347
347
  "name": "getFields",
@@ -360,8 +360,8 @@
360
360
  "name": "getOrUpsert",
361
361
  "async": true,
362
362
  "params": [
363
- "data: Record<string>",
364
- "defaults?: Record<string>"
363
+ "data: Record<string, unknown>",
364
+ "defaults?: Record<string, unknown>"
365
365
  ],
366
366
  "returns": "any"
367
367
  },
@@ -372,7 +372,7 @@
372
372
  {
373
373
  "name": "initialize",
374
374
  "async": true,
375
- "returns": "Promise"
375
+ "returns": "Promise<this>"
376
376
  },
377
377
  {
378
378
  "name": "list",
@@ -380,7 +380,7 @@
380
380
  "params": [
381
381
  "options?: SmrtListOptions<ModelType>"
382
382
  ],
383
- "returns": "Promise<SmrtObject[] | Record<string>[]>"
383
+ "returns": "Promise<SmrtObject[] | Record<string, unknown>[]>"
384
384
  },
385
385
  {
386
386
  "name": "listByIds",
@@ -403,7 +403,7 @@
403
403
  "async": true,
404
404
  "params": [
405
405
  "sql: string",
406
- "params?: any",
406
+ "params?: unknown[]",
407
407
  "options?: object"
408
408
  ],
409
409
  "returns": "Promise<ModelType[]>"
@@ -414,7 +414,7 @@
414
414
  "params": [
415
415
  "options: object"
416
416
  ],
417
- "returns": "Promise"
417
+ "returns": "Promise<unknown>"
418
418
  },
419
419
  {
420
420
  "name": "recallAll",
@@ -422,7 +422,7 @@
422
422
  "params": [
423
423
  "options?: object"
424
424
  ],
425
- "returns": "Promise<Map<string>>"
425
+ "returns": "Promise<Map<string, unknown>>"
426
426
  },
427
427
  {
428
428
  "name": "remember",
@@ -439,7 +439,7 @@
439
439
  "query: string",
440
440
  "options?: object"
441
441
  ],
442
- "returns": "Promise<Array>"
442
+ "returns": "any"
443
443
  },
444
444
  {
445
445
  "name": "validate",
@@ -480,33 +480,33 @@
480
480
  {
481
481
  "name": "getAncestors",
482
482
  "async": true,
483
- "returns": "Promise"
483
+ "returns": "Promise<this[]>"
484
484
  },
485
485
  {
486
486
  "name": "getChildren",
487
487
  "async": true,
488
- "returns": "Promise"
488
+ "returns": "Promise<this[]>"
489
489
  },
490
490
  {
491
491
  "name": "getDescendants",
492
492
  "async": true,
493
- "returns": "Promise"
493
+ "returns": "Promise<this[]>"
494
494
  },
495
495
  {
496
496
  "name": "getHierarchy",
497
497
  "async": true,
498
- "returns": "Promise<HierarchyView>"
498
+ "returns": "Promise<HierarchyView<this>>"
499
499
  },
500
500
  {
501
501
  "name": "getParent",
502
502
  "async": true,
503
- "returns": "Promise<null>"
503
+ "returns": "Promise<this | null>"
504
504
  },
505
505
  {
506
506
  "name": "moveTo",
507
507
  "async": true,
508
508
  "params": [
509
- "newParent: string | null"
509
+ "newParent: this | string | null"
510
510
  ],
511
511
  "returns": "Promise<void>"
512
512
  }
@@ -653,7 +653,7 @@
653
653
  "name": "_setLoadedRelationship",
654
654
  "params": [
655
655
  "fieldName: string",
656
- "value: any"
656
+ "value: unknown"
657
657
  ],
658
658
  "returns": "void"
659
659
  },
@@ -663,7 +663,7 @@
663
663
  "params": [
664
664
  "expectedUpdatedAt: Date | string"
665
665
  ],
666
- "returns": "Promise"
666
+ "returns": "Promise<this>"
667
667
  },
668
668
  {
669
669
  "name": "classifyConstraintError",
@@ -785,7 +785,7 @@
785
785
  {
786
786
  "name": "initialize",
787
787
  "async": true,
788
- "returns": "Promise"
788
+ "returns": "Promise<this>"
789
789
  },
790
790
  {
791
791
  "name": "is",
@@ -812,7 +812,7 @@
812
812
  "name": "loadDataFromDb",
813
813
  "async": true,
814
814
  "params": [
815
- "data: Record<string>"
815
+ "data: Record<string, unknown>"
816
816
  ],
817
817
  "returns": "any"
818
818
  },
@@ -854,7 +854,7 @@
854
854
  "params": [
855
855
  "options: object"
856
856
  ],
857
- "returns": "Promise"
857
+ "returns": "Promise<unknown>"
858
858
  },
859
859
  {
860
860
  "name": "recallAll",
@@ -862,7 +862,7 @@
862
862
  "params": [
863
863
  "options?: object"
864
864
  ],
865
- "returns": "Promise<Map<string>>"
865
+ "returns": "Promise<Map<string, unknown>>"
866
866
  },
867
867
  {
868
868
  "name": "remember",
@@ -890,14 +890,14 @@
890
890
  },
891
891
  {
892
892
  "name": "toPlainObject",
893
- "returns": "Record<string>"
893
+ "returns": "Record<string, unknown>"
894
894
  },
895
895
  {
896
896
  "name": "toPublicJSON",
897
897
  "params": [
898
898
  "options?: PublicJsonOptions"
899
899
  ],
900
- "returns": "Record<string>"
900
+ "returns": "Record<string, unknown>"
901
901
  },
902
902
  {
903
903
  "name": "withTransaction",
@@ -981,7 +981,7 @@
981
981
  "polymorphicAssociations": 1,
982
982
  "uuidColumns": 3
983
983
  },
984
- "agentDoc": "# @happyvertical/smrt-core\n\nFoundation ORM, registry, schema/code generation, AI integration, and DispatchBus.\nRead the module for the subsystem being edited; root AGENTS covers shared model\nand repository rules.\n\n## Modules\n\n| Source | Scope | Module doc |\n|---|---|---|\n| `src/object.ts`, `src/collection.ts`, `src/child-accessors.ts` | Lifecycle, hydration, operators, STI, child accessors, dispatch | [agents/object-runtime.md](agents/object-runtime.md) |\n| `src/revision-guard.ts` | Guarded writes and PostgreSQL revision precision | [agents/revision-guard.md](agents/revision-guard.md) |\n| `src/collection.ts` | Projections, latest-related, facets, counts, read plans | [agents/collection-reads.md](agents/collection-reads.md) |\n| `src/collection.ts` | Limits, sort whitelist, generated list order | [agents/query-bounds.md](agents/query-bounds.md) |\n| `src/data-query.ts` | Transport-neutral bounded query normalization | [agents/data-query.md](agents/data-query.md) |\n| `src/schema/`, `src/migrations/`, `src/cascade.ts`, `src/system/` | DDL parity, indexes, migrations, delete integrity, retention | [agents/schema-paths.md](agents/schema-paths.md) |\n| `src/change-feed.ts` | Durable changes, cursors, table versions, retention | [agents/change-feed.md](agents/change-feed.md) |\n| `src/change-signals.ts` | Signal bus, replica fan-out, SSE | [agents/change-signals.md](agents/change-signals.md) |\n| `src/generators/`, `src/vite-plugin/web-collections.ts` | REST/CLI/MCP generation, manifest hashes, ETags | [agents/generators.md](agents/generators.md) |\n| `src/vite-plugin/`, `src/consumer-plugin/`, `src/knowledge.ts` | Decorator UI hints, knowledge projection, generation snapshots | [agents/build-knowledge.md](agents/build-knowledge.md) |\n| `src/object.ts`, `src/collection.ts`, `src/learning/memory.ts` | Context memory and semantic search | [agents/memory.md](agents/memory.md) |\n\n## Cross-module invariants\n\n- `ObjectRegistry` is a `globalThis` singleton so registration survives HMR.\n\n- Production DDL uses manifest generators; `getTestDatabase()` uses registry\n generators. Keep columns, indexes, FK actions, and runtime conflict targets in\n parity (`src/schema/schema-path-parity.test.ts`). Every new query predicate\n needs its index or an explicit reason none is needed.\n- Tenant scoping covers every read and every unique/conflict key. Explicit\n conflict columns are not rewritten; their author must include tenant scope.\n- Persisted saves use `id` and loaded `updated_at`; new saves use natural keys.\n Preserve revision compare-and-swap ordering through public `save()`,\n `claimRevision()`, and transaction APIs. Embedded saves, deletes, and complete\n `withTransaction()` callbacks share a process-local write queue.\n- Collection model hydration is serial in result order: initialization may query\n the same transaction-bound PostgreSQL client. Use projections for plain rows.\n- Native DuckDB UUIDs must be cast coherently on read before identity reuse;\n custom embedded revision paths use `getCanonicalPersistedRow()`. Never replay\n a mutation to discover result types.\n- `withDatabase(db, callback)` restores only database bindings (including public\n `options.db`); `withTransaction(callback)` also restores identity/revision\n metadata after rollback. Do not use a bound instance concurrently.\n- `ensureSystemTables(db, typeHint?)` provisions framework tables idempotently;\n call it on a base PostgreSQL connection before caller-owned transactions.\n Bootstrap uses an advisory lock. Application tables still require migrations;\n runtime table verification checks existence only.\n- Manifest generation fails closed on scanner errors, including unresolved\n decorator spreads. Never emit partial, default-open registration.\n- Generated registration repairs bundled class identity using the exact imported\n constructor, explicit package, and isolated one-object manifest. Never infer\n ownership from paths, simple names, or table names; packages can share names.\n Consumer regression gate: `packages/bundle-gate/src/__tests__/registry-identity.spec.ts`.\n\n## Gotchas\n\n- Optional filesystem support stays lazy: use `createFilesystemAdapter()` in\n `src/filesystem-loader.ts`, not a static files-SDK import. Fully bundled apps\n import `@happyvertical/smrt-core/filesystem` at startup. Use\n `importOptionalDependency()` for similarly heavy optional dependencies.\n- Database retries are transient-only, four attempts total for `get`/`upsert`.\n Use `src/db-errors.ts` classifiers through the cause chain, never message\n matching (SDK driver text can live in `context.originalError`). Constraints,\n bad input, missing tables, and aborted PostgreSQL transactions fail immediately.\n Unique/PK violations become `VALIDATION_UNIQUE_CONSTRAINT`, NOT NULL becomes\n `VALIDATION_REQUIRED_FIELD`; other failures keep the driver error as `cause`.\n- Property initializers precede option values; options win. Arrays/objects are\n shallow-cloned. Collection creation caches fields; table verification caches\n by DB URL and table. Preserve these scopes when changing initialization.\n- The Vite plugin loads scanner/schema code from `dist/` when present. Rebuild\n core after editing those sources before testing consumer manifest generation.\n Vite 8 requires `oxc.decorator: { legacy: true, emitDecoratorMetadata: true }`.\n\n## Validation\n\nRun focused tests first, then applicable package checks:\n\n```bash\npnpm --filter @happyvertical/smrt-core test\npnpm --filter @happyvertical/smrt-core typecheck\npnpm --filter @happyvertical/smrt-core build\npnpm --filter @happyvertical/smrt-core test:postgres\npnpm check:agents-chain\npnpm smrt dev:knowledge-check\n```\n\nThe PostgreSQL lane is required for numeric types, UUID casts, conflict targets,\ntimestamps, and migrations. Tests generate their manifest before Vitest; restart\nwatch mode after adding decorated classes. Documentation-only changes need\ninstruction-chain and knowledge freshness checks, not the runtime test suite.\n",
984
+ "agentDoc": "# @happyvertical/smrt-core\n\nFoundation ORM, registry, schema/code generation, AI integration, and DispatchBus.\nRead the module for the subsystem being edited; root AGENTS covers shared model\nand repository rules.\n\n## Modules\n\n| Source | Scope | Module doc |\n|---|---|---|\n| `src/object.ts`, `src/collection.ts`, `src/child-accessors.ts` | Lifecycle, hydration, operators, STI, child accessors, dispatch | [agents/object-runtime.md](agents/object-runtime.md) |\n| `src/revision-guard.ts` | Guarded writes and PostgreSQL revision precision | [agents/revision-guard.md](agents/revision-guard.md) |\n| `src/collection.ts` | Projections, latest-related, facets, counts, read plans | [agents/collection-reads.md](agents/collection-reads.md) |\n| `src/collection.ts` | Limits, sort whitelist, generated list order | [agents/query-bounds.md](agents/query-bounds.md) |\n| `src/data-query.ts` | Transport-neutral bounded query normalization | [agents/data-query.md](agents/data-query.md) |\n| `src/schema/`, `src/migrations/`, `src/cascade.ts`, `src/system/` | DDL parity, indexes, migrations, delete integrity, retention | [agents/schema-paths.md](agents/schema-paths.md) |\n| `src/postgres-permissions.ts` | Explicit PostgreSQL ACL plans and atomic reconciliation | [deployment permission contract](../../docs/content/postgres-permissions.md) |\n| `src/change-feed.ts` | Durable changes, cursors, table versions, retention | [agents/change-feed.md](agents/change-feed.md) |\n| `src/change-signals.ts` | Signal bus, replica fan-out, SSE | [agents/change-signals.md](agents/change-signals.md) |\n| `src/generators/`, `src/vite-plugin/web-collections.ts` | REST/CLI/MCP generation, manifest hashes, ETags | [agents/generators.md](agents/generators.md) |\n| `src/vite-plugin/`, `src/consumer-plugin/`, `src/knowledge.ts` | Decorator UI hints, knowledge projection, generation snapshots | [agents/build-knowledge.md](agents/build-knowledge.md) |\n| `src/object.ts`, `src/collection.ts`, `src/learning/memory.ts` | Context memory and semantic search | [agents/memory.md](agents/memory.md) |\n\n## Cross-module invariants\n\n- `ObjectRegistry` is a `globalThis` singleton so registration survives HMR.\n\n- Production DDL uses manifest generators; `getTestDatabase()` uses registry\n generators. Keep columns, indexes, FK actions, and runtime conflict targets in\n parity (`src/schema/schema-path-parity.test.ts`). Every new query predicate\n needs its index or an explicit reason none is needed.\n- Tenant scoping covers every read and every unique/conflict key. Explicit\n conflict columns are not rewritten; their author must include tenant scope.\n- Persisted saves use `id` and loaded `updated_at`; new saves use natural keys.\n Preserve revision compare-and-swap ordering through public `save()`,\n `claimRevision()`, and transaction APIs. Embedded saves, deletes, and complete\n `withTransaction()` callbacks share a process-local write queue.\n- Collection model hydration is serial in result order: initialization may query\n the same transaction-bound PostgreSQL client. Use projections for plain rows.\n- Native DuckDB UUIDs must be cast coherently on read before identity reuse;\n custom embedded revision paths use `getCanonicalPersistedRow()`. Never replay\n a mutation to discover result types.\n- `withDatabase(db, callback)` restores only database bindings (including public\n `options.db`); `withTransaction(callback)` also restores identity/revision\n metadata after rollback. Do not use a bound instance concurrently.\n- `ensureSystemTables(db, typeHint?)` provisions framework tables idempotently;\n call it on a base PostgreSQL connection before caller-owned transactions.\n Bootstrap uses an advisory lock. Application tables still require migrations;\n runtime table verification checks existence only.\n- Manifest generation fails closed on scanner errors, including unresolved\n decorator spreads. Never emit partial, default-open registration.\n- Generated registration repairs bundled class identity using the exact imported\n constructor, explicit package, and isolated one-object manifest. Never infer\n ownership from paths, simple names, or table names; packages can share names.\n Consumer regression gate: `packages/bundle-gate/src/__tests__/registry-identity.spec.ts`.\n- API custom-action eligibility has ONE resolver, `resolveApiMethodExposure()`\n in `generators/custom-action.ts`: both SvelteKit route emitters,\n `resolveApiActionSet`, and `knowledge.ts` read it, and a new consumer must too\n — a local mirror is how a method gets reported unavailable while its route\n file is still written. A public method routes by default only when every\n parameter is JSON-shaped; `@method({ expose })` overrides in both directions,\n `expose: true` bypasses the heuristic ALONE, and an explicit `api.include` or\n `api.routes` entry keeps its pre-#2686 route. Fail closed on scanner\n uncertainty: read `parameters[].typeUnresolved`, never the `'any'` it\n substitutes. Accepting `Date` as wire-able and hydrating it\n (`toCustomActionDate`) are one decision — changing either breaks the other.\n The runtime `APIGenerator` transport stays declaration-gated: `rest.ts`\n dispatch and `preflight-route.ts` prediction both read\n `declaresRuntimeRestRoute()`, which must accept every `ApiCustomRouteConfig`\n option so a sweep moving one onto its method cannot delete the endpoint. Its\n twin `declaresRuntimeRestRouteShape()` deliberately ignores `expose: false`:\n the dispatcher must still SEE a withheld declaration to answer 404, because\n `POST /<collection>/<segment>` resolves to `create` when nothing claims the\n segment. Split unions and type arguments with `splitTopLevel()` — a naive\n `split('|')` truncates `Record<string, Asset | null>` into fragments that\n match no rule and are then accepted, widening the gate. `extractTypeName`\n returns `null` for a generic with an unresolvable ARGUMENT or a union with an\n unresolvable BRANCH so those reach that fail-closed path instead of arriving\n as a bare `'Array'`. Runtime transports read\n `ObjectRegistry.resolveRuntimeMethod()`, which tries the item class's manifest\n entry, then the COLLECTION class's (where a collection-hosted action's\n parameters live), then the live `@method()` store — keyed by CONSTRUCTOR,\n never by simple name (`Account` exists in two packages), and recording\n `isStatic` because an unscanned runtime has no manifest to recover the\n receiver from. `isRestActionRoutable` ANDs \"declared\" with that receiver, so\n it never predicts `allow` for an action dispatch refuses. A declared action\n with no receiver is refused (501 collection-scoped, 404 item-scoped), never\n allowed to fall through into `create`. All eight consumers read the resolver,\n including `packages/smrt-workbench/src/discovery.ts`; it imports the\n `./generators/custom-action` LEAF subpath, not `./generators`, because that\n barrel value-re-exports `MCPGenerator` and so drags `@happyvertical/ai` and\n `@happyvertical/sql` into a build-time helper (2 modules vs 109). Keep\n `custom-action.ts` free of value imports outside `tools/tool-generator`.\n\n## Gotchas\n\n- Optional filesystem support stays lazy: use `createFilesystemAdapter()` in\n `src/filesystem-loader.ts`, not a static files-SDK import. Fully bundled apps\n import `@happyvertical/smrt-core/filesystem` at startup. Use\n `importOptionalDependency()` for similarly heavy optional dependencies.\n- Database retries are transient-only, four attempts total for `get`/`upsert`.\n Use `src/db-errors.ts` classifiers through the cause chain, never message\n matching (SDK driver text can live in `context.originalError`). Constraints,\n bad input, missing tables, and aborted PostgreSQL transactions fail immediately.\n Unique/PK violations become `VALIDATION_UNIQUE_CONSTRAINT`, NOT NULL becomes\n `VALIDATION_REQUIRED_FIELD`; other failures keep the driver error as `cause`.\n- Property initializers precede option values; options win. Arrays/objects are\n shallow-cloned. Collection creation caches fields; table verification caches\n by DB URL and table. Preserve these scopes when changing initialization.\n- The Vite plugin loads scanner/schema code from `dist/` when present. Rebuild\n core after editing those sources before testing consumer manifest generation.\n Vite 8 requires `oxc.decorator: { legacy: true, emitDecoratorMetadata: true }`.\n\n## Validation\n\nRun focused tests first, then applicable package checks:\n\n```bash\npnpm --filter @happyvertical/smrt-core test\npnpm --filter @happyvertical/smrt-core typecheck\npnpm --filter @happyvertical/smrt-core build\npnpm --filter @happyvertical/smrt-core test:postgres\npnpm check:agents-chain\npnpm smrt dev:knowledge-check\n```\n\nThe PostgreSQL lane is required for numeric types, UUID casts, conflict targets,\ntimestamps, and migrations. Tests generate their manifest before Vitest; restart\nwatch mode after adding decorated classes. Documentation-only changes need\ninstruction-chain and knowledge freshness checks, not the runtime test suite.\n",
985
985
  "moduleDocs": [
986
986
  {
987
987
  "path": "agents/object-runtime.md",
@@ -1026,7 +1026,7 @@
1026
1026
  {
1027
1027
  "path": "agents/generators.md",
1028
1028
  "module": "generators",
1029
- "content": "# smrt-core/code generators\n\nModule semantics for `src/generators/` + `src/vite-plugin/`. Package orientation, the cross-module\ninvariants, and the traps that apply before editing anything live in\n[../AGENTS.md](../AGENTS.md) — read that first.\n\n## Code Generators\n\n| Generator | Location | Output |\n|-----------|----------|--------|\n| REST API | `src/generators/rest.ts` | OpenAPI-compliant CRUD endpoints |\n| CLI | `src/generators/cli.ts` | `objectname:action` admin commands — writable allowlist, exhaustive-include, `--from-file`, fail-closed tenant context |\n| MCP Server | `src/generators/mcp.ts` | Model Context Protocol tools |\n| Web collections | `src/vite-plugin/web-collections.ts` (selectors) + `generateWebModule` | `@happyvertical/smrt-virt-web` — one typed collection definition per API-exposed REST collection (#1761), consumed by `@happyvertical/smrt-web` |\n\nThe same web virtual module exports `webMcpToolDefinitions` (#2518), a\ncanonical per-tool array selected independently of list materialization. Every\nnon-empty canonical API action set contributes tools, so get-only and\ncustom-action-only models are discoverable; custom actions declared on a\n`SmrtCollection` merge into the owning row collection. Each definition carries\ncomplete route and invalidation metadata. `collectionDefinitions` and its\nembedded descriptor copy remain unchanged for existing cache-backed consumers.\n\nGenerated API clients share `selectApiClientEntries()` across the runtime Vite\nmodule, its ambient declaration, and physical prebuild declarations. When a\ncollection class and its populated model share an endpoint, the model owns the\ncanonical collection key and row payload schema; the collection class remains\navailable under a deterministic class-derived secondary key. Selection and\ncollision suffixes must not depend on manifest insertion order (#2027).\nFor aggregated manifests, inheritance and item-type references resolve exact\nqualified names first, then package-local simple names, then a stable identity\nfallback so duplicate class names across packages cannot reintroduce ordering.\n\nThe web module also emits a build-time **`manifestHash`** constant (#1764): `computeWebManifestHash(manifest)` is a deterministic, replica-stable digest of the emitted web-collection SHAPE (name/className/endpoint/idField/actions/fields/relationships), canonicalized (recursive key sort) before `sha256 → base64url`, truncated to 16 chars — so the same schema always hashes the same, and a field add/remove/type-change/edge-change changes it. A change means old persisted client rows may mis-hydrate, so smrt-web keys its durable persistence namespace on it and its `updateAvailable` contract signal compares against it. Four co-managed emission sites must not drift: the runtime value (`generateWebModule`), the `@happyvertical/smrt-virt-web` ambient d.ts (`vite-plugin/index.ts`), the physical `@smrt/web` d.ts (`prebuild/index.ts`), and the hand-written type mirror in `@happyvertical/smrt-web` (`packages/smrt-web/src/index.ts` — dependency-free, so textual sync only).\n\n`webMcpToolDefinitions` is deliberately outside that digest: tool-only route,\nidentifier, or annotation changes cannot alter persisted row hydration.\n\nPer-field web emission (#2046): `buildWebFieldDefinitions` carries `description` (from `@field({ description })`) and sanitized `ui` hints (from `@field({ ui: { basic, group, order, locked } })`, read off the manifest `_meta.ui` bag through per-key type guards) into each emitted field definition, and `buildWebToolDescriptors` threads the same `description` into browser MCP tool schemas. `sensitive`/`transient` fields are excluded from emission entirely, so their descriptions never ship. Both keys are conditional, so hint-less schemas emit byte-identical definitions (and hashes) as before; adding a description/ui hint changes the manifest hash — deliberate over-invalidation, harmless per the #1764 contract.\n\n## Generated MCP server output language\n\n`MCPGenerator` builds every file as TypeScript, so the requested `outputPath`\nextension decides what is written (#2279). `.ts`/`.mts` targets keep the source\nverbatim for `tsx` or Node type stripping — which is why the generated source\nmust stay erasable-syntax-only (no parameter properties, enums, or namespaces).\nEvery other target (`.smrt/mcp-server/index.js` by default) is transpiled to\nJavaScript with lazily loaded `oxc-transform` before writing, because the\nprinted run script and the generated `claude-config.example.json` both invoke\nit with plain `node`. Ordinary core imports and `.ts`/`.mts` output therefore\ndo not load OXC's native bindings.\nThis keeps `typescript` dev-only in `@happyvertical/smrt-core`; generated MCP\nsource must remain erasable-syntax-only. A `.cjs`/`.cts` target is rejected\noutright: generated servers are ES modules. `src/generators/mcp-emit.ts` owns\nthose decisions — do not reintroduce a bare `writeFile` of generated source.\n\nModular output writes `config`, `tools/index`, and `handlers/index` with the\nentry point's own extension, and emits the entry's relative import specifiers\nwith that same extension, so the files it imports both exist and load with the\nsame module semantics — an `.mjs` entry gets `.mjs` siblings, not `.js` ones a\nCommonJS package would then parse as CommonJS. The entry is written at the\nrequested path rather than a hardcoded `index.js`.\nGenerated code also has to be valid in an ES module: `arguments` is not a legal\nbinding name there, however convenient it reads.\n\n## Browser-plane playbook preflight route (#2590)\n\n`GET {basePath}/_preflight?key=<playbook key>` (`src/generators/preflight-route.ts`)\nis an advisory, read-effect, idempotent report of what a caller's playbook would\nbe allowed to do — capability *selection*, never authorization. Resolution and\nverdict shaping live in `@happyvertical/smrt-playbooks`, which depends on this\npackage, so core takes the evaluator as the `APIConfig.playbookPreflight` seam and\nthe dependency stays one-way. Without a provider the route 404s.\n\n**`authMiddleware` is never invoked by preflight**, and that is enforced\nstructurally rather than by discipline: `PlaybookPreflightRouteOptions` has no\nauth member of any kind, and `rest.ts` passes the boolean `appAuthConfigured`\ninstead — so there is no handle in the module to invoke by mistake. A synthetic-\n`Request` dry run is explicitly not an option: the middleware is request-bound,\nreturns a `Response` rather than a boolean, and may consult session stores,\nrate-limit, or audit. The app-auth layer therefore reports `unknown`, which is the\nhonest answer, and a future `authPredicate` seam can fill it in without changing\nthe contract.\n\nThe static layers preflight predicts against are exported from the same module —\n`isApiActionEnabledForObject`, `isRestActionRoutable`, `isRestRoutePublic`,\n`restFieldReadPermissions`, `restMethodForApiAction`,\n`resolveRegisteredObjectName` — and `APIGenerator`'s own\n`isApiActionEnabled` / `isRoutePublic` now delegate to them, so the route and the\nprediction of the route cannot drift. Exposure and existence are separate\nquestions: `include`/`exclude` gate a route, they do not conjure one, so\n`isRestActionRoutable` additionally requires a custom action to be declared in\n`api.routes` — the only map `dispatchCustomCollectionAction` iterates. A custom\naction is predicted against the verb its own route config declares, so a\n`public: 'read'` opt-out neither silently covers a `POST` action nor falsely\ndenies a declared `GET` one. Every unresolvable key returns the provider's single uniform\n\"unavailable\" body with an unconditional 200: unknown and unauthorized keys are\nindistinguishable at the HTTP layer too.\n\n## Emitted agent surface (#2591)\n\nGenerated model tools have always been build-time artifacts — virtual module,\nmanifest, knowledge graph. View intents (#2588) and playbooks (#2589) existed\nonly once something mounted, so \"what can an agent do in this app\" had no answer\nshort of enumerating every route. This closes that.\n\nThe same OXC scan that builds the manifest also runs the scanner's\nagent-surface matcher (`ScanResults.agentSurface`). `smrtPlugin()` captures it\nin `scanWithOxc`, projects it with `toKnowledgeAgentSurface`, and passes it to\n`buildDomainKnowledgeManifest` as `agentSurface`. Note that declaration\ndiscovery is NOT bound to the plugin's `include` glob — an app that scans\n`src/lib/objects/**` for models still has its `src/lib/agent/*.intents.ts`\nsidecars found (see `packages/scanner/AGENTS.md`). Two more consequences worth\nholding onto:\n\n- **It never touches `manifest.json`.** The runtime manifest stays\n runtime-focused; the agent-addressable surface is an agent/developer contract,\n so it lands in `.smrt/smrt-knowledge.json` and `dist/smrt-knowledge.json`\n only, under `agentSurface: { intents, playbooks, diagnostics }`.\n- **It is passed in, not scanned in `knowledge.ts`.** The scanner carries a\n native parser binary and `smrt-core`'s main entry is browser-reachable, so\n core's sync knowledge builder must not import it. The Vite plugin already\n imports the scanner lazily on the Node side and is the only caller that writes\n this artifact.\n\nThe field is **omitted entirely** when a package declares nothing, which is what\nmakes it additive in practice rather than only on paper: every existing\npackage's checked-in artifact stays byte-identical.\n\nEach declaring module gets a `sourceHashes` entry under the\n`agentSurface:<package-relative path>` prefix (`AGENT_SURFACE_HASH_PREFIX`), so\nEDITING an intent sidecar marks the artifact stale exactly like editing\n`AGENTS.md` does (`stale-domain-knowledge`).\n\nHashes alone cannot see an **added** declaration, though: a brand-new sidecar\nhas no recorded hash to mismatch, the runtime manifest never carries intents,\nand `AGENTS.md` is untouched — so every other signal stays green while the\nartifact omits a real operation. `dev:knowledge-check` therefore also re-derives\nthe declaration SET from source and compares it to the artifact by identity,\nreporting either direction as `stale-agent-surface`. The scan is bounded like\nthe numeric-precision lint: `src` only, behind the scanner's token pre-filter.\n\nThat re-derivation must model what the EMITTER sees, not merely what is on\ndisk, or it reports drift no rebuild can clear. Which files count is decided by\nthe scanner's exported `isAgentSurfaceSourcePath` — the same predicate the\nemitter itself uses, never a list copied into the checker — and the per-file\nresults run through `mergeAgentSurfaces` before comparing, because the merge is\nwhere a duplicate identity and a derived tool-name collision are resolved and\nthe artifact is the merged result.\nDiagnostics are compared alongside identities: a sidecar containing only a\ncomputed declaration adds no identity and has no prior hash, so without that,\n\"a diagnostic, never silence\" would quietly become \"a diagnostic, until the\nartifact goes stale\". The walk covers `<pkg>/src` while the emitter globs the\nwhole project root, so an emitted entry from outside `src` is not reported as\nmissing — this check did not look there, and claiming otherwise would be an\nerror nothing could clear.\n\nBoth `stale-*` codes are warnings by default and errors under `--strict`, which\nis what CI runs. Alongside them: `agent-surface-missing-identity`,\n`agent-surface-duplicate-identity`, and `agent-surface-empty-playbook` are\nerrors, and `agent-surface-not-static` is a warning. A cross-file duplicate\narrives as a *diagnostic* rather than two entries — the scanner's merge already\ndropped the loser — so that diagnostic maps to the duplicate error rather than\nthe not-static warning; otherwise the error would be unreachable for the case it\nexists to catch.\n\n`smrt doctor` prints the whole surface — model tools, intents, playbooks — from\nthese artifacts alone, with no application running.\n\n## Custom-action contract\n\n`resolveCustomActionMetadata()` is the common discovery and invocation contract\nfor generated REST routes and API clients, MCP, CLI, WebMCP, and simple\nREST-resource discovery. Receiver scope comes from the executable method, never a\nconfiguration-only `api.routes[name].scope` override: instance model methods\nare item-scoped and require `id`; static model methods and recognized\n`SmrtCollection` methods are collection-scoped and do not accept `id`. Route\nconfiguration may still choose its path and HTTP verb, but it cannot turn an\ninstance call into `ClassRef.action` or vice versa.\n\nWhen scanner method metadata exists, discovery projects each named parameter\nand its JSON-schema type, and invokers pass the values positionally in declared\norder. The legacy single `options` bag remains compatible when metadata is\nabsent (or the declared method takes `options`). Do not infer this from runtime\nfunction arity. An omitted typed `options` parameter remains `undefined`, so a\nmethod's JavaScript default initializer continues to apply; an explicit `null`\nremains `null`. Flat tool and CLI inputs reserve `id` for receiver parsing. If\nan action declares an `id` parameter, its flat MCP/WebMCP field is `actionId`\n(and CLI uses `--action-id`); REST keeps its independent path/body\nnamespaces. Typed CLI actions may use standard flag names such as `limit`,\n`offset`, `where`, and `format` without those values being stripped as CRUD\nflags.\n\nCustom actions may return an explicit, domain-neutral failure object with\n`ok: false`, `code`, and `message` plus optional `status`, `details`,\n`retryable`, and `correlationId`. `normalizeCustomActionFailure()` redacts it;\ngenerated REST returns `{ error: failure }` with the non-2xx status, while MCP\nreturns `isError: true` and `_meta['io.happyvertical/smrt']`. Opaque successful\nobjects (including `{ code, message }`) remain untouched; thrown exceptions are\nnot reclassified as domain failures.\n\nCustom route metadata also classifies browser-tool effects. Set `effect` to\n`read`, `write`, or `destructive`, with truthful `idempotent` and `openWorld`\nflags. CRUD classification is fixed: list/get are read, create/update are write,\nand delete is destructive. An undeclared custom action deliberately defaults to\ndestructive, non-idempotent, and open-world so a browser capability policy never\nfails open.\n\nGenerated reads (`list`/`get`) on the REST and SvelteKit generators support conditional GET (helpers in `src/generators/conditional-get.ts`). ETag v2 (#1765): the validator is the table's change-feed version (`getTableVersion`) keyed by the request representation, so a **concrete** `If-None-Match` short-circuits into a 304 with an empty body **before** the collection query runs — an unchanged table revalidates with zero table scan. A wildcard `If-None-Match: *` is deferred until the payload builds (existence confirmed), so a missing item still returns 404, not a false 304. Tenant-scoped reads fold the active tenant into the representation (`resolveTenantEtagDiscriminator`) so one tenant's cached validator never satisfies another's read of the same URL. Routes whose GET renders via a **custom serializer** (which can load related tables the base-table version can't observe) keep the v1 body-hash ETag (`#1757`, query-first but correct); the default `toPublicJSON` path — all REST reads and non-serializer SvelteKit reads — uses v2. v2 is weakly consistent by design (the cost of not reading the data): a revalidation in the sub-statement window between a committed write and its feed append can return a stale 304 that self-heals on the next revalidation. The other v2 window — a deploy that changes the response shape WITHOUT a table write — is closed by the **#1764 ETag salt**: `computeTableVersionEtag(version, representation, manifestHash?)` folds the build's web-collection shape digest into the digest, so a shape-only redeploy busts every read validator (`undefined` reproduces the pre-#1764 unsalted value byte-for-byte for direct helper callers). The generated SvelteKit route bakes the digest in as a `MANIFEST_HASH` constant (via `generateConditionalGetRouteHelper`'s `manifestHash` option, sourced from `computeWebManifestHash(manifest)`) — automatic for the SvelteKit transport. The runtime `APIGenerator` auto-populates the same salt from the runtime registry with `computeRuntimeWebManifestHash()` when `APIConfig.manifestHash` is omitted; explicit `APIConfig.manifestHash` still wins for custom setups. The digest scope is get-OR-list (`selectWebEtagSaltEntries`), so **get-only** routes are salted too. Strong consistency still requires the v1 body-hash path. Cache-Control policy (unchanged from #1757): `private, no-cache` by default; public models may opt into shared caching via `@smrt({ api: { public: true | 'read', cache: { sMaxage } } })` → `public, max-age=0, s-maxage=<n>`; non-public models never emit shared-cache headers. Tenant-scoped models (any mode) never emit them either — bodies vary with session-cookie tenant context that URL-keyed shared caches cannot see; `sMaxage` is neutralized to `private, no-cache` with a one-time warning.\n"
1029
+ "content": "# smrt-core/code generators\n\nModule semantics for `src/generators/` + `src/vite-plugin/`. Package orientation, the cross-module\ninvariants, and the traps that apply before editing anything live in\n[../AGENTS.md](../AGENTS.md) — read that first.\n\n## Code Generators\n\n| Generator | Location | Output |\n|-----------|----------|--------|\n| REST API | `src/generators/rest.ts` | OpenAPI-compliant CRUD endpoints |\n| MCP Server | `src/generators/mcp.ts` | Model Context Protocol tools |\n| Web collections | `src/vite-plugin/web-collections.ts` (selectors) + `generateWebModule` | `@happyvertical/smrt-virt-web` — one typed collection definition per API-exposed REST collection (#1761), consumed by `@happyvertical/smrt-web` |\n\nThe same web virtual module exports `webMcpToolDefinitions` (#2518), a\ncanonical per-tool array selected independently of list materialization. Every\nnon-empty canonical API action set contributes tools, so get-only and\ncustom-action-only models are discoverable; custom actions declared on a\n`SmrtCollection` merge into the owning row collection. Each definition carries\ncomplete route and invalidation metadata. `collectionDefinitions` and its\nembedded descriptor copy remain unchanged for existing cache-backed consumers.\n\nGenerated API clients share `selectApiClientEntries()` across the runtime Vite\nmodule, its ambient declaration, and physical prebuild declarations. When a\ncollection class and its populated model share an endpoint, the model owns the\ncanonical collection key and row payload schema; the collection class remains\navailable under a deterministic class-derived secondary key. Selection and\ncollision suffixes must not depend on manifest insertion order (#2027).\nFor aggregated manifests, inheritance and item-type references resolve exact\nqualified names first, then package-local simple names, then a stable identity\nfallback so duplicate class names across packages cannot reintroduce ordering.\n\nThe web module also emits a build-time **`manifestHash`** constant (#1764): `computeWebManifestHash(manifest)` is a deterministic, replica-stable digest of the emitted web-collection SHAPE (name/className/endpoint/idField/actions/fields/relationships), canonicalized (recursive key sort) before `sha256 → base64url`, truncated to 16 chars — so the same schema always hashes the same, and a field add/remove/type-change/edge-change changes it. A change means old persisted client rows may mis-hydrate, so smrt-web keys its durable persistence namespace on it and its `updateAvailable` contract signal compares against it. Four co-managed emission sites must not drift: the runtime value (`generateWebModule`), the `@happyvertical/smrt-virt-web` ambient d.ts (`vite-plugin/index.ts`), the physical `@smrt/web` d.ts (`prebuild/index.ts`), and the hand-written type mirror in `@happyvertical/smrt-web` (`packages/smrt-web/src/index.ts` — dependency-free, so textual sync only).\n\n`webMcpToolDefinitions` is deliberately outside that digest: tool-only route,\nidentifier, or annotation changes cannot alter persisted row hydration.\n\nPer-field web emission (#2046): `buildWebFieldDefinitions` carries `description` (from `@field({ description })`) and sanitized `ui` hints (from `@field({ ui: { basic, group, order, locked } })`, read off the manifest `_meta.ui` bag through per-key type guards) into each emitted field definition, and `buildWebToolDescriptors` threads the same `description` into browser MCP tool schemas. `sensitive`/`transient` fields are excluded from emission entirely, so their descriptions never ship. Both keys are conditional, so hint-less schemas emit byte-identical definitions (and hashes) as before; adding a description/ui hint changes the manifest hash — deliberate over-invalidation, harmless per the #1764 contract.\n\n## Generated MCP server output language\n\n`MCPGenerator` builds every file as TypeScript, so the requested `outputPath`\nextension decides what is written (#2279). `.ts`/`.mts` targets keep the source\nverbatim for `tsx` or Node type stripping — which is why the generated source\nmust stay erasable-syntax-only (no parameter properties, enums, or namespaces).\nEvery other target (`.smrt/mcp-server/index.js` by default) is transpiled to\nJavaScript with lazily loaded `oxc-transform` before writing, because the\nprinted run script and the generated `claude-config.example.json` both invoke\nit with plain `node`. Ordinary core imports and `.ts`/`.mts` output therefore\ndo not load OXC's native bindings.\nThis keeps `typescript` dev-only in `@happyvertical/smrt-core`; generated MCP\nsource must remain erasable-syntax-only. A `.cjs`/`.cts` target is rejected\noutright: generated servers are ES modules. `src/generators/mcp-emit.ts` owns\nthose decisions — do not reintroduce a bare `writeFile` of generated source.\n\nModular output writes `config`, `tools/index`, and `handlers/index` with the\nentry point's own extension, and emits the entry's relative import specifiers\nwith that same extension, so the files it imports both exist and load with the\nsame module semantics — an `.mjs` entry gets `.mjs` siblings, not `.js` ones a\nCommonJS package would then parse as CommonJS. The entry is written at the\nrequested path rather than a hardcoded `index.js`.\nGenerated code also has to be valid in an ES module: `arguments` is not a legal\nbinding name there, however convenient it reads.\n\n## Browser-plane playbook preflight route (#2590)\n\n`GET {basePath}/_preflight?key=<playbook key>` (`src/generators/preflight-route.ts`)\nis an advisory, read-effect, idempotent report of what a caller's playbook would\nbe allowed to do — capability *selection*, never authorization. Resolution and\nverdict shaping live in `@happyvertical/smrt-playbooks`, which depends on this\npackage, so core takes the evaluator as the `APIConfig.playbookPreflight` seam and\nthe dependency stays one-way. Without a provider the route 404s.\n\n**`authMiddleware` is never invoked by preflight**, and that is enforced\nstructurally rather than by discipline: `PlaybookPreflightRouteOptions` has no\nauth member of any kind, and `rest.ts` passes the boolean `appAuthConfigured`\ninstead — so there is no handle in the module to invoke by mistake. A synthetic-\n`Request` dry run is explicitly not an option: the middleware is request-bound,\nreturns a `Response` rather than a boolean, and may consult session stores,\nrate-limit, or audit. The app-auth layer therefore reports `unknown`, which is the\nhonest answer, and a future `authPredicate` seam can fill it in without changing\nthe contract.\n\nThe static layers preflight predicts against are exported from the same module —\n`isApiActionEnabledForObject`, `isRestActionRoutable`, `isRestRoutePublic`,\n`restFieldReadPermissions`, `restMethodForApiAction`,\n`resolveRegisteredObjectName` — and `APIGenerator`'s own\n`isApiActionEnabled` / `isRoutePublic` now delegate to them, so the route and the\nprediction of the route cannot drift. Exposure and existence are separate\nquestions: `include`/`exclude` gate a route, they do not conjure one, so\n`isRestActionRoutable` additionally requires a custom action to be declared in\n`api.routes` — the only map `dispatchCustomCollectionAction` iterates. A custom\naction is predicted against the verb its own route config declares, so a\n`public: 'read'` opt-out neither silently covers a `POST` action nor falsely\ndenies a declared `GET` one. Every unresolvable key returns the provider's single uniform\n\"unavailable\" body with an unconditional 200: unknown and unauthorized keys are\nindistinguishable at the HTTP layer too.\n\n## Emitted agent surface (#2591)\n\nGenerated model tools have always been build-time artifacts — virtual module,\nmanifest, knowledge graph. View intents (#2588) and playbooks (#2589) existed\nonly once something mounted, so \"what can an agent do in this app\" had no answer\nshort of enumerating every route. This closes that.\n\nThe same OXC scan that builds the manifest also runs the scanner's\nagent-surface matcher (`ScanResults.agentSurface`). `smrtPlugin()` captures it\nin `scanWithOxc`, projects it with `toKnowledgeAgentSurface`, and passes it to\n`buildDomainKnowledgeManifest` as `agentSurface`. Note that declaration\ndiscovery is NOT bound to the plugin's `include` glob — an app that scans\n`src/lib/objects/**` for models still has its `src/lib/agent/*.intents.ts`\nsidecars found (see `packages/scanner/AGENTS.md`). Two more consequences worth\nholding onto:\n\n- **It never touches `manifest.json`.** The runtime manifest stays\n runtime-focused; the agent-addressable surface is an agent/developer contract,\n so it lands in `.smrt/smrt-knowledge.json` and `dist/smrt-knowledge.json`\n only, under `agentSurface: { intents, playbooks, diagnostics }`.\n- **It is passed in, not scanned in `knowledge.ts`.** The scanner carries a\n native parser binary and `smrt-core`'s main entry is browser-reachable, so\n core's sync knowledge builder must not import it. The Vite plugin already\n imports the scanner lazily on the Node side and is the only caller that writes\n this artifact.\n\nThe field is **omitted entirely** when a package declares nothing, which is what\nmakes it additive in practice rather than only on paper: every existing\npackage's checked-in artifact stays byte-identical.\n\nEach declaring module gets a `sourceHashes` entry under the\n`agentSurface:<package-relative path>` prefix (`AGENT_SURFACE_HASH_PREFIX`), so\nEDITING an intent sidecar marks the artifact stale exactly like editing\n`AGENTS.md` does (`stale-domain-knowledge`).\n\nHashes alone cannot see an **added** declaration, though: a brand-new sidecar\nhas no recorded hash to mismatch, the runtime manifest never carries intents,\nand `AGENTS.md` is untouched — so every other signal stays green while the\nartifact omits a real operation. `dev:knowledge-check` therefore also re-derives\nthe declaration SET from source and compares it to the artifact by identity,\nreporting either direction as `stale-agent-surface`. The scan is bounded like\nthe numeric-precision lint: `src` only, behind the scanner's token pre-filter.\n\nThat re-derivation must model what the EMITTER sees, not merely what is on\ndisk, or it reports drift no rebuild can clear. Which files count is decided by\nthe scanner's exported `isAgentSurfaceSourcePath` — the same predicate the\nemitter itself uses, never a list copied into the checker — and the per-file\nresults run through `mergeAgentSurfaces` before comparing, because the merge is\nwhere a duplicate identity and a derived tool-name collision are resolved and\nthe artifact is the merged result.\nDiagnostics are compared alongside identities: a sidecar containing only a\ncomputed declaration adds no identity and has no prior hash, so without that,\n\"a diagnostic, never silence\" would quietly become \"a diagnostic, until the\nartifact goes stale\". The walk covers `<pkg>/src` while the emitter globs the\nwhole project root, so an emitted entry from outside `src` is not reported as\nmissing — this check did not look there, and claiming otherwise would be an\nerror nothing could clear.\n\nBoth `stale-*` codes are warnings by default and errors under `--strict`, which\nis what CI runs. Alongside them: `agent-surface-missing-identity`,\n`agent-surface-duplicate-identity`, and `agent-surface-empty-playbook` are\nerrors, and `agent-surface-not-static` is a warning. A cross-file duplicate\narrives as a *diagnostic* rather than two entries — the scanner's merge already\ndropped the loser — so that diagnostic maps to the duplicate error rather than\nthe not-static warning; otherwise the error would be unreachable for the case it\nexists to catch.\n\n`smrt doctor` prints the whole surface — model tools, intents, playbooks — from\nthese artifacts alone, with no application running.\n\n## Custom-action contract\n\n`resolveCustomActionMetadata()` is the common discovery and invocation contract\nfor generated REST routes and API clients, MCP, CLI, WebMCP, and simple\nREST-resource discovery. Receiver scope comes from the executable method, never a\nconfiguration-only `api.routes[name].scope` override: instance model methods\nare item-scoped and require `id`; static model methods and recognized\n`SmrtCollection` methods are collection-scoped and do not accept `id`. Route\nconfiguration may still choose its path and HTTP verb, but it cannot turn an\ninstance call into `ClassRef.action` or vice versa.\n\nWhen scanner method metadata exists, discovery projects each named parameter\nand its JSON-schema type, and invokers pass the values positionally in declared\norder. The legacy single `options` bag remains compatible when metadata is\nabsent (or the declared method takes `options`). Do not infer this from runtime\nfunction arity. An omitted typed `options` parameter remains `undefined`, so a\nmethod's JavaScript default initializer continues to apply; an explicit `null`\nremains `null`. Flat tool and CLI inputs reserve `id` for receiver parsing. If\nan action declares an `id` parameter, its flat MCP/WebMCP field is `actionId`\n(and CLI uses `--action-id`); REST keeps its independent path/body\nnamespaces. Typed CLI actions may use standard flag names such as `limit`,\n`offset`, `where`, and `format` without those values being stripped as CRUD\nflags.\n\nCustom actions may return an explicit, domain-neutral failure object with\n`ok: false`, `code`, and `message` plus optional `status`, `details`,\n`retryable`, and `correlationId`. `normalizeCustomActionFailure()` redacts it;\ngenerated REST returns `{ error: failure }` with the non-2xx status, while MCP\nreturns `isError: true` and `_meta['io.happyvertical/smrt']`. Opaque successful\nobjects (including `{ code, message }`) remain untouched; thrown exceptions are\nnot reclassified as domain failures.\n\nCustom route metadata also classifies browser-tool effects. Set `effect` to\n`read`, `write`, or `destructive`, with truthful `idempotent` and `openWorld`\nflags. CRUD classification is fixed: list/get are read, create/update are write,\nand delete is destructive. An undeclared custom action deliberately defaults to\ndestructive, non-idempotent, and open-world so a browser capability policy never\nfails open.\n\nGenerated reads (`list`/`get`) on the REST and SvelteKit generators support conditional GET (helpers in `src/generators/conditional-get.ts`). ETag v2 (#1765): the validator is the table's change-feed version (`getTableVersion`) keyed by the request representation, so a **concrete** `If-None-Match` short-circuits into a 304 with an empty body **before** the collection query runs — an unchanged table revalidates with zero table scan. A wildcard `If-None-Match: *` is deferred until the payload builds (existence confirmed), so a missing item still returns 404, not a false 304. Tenant-scoped reads fold the active tenant into the representation (`resolveTenantEtagDiscriminator`) so one tenant's cached validator never satisfies another's read of the same URL. Routes whose GET renders via a **custom serializer** (which can load related tables the base-table version can't observe) keep the v1 body-hash ETag (`#1757`, query-first but correct); the default `toPublicJSON` path — all REST reads and non-serializer SvelteKit reads — uses v2. v2 is weakly consistent by design (the cost of not reading the data): a revalidation in the sub-statement window between a committed write and its feed append can return a stale 304 that self-heals on the next revalidation. The other v2 window — a deploy that changes the response shape WITHOUT a table write — is closed by the **#1764 ETag salt**: `computeTableVersionEtag(version, representation, manifestHash?)` folds the build's web-collection shape digest into the digest, so a shape-only redeploy busts every read validator (`undefined` reproduces the pre-#1764 unsalted value byte-for-byte for direct helper callers). The generated SvelteKit route bakes the digest in as a `MANIFEST_HASH` constant (via `generateConditionalGetRouteHelper`'s `manifestHash` option, sourced from `computeWebManifestHash(manifest)`) — automatic for the SvelteKit transport. The runtime `APIGenerator` auto-populates the same salt from the runtime registry with `computeRuntimeWebManifestHash()` when `APIConfig.manifestHash` is omitted; explicit `APIConfig.manifestHash` still wins for custom setups. The digest scope is get-OR-list (`selectWebEtagSaltEntries`), so **get-only** routes are salted too. Strong consistency still requires the v1 body-hash path. Cache-Control policy (unchanged from #1757): `private, no-cache` by default; public models may opt into shared caching via `@smrt({ api: { public: true | 'read', cache: { sMaxage } } })` → `public, max-age=0, s-maxage=<n>`; non-public models never emit shared-cache headers. Tenant-scoped models (any mode) never emit them either — bodies vary with session-cookie tenant context that URL-keyed shared caches cannot see; `sMaxage` is neutralized to `private, no-cache` with a one-time warning.\n"
1030
1030
  },
1031
1031
  {
1032
1032
  "path": "agents/build-knowledge.md",
@@ -53,7 +53,12 @@ export declare function resolveTestDatabaseDDLEngine(type: TestDatabaseOptions['
53
53
  * - Uses `SchemaGenerator.generateSQL()` - the single source of truth for DDL
54
54
  * - Handles STI (Single Table Inheritance) correctly
55
55
  * - Creates system tables for framework functionality
56
- * - Safe for parallel test execution (each call creates isolated instance)
56
+ * - Safe for parallel test execution: each call creates an isolated
57
+ * in-memory instance with its own embedded write-queue identity, so
58
+ * unrelated `:memory:` databases never serialize writes against each
59
+ * other (#2707). A `cache=shared` URL is the deliberate exception: it
60
+ * asks SQLite/DuckDB to genuinely share the underlying database, so it
61
+ * keeps sharing one write-queue identity too.
57
62
  *
58
63
  * @param options - Configuration options
59
64
  * @returns Promise resolving to configured DatabaseInterface
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAwJ5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEjD;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACjC,EAAE,EAAE,iBAAiB,EACrB,iBAAiB,UAAQ,GACxB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAwC3C;AA4DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CA+M5B"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAyJ5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEjD;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACjC,EAAE,EAAE,iBAAiB,EACrB,iBAAiB,UAAQ,GACxB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAwC3C;AA4DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,iBAAiB,CAAC,CAiO5B"}