@happyvertical/smrt-core 0.49.8 → 0.51.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 (54) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/dispatch/bus.d.ts.map +1 -1
  3. package/dist/dispatch/bus.js +15 -12
  4. package/dist/dispatch/bus.js.map +1 -1
  5. package/dist/dispatch/collections/DispatchSubscriptions.d.ts +7 -2
  6. package/dist/dispatch/collections/DispatchSubscriptions.d.ts.map +1 -1
  7. package/dist/dispatch/collections/DispatchSubscriptions.js +9 -8
  8. package/dist/dispatch/collections/DispatchSubscriptions.js.map +1 -1
  9. package/dist/dispatch/collections/Dispatches.d.ts +12 -2
  10. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
  11. package/dist/dispatch/collections/Dispatches.js +14 -8
  12. package/dist/dispatch/collections/Dispatches.js.map +1 -1
  13. package/dist/dispatch/types.d.ts +16 -1
  14. package/dist/dispatch/types.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/knowledge-graph.d.ts +95 -0
  17. package/dist/knowledge-graph.d.ts.map +1 -0
  18. package/dist/knowledge-graph.js +268 -0
  19. package/dist/knowledge-graph.js.map +1 -0
  20. package/dist/knowledge.d.ts +1 -0
  21. package/dist/knowledge.d.ts.map +1 -1
  22. package/dist/knowledge.js +57 -4
  23. package/dist/knowledge.js.map +1 -1
  24. package/dist/manifest/static-manifest.js +1 -1
  25. package/dist/manifest/static-manifest.js.map +1 -1
  26. package/dist/manifest/store.js +1 -1
  27. package/dist/manifest.json +1 -1
  28. package/dist/migrations/backfill-tracker.d.ts +7 -0
  29. package/dist/migrations/backfill-tracker.d.ts.map +1 -1
  30. package/dist/migrations/backfill-tracker.js +20 -1
  31. package/dist/migrations/backfill-tracker.js.map +1 -1
  32. package/dist/migrations/differ.d.ts +50 -18
  33. package/dist/migrations/differ.d.ts.map +1 -1
  34. package/dist/migrations/differ.js +136 -50
  35. package/dist/migrations/differ.js.map +1 -1
  36. package/dist/registry/types.d.ts +21 -1
  37. package/dist/registry/types.d.ts.map +1 -1
  38. package/dist/schema/live-parity.d.ts.map +1 -1
  39. package/dist/schema/live-parity.js +133 -36
  40. package/dist/schema/live-parity.js.map +1 -1
  41. package/dist/smrt-knowledge.json +12 -7
  42. package/dist/system/bootstrap.d.ts +23 -0
  43. package/dist/system/bootstrap.d.ts.map +1 -1
  44. package/dist/system/bootstrap.js +52 -17
  45. package/dist/system/bootstrap.js.map +1 -1
  46. package/dist/vite-plugin/index.d.ts +3 -1
  47. package/dist/vite-plugin/index.d.ts.map +1 -1
  48. package/dist/vite-plugin/index.js +9 -2
  49. package/dist/vite-plugin/index.js.map +1 -1
  50. package/dist/vite-plugin/sveltekit-generator.d.ts +26 -5
  51. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  52. package/dist/vite-plugin/sveltekit-generator.js +48 -14
  53. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  54. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"sveltekit-generator.js","names":[],"sources":["../../src/vite-plugin/sveltekit-generator.ts"],"sourcesContent":["/**\n * SvelteKit route auto-generation from SMRT objects\n * Generates real TypeScript files in src/routes/api/ based on discovered SMRT objects\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport type { DomainKnowledgeConfig } from '@happyvertical/smrt-types';\nimport { generateConditionalGetRouteHelper } from '../generators/conditional-get.js';\nimport {\n type ApiMethodExposure,\n CRUD_OPERATIONS,\n createManifestClassNamePredicate,\n declaredTypeAcceptsDate,\n isCrudOperation,\n queryStringDecoderFor,\n resolveApiMethodExposure,\n resolveCustomActionMetadata,\n resolveCustomActionNames,\n resolveDeclaredScopeMismatch,\n resolveEffectiveActionMetadata,\n type WireabilityOptions,\n} from '../generators/custom-action.js';\nimport {\n buildDefaultListOrderBy,\n DEFAULT_LIST_LIMIT,\n MAX_LIST_LIMIT,\n} from '../query-bounds.js';\nimport { isFrameworkBaseClass } from '../registry/framework-base-classes.js';\nimport type {\n ApiConfig,\n ApiHttpMethod,\n ApiSerializerReference,\n} from '../registry/types.js';\nimport type {\n MethodDefinition,\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nimport { generateChangesRoute } from './changes-route.js';\nimport {\n generateDevPlaneRoute,\n willGenerateDevPlaneRoute,\n} from './dev-plane-route.js';\nimport { generateEventsRoute } from './events-route.js';\nimport {\n generateResourcesRoute,\n reservesResourcesRoute,\n} from './resources-route.js';\nimport { AUTO_GENERATED_ROUTE_HEADER } from './route-header.js';\nimport { resolveSvelteKitConfigImport } from './sveltekit-config-import.js';\nimport { canonicalSvelteKitPath } from './sveltekit-path.js';\nimport {\n collectSyncApplyTargets,\n generateSyncApplyRoute,\n} from './sync-apply-route.js';\nimport {\n computeWebManifestHash,\n isCollectionManifestClass,\n orderedManifestObjectEntries,\n resolveCollectionItemObject,\n resolveCollectionItemTypeName,\n} from './web-collections.js';\n\nexport interface SvelteKitOptions {\n enabled: boolean;\n routesDir: string;\n objectsDir: string;\n configPath?: string; // default: 'src/lib/server'\n configFileName?: string; // default: 'smrt.ts'\n /** Internal absolute consumer registration entrypoints for a coordinated host. */\n consumerRegistrationPaths?: readonly string[];\n /**\n * Apply kebab-case to custom-method URL segments (e.g. `discoverFromUrl`\n * becomes `/discover-from-url`). Opt-in for one minor; default flips in the\n * next major. An explicit `api.routes[name].path` always wins over this.\n */\n kebabRoutes?: boolean;\n /** Domain knowledge API route generation. Disabled unless explicitly enabled. */\n knowledge?: DomainKnowledgeConfig;\n /**\n * Change-feed `_changes` route generation (#1758). Enabled by default\n * (the route is auth-guarded fail-closed); set `enabled: false` to skip.\n */\n changesRoute?: { enabled?: boolean };\n /**\n * Opt-in in-app runtime dev-plane route (`_dev/[...tool]`, #2782). Dev\n * mode only; requires `@happyvertical/smrt-dev-mcp` in the consumer and\n * `SMRT_DEV_MCP_TOKEN` at runtime.\n */\n devPlaneRoute?: { enabled?: boolean };\n /**\n * Live `_events` SSE route generation (#1763). Enabled by default (the route\n * is auth-guarded fail-closed, same-origin only); set `enabled: false` to\n * skip. `maxSubscribers` caps active streams per process (#1860); 0 means\n * unlimited.\n *\n * Cross-origin subscription (#1861) is opt-in and fail-closed: provide\n * `allowedOrigins` (an explicit allowlist — never `*`) and set\n * `allowCredentials: true` so an allow-listed browser client can subscribe\n * with a credentialed `EventSource` (`withCredentials: true`). The generated\n * route echoes the specific request `Origin` only when it is allow-listed,\n * adds `Access-Control-Allow-Credentials: true`, and otherwise stays\n * same-origin only. Auth (an authenticated principal on `locals`) is\n * unchanged — CORS only lets the cookie reach the guard.\n */\n eventsRoute?: {\n enabled?: boolean;\n maxSubscribers?: number;\n allowedOrigins?: string[];\n allowCredentials?: boolean;\n };\n /**\n * CLI discovery `_resources` route generation (#2663). Enabled by default,\n * but only ever emitted when `@happyvertical/smrt-users` is resolvable\n * from the consumer (see `resources-route.ts` for the detection\n * mechanism) — set `enabled: false` to opt out even when it is present. A\n * pre-existing hand-written `_resources` route is always preserved.\n */\n resourcesRoute?: { enabled?: boolean };\n /** Reject route paths owned by distinct selected identities before cleanup. */\n rejectRouteCollisions?: boolean;\n}\n\n// Keep this aligned with biome.json formatter.lineWidth.\nconst BIOME_LINE_WIDTH = 80;\nconst GITIGNORE_MANAGED_BLOCK_START =\n '# BEGIN SMRT auto-generated routes (Vite plugin)';\nconst GITIGNORE_MANAGED_BLOCK_END =\n '# END SMRT auto-generated routes (Vite plugin)';\nconst LEGACY_GITIGNORE_HEADER =\n '# SMRT auto-generated routes (from Vite plugin)';\n\nexport interface ResolvedApiActionRouteConfig {\n scope: 'item' | 'collection';\n method: ApiHttpMethod;\n pathSegments: string[];\n pathParamNames: string[];\n}\n\ninterface GeneratedActionRouteSpec {\n lookupClassName: string;\n lookupObjectDef?: SmartObjectDefinition;\n hostClassName: string;\n actionName: string;\n actionDef: MethodDefinition;\n routeConfig: ResolvedApiActionRouteConfig;\n hostType: 'item' | 'collection';\n}\n\ninterface ResolvedStandardRouteSerializers {\n importStatements: string[];\n itemSerializerName?: string;\n listItemSerializerName?: string;\n}\n\ninterface GeneratedTypeReference {\n typeName: string;\n importStatement?: string;\n}\n\n/**\n * Extract simple class name from potentially qualified name.\n * Qualified names follow the pattern: @scope/package:ClassName\n *\n * Issue #870: Manifests may contain qualified names which generate invalid\n * import statements like: import { @pkg:Class } from '@pkg'\n *\n * @param qualifiedName - Class name that may be qualified (e.g., \"@pkg:Class\" or \"Class\")\n * @returns Simple class name (e.g., \"Class\")\n */\nfunction extractSimpleClassName(qualifiedName: string): string {\n const colonIndex = qualifiedName.indexOf(':');\n if (colonIndex !== -1) {\n return qualifiedName.substring(colonIndex + 1);\n }\n return qualifiedName;\n}\n\n/**\n * Check if an object definition represents a SmrtCollection class.\n * Collection classes share route paths with their item class (via inherited `collection` field),\n * so generating routes for both would cause file collisions.\n */\nfunction isCollectionClass(objectDef: SmartObjectDefinition): boolean {\n return objectDef.extends === 'SmrtCollection' || !!objectDef.extendsTypeArg;\n}\n\nfunction getRegistrationPackageName(\n manifest: SmartObjectManifest,\n objectDef: SmartObjectDefinition,\n isLocal: boolean,\n): string | undefined {\n if (isLocal) {\n return objectDef.packageName ?? manifest.packageName;\n }\n\n return objectDef.packageName;\n}\n\nfunction toSingleQuotedStringLiteral(value: string): string {\n const jsonLiteral = JSON.stringify(value);\n const jsonContent = jsonLiteral.slice(1, -1).replaceAll(\"'\", \"\\\\'\");\n return `'${jsonContent}'`;\n}\n\nfunction getApiConfigObject(apiConfig: unknown): ApiConfig | null {\n if (!apiConfig || typeof apiConfig !== 'object') {\n return null;\n }\n\n return apiConfig as ApiConfig;\n}\n\nfunction isSameSerializerReference(\n left?: ApiSerializerReference,\n right?: ApiSerializerReference,\n): boolean {\n return (\n !!left &&\n !!right &&\n left.importPath === right.importPath &&\n left.exportName === right.exportName\n );\n}\n\nfunction resolveStandardRouteSerializers(\n apiConfig: unknown,\n): ResolvedStandardRouteSerializers {\n const config = getApiConfigObject(apiConfig);\n const itemSerializer = config?.serializers?.item;\n const listItemSerializer =\n config?.serializers?.listItem || config?.serializers?.item;\n\n const importStatements: string[] = [];\n let itemSerializerName: string | undefined;\n let listItemSerializerName: string | undefined;\n\n if (itemSerializer) {\n itemSerializerName = 'serializeItemResponse';\n importStatements.push(\n `import { ${itemSerializer.exportName} as ${itemSerializerName} } from '${itemSerializer.importPath}';`,\n );\n }\n\n if (listItemSerializer) {\n if (isSameSerializerReference(listItemSerializer, itemSerializer)) {\n listItemSerializerName = itemSerializerName;\n } else {\n listItemSerializerName = 'serializeListItemResponse';\n importStatements.push(\n `import { ${listItemSerializer.exportName} as ${listItemSerializerName} } from '${listItemSerializer.importPath}';`,\n );\n }\n }\n\n return {\n importStatements,\n itemSerializerName,\n listItemSerializerName,\n };\n}\n\nfunction isValidTypeIdentifier(name: string): boolean {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);\n}\n\nfunction resolveObjectTypeReference(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition | undefined,\n options: SvelteKitOptions,\n routeDir?: string,\n): GeneratedTypeReference {\n const simpleClassName = extractSimpleClassName(className);\n\n if (!objectDef || !isValidTypeIdentifier(simpleClassName)) {\n return { typeName: \"import('@happyvertical/smrt-core').SmrtObject\" };\n }\n\n const external =\n !isLocalObject(projectRoot, objectDef) && objectDef.packageName;\n const importPath = external\n ? objectDef.importPath || objectDef.packageName\n : getRouteTypeImportPath(\n projectRoot,\n objectDef,\n options,\n simpleClassName,\n routeDir,\n );\n const exportName = external\n ? objectDef.exportName || simpleClassName\n : simpleClassName;\n\n return {\n typeName: simpleClassName,\n importStatement: `import type { ${exportName}${exportName === simpleClassName ? '' : ` as ${simpleClassName}`} } from '${importPath}';`,\n };\n}\n\nfunction getRouteTypeImportPath(\n projectRoot: string,\n objectDef: SmartObjectDefinition,\n options: SvelteKitOptions,\n simpleClassName: string,\n routeDir?: string,\n): string {\n if (objectDef.filePath) {\n const srcLibDir = join(projectRoot, 'src/lib');\n if (objectDef.filePath.startsWith(`${srcLibDir}/`)) {\n const libRelative = relative(srcLibDir, objectDef.filePath)\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n return `$lib/${libRelative}`.replace(/\\/+/g, '/');\n }\n\n if (routeDir) {\n const routeRelative = relative(routeDir, objectDef.filePath)\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n return routeRelative.startsWith('.')\n ? routeRelative\n : `./${routeRelative}`;\n }\n }\n\n return getSvelteKitImportPath(\n projectRoot,\n objectDef.filePath,\n options.objectsDir,\n simpleClassName,\n );\n}\n\nfunction mergeImportStatements(\n importStatements: Array<string | undefined>,\n): string {\n return Array.from(new Set(importStatements.filter(Boolean))).join('\\n');\n}\n\nfunction findObjectDefByRegistryKey(\n manifest: SmartObjectManifest,\n className: string,\n): SmartObjectDefinition | undefined {\n return (\n manifest.objects[className] ??\n Object.values(manifest.objects).find(\n (objectDef) => objectDef.className === extractSimpleClassName(className),\n )\n );\n}\n\n/**\n * Collect property names marked `@field({ readonly: true })` for an object, so\n * the generated write surfaces can strip them from request bodies (#1540, 2b).\n */\nfunction collectReadonlyFieldNames(objectDef: SmartObjectDefinition): string[] {\n const fields = objectDef.fields || {};\n const names: string[] = [];\n for (const [name, def] of Object.entries(fields)) {\n const meta = (def as { _meta?: Record<string, unknown> })._meta;\n if (\n (def as { readonly?: boolean }).readonly === true ||\n meta?.readonly === true\n ) {\n names.push(name);\n }\n }\n return names;\n}\n\n/**\n * Resolve the optional `@smrt({ api: { writable: [...] } })` allowlist. When\n * present, only these fields may be set from a create/update request body.\n */\nfunction getApiWritableAllowlist(apiConfig: unknown): string[] | null {\n const config = getApiConfigObject(apiConfig);\n return Array.isArray(config?.writable) ? config.writable : null;\n}\n\n/**\n * Emit the mass-assignment guard helper injected into generated route files\n * (#1540, 2b). It strips framework/server-managed (`id`, `tenantId`,\n * timestamps, `_`-prefixed) and `@field({ readonly: true })` fields from\n * request bodies, and — when a `writable` allowlist is configured — intersects\n * with it. Applied to every generated `create`/`update` handler.\n */\nfunction generateWritablePolicyHelper(\n objectDef: SmartObjectDefinition,\n): string {\n const readonly = collectReadonlyFieldNames(objectDef);\n const writable = getApiWritableAllowlist(objectDef.decoratorConfig?.api);\n\n return `\n// Mass-assignment guard (#1540): strip framework/server-managed + read-only\n// fields from create/update request bodies before they reach the model.\nconst WRITABLE_ALLOWLIST: string[] | null = ${\n writable ? JSON.stringify(writable) : 'null'\n };\nconst READONLY_FIELDS: string[] = ${JSON.stringify(readonly)};\nconst SERVER_MANAGED_FIELDS = [\n 'id',\n 'tenantId',\n 'tenant_id',\n 'createdAt',\n 'created_at',\n 'updatedAt',\n 'updated_at',\n];\n\nfunction applyWritablePolicy(data: unknown): Record<string, unknown> {\n if (!data || typeof data !== 'object') return {};\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (key.startsWith('_')) continue;\n if (SERVER_MANAGED_FIELDS.includes(key)) continue;\n if (READONLY_FIELDS.includes(key)) continue;\n if (WRITABLE_ALLOWLIST && !WRITABLE_ALLOWLIST.includes(key)) continue;\n result[key] = value;\n }\n return result;\n}\n`;\n}\n\n/**\n * Resolve the `@smrt({ api: { public } })` posture (fail-closed default).\n * - `false`/unset → all routes require an authenticated principal.\n * - `true` → all routes are public.\n * - `'read'` → reads are public, mutations still require auth.\n */\nfunction getApiPublicAccess(apiConfig: unknown): boolean | 'read' {\n const config = getApiConfigObject(apiConfig);\n const value = config?.public;\n if (value === true || value === 'read') {\n return value;\n }\n return false;\n}\n\nfunction toFieldColumnAlias(fieldName: string): string {\n return fieldName\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/[-\\s]+/g, '_')\n .toLowerCase();\n}\n\nfunction manifestObjectKey(objectDef: SmartObjectDefinition): string {\n return objectDef.qualifiedName ?? objectDef.className;\n}\n\nfunction manifestObjectExtends(\n objectDef: SmartObjectDefinition,\n parent: SmartObjectDefinition,\n): boolean {\n const extendsQualified = objectDef.extendsQualified;\n const extendsName = objectDef.extends;\n return (\n (typeof extendsQualified === 'string' &&\n extendsQualified === parent.qualifiedName) ||\n (typeof extendsName === 'string' &&\n (extendsName === parent.className ||\n extendsName === parent.qualifiedName))\n );\n}\n\nfunction findManifestParent(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): SmartObjectDefinition | undefined {\n return Object.values(manifest.objects).find((candidate) =>\n manifestObjectExtends(objectDef, candidate),\n );\n}\n\nfunction collectStiHierarchyObjects(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): SmartObjectDefinition[] {\n if (!manifest) return [objectDef];\n\n let cursor: SmartObjectDefinition | undefined = objectDef;\n let stiBase: SmartObjectDefinition | undefined =\n cursor.decoratorConfig?.tableStrategy === 'sti' ? cursor : undefined;\n while (cursor) {\n const parent = findManifestParent(cursor, manifest);\n if (!parent) break;\n if (parent.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = parent;\n }\n cursor = parent;\n }\n\n if (!stiBase) return [objectDef];\n\n const members = new Map<string, SmartObjectDefinition>();\n const visit = (current: SmartObjectDefinition) => {\n const key = manifestObjectKey(current);\n if (members.has(key)) return;\n members.set(key, current);\n for (const candidate of Object.values(manifest.objects)) {\n if (candidate === current) continue;\n if (manifestObjectExtends(candidate, current)) {\n visit(candidate);\n }\n }\n };\n\n visit(stiBase);\n return [...members.values()];\n}\n\nfunction collectReadPermissionFields(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): Array<[string, string]> {\n const result: Array<[string, string]> = [];\n const seen = new Set<string>();\n for (const member of collectStiHierarchyObjects(objectDef, manifest)) {\n for (const [name, def] of Object.entries(member.fields ?? {})) {\n const permission =\n typeof def.readPermission === 'string'\n ? def.readPermission\n : typeof def._meta?.readPermission === 'string'\n ? def._meta.readPermission\n : undefined;\n if (!permission) continue;\n for (const fieldName of [name, toFieldColumnAlias(name)]) {\n const key = `${fieldName}\\0${permission}`;\n if (seen.has(key)) continue;\n seen.add(key);\n result.push([fieldName, permission]);\n }\n }\n }\n return result;\n}\n\n/**\n * Emit the fail-closed authorization guard injected into generated route files\n * (#1540, 2c). Every generated CRUD/action handler calls `requireRouteAuth`,\n * which throws 401 unless the route is `public` or `locals` carries an\n * authenticated principal. Mirrors the knowledge-route `isKnowledgeAdmin`\n * precedent. Mutating verbs require auth even when reads are public.\n */\nfunction generateAuthGuardHelper(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): string {\n const publicAccess = getApiPublicAccess(objectDef.decoratorConfig?.api);\n const readPermissionFields = collectReadPermissionFields(objectDef, manifest);\n\n return `\n// Fail-closed authorization (#1540): generated routes require an authenticated\n// principal on \\`locals\\` unless explicitly marked \\`@smrt({ api: { public } })\\`.\nconst PUBLIC_ACCESS: boolean | 'read' = ${JSON.stringify(publicAccess)};\nconst READ_PERMISSION_FIELDS: Array<[string, string]> = ${JSON.stringify(readPermissionFields)};\n\ninterface PublicJsonOptions {\n permissions?: Iterable<string>;\n}\n\nfunction hasAuthenticatedPrincipal(locals: unknown): boolean {\n if (!locals || typeof locals !== 'object') return false;\n const l = locals as Record<string, unknown>;\n // Only a resolved, object-shaped principal counts. We intentionally do NOT\n // treat \\`locals.auth\\` as a signal: Auth.js/SvelteKit put a callable\n // \\`auth()\\` helper on every request (including anonymous ones), so honoring\n // it would fail OPEN. Booleans don't count either (no convention sets\n // \\`locals.user = true\\`); the only boolean accepted is the explicit\n // \\`smrtAuth\\` opt-in marker.\n const isResolvedPrincipal = (v: unknown) =>\n typeof v === 'object' && v !== null;\n return (\n isResolvedPrincipal(l.user) ||\n isResolvedPrincipal(l.session) ||\n l.smrtAuth === true\n );\n}\n\nfunction requireRouteAuth(locals: unknown, mutating: boolean): void {\n if (PUBLIC_ACCESS === true) return;\n if (PUBLIC_ACCESS === 'read' && !mutating) return;\n if (!hasAuthenticatedPrincipal(locals)) {\n throw error(401, 'Authentication required');\n }\n}\n\nfunction getPublicJsonOptions(locals: unknown): PublicJsonOptions {\n const l = readJsonRecord(locals);\n const permissions = l.permissions ?? l.permissionSet ?? l.smrtPermissions;\n if (Array.isArray(permissions) || permissions instanceof Set) {\n return { permissions };\n }\n return {};\n}\n\nfunction hasReadPermission(\n options: PublicJsonOptions,\n permission: string,\n): boolean {\n if (!options.permissions) return false;\n for (const granted of options.permissions) {\n if (granted === permission) return true;\n }\n return false;\n}\n\nfunction applyReadPermissionRedaction(\n value: unknown,\n options: PublicJsonOptions,\n seen: WeakSet<object> = new WeakSet(),\n): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return null;\n if (hasPublicJson(value)) {\n seen.add(value);\n return applyReadPermissionRedaction(\n value.toPublicJSON(options),\n options,\n seen,\n );\n }\n if (Array.isArray(value)) {\n seen.add(value);\n return value.map((entry) =>\n applyReadPermissionRedaction(entry, options, seen),\n );\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n seen.add(value);\n const out = { ...(value as Record<string, unknown>) };\n const metaData =\n out._meta_data && typeof out._meta_data === 'object'\n ? { ...(out._meta_data as Record<string, unknown>) }\n : null;\n for (const [fieldName, permission] of READ_PERMISSION_FIELDS) {\n if (hasReadPermission(options, permission)) continue;\n delete out[fieldName];\n if (metaData) delete metaData[fieldName];\n }\n if (metaData) out._meta_data = metaData;\n for (const [key, entry] of Object.entries(out)) {\n out[key] = applyReadPermissionRedaction(entry, options, seen);\n }\n return out;\n}\n\n// Sensitive-field-safe serialization for custom-action results (#1540): a\n// custom method may return a SmrtObject (or one nested in an array/plain\n// object), so recurse and route each through toPublicJSON() rather than letting\n// JSON.stringify call toJSON(). Non-plain instances (Date, etc.) and primitives\n// pass through; a cycle guard prevents infinite loops.\ninterface PublicJsonSource {\n toPublicJSON(options?: PublicJsonOptions): unknown;\n}\n\nfunction hasPublicJson(value: object): value is PublicJsonSource {\n return (\n 'toPublicJSON' in value &&\n typeof (value as { toPublicJSON?: unknown }).toPublicJSON === 'function'\n );\n}\n\nfunction readJsonRecord(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return {};\n return value as Record<string, unknown>;\n}\n\nfunction toPublicResult(\n value: unknown,\n options: PublicJsonOptions,\n seen: WeakSet<object> = new WeakSet(),\n): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return null;\n if (hasPublicJson(value)) {\n seen.add(value);\n return toPublicResult(value.toPublicJSON(options), options, seen);\n }\n if (Array.isArray(value)) {\n seen.add(value);\n return value.map((entry) => toPublicResult(entry, options, seen));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(\n value as Record<string, unknown>,\n )) {\n out[key] = toPublicResult(entry, options, seen);\n }\n return out;\n}\n`;\n}\n\n/**\n * Whether an object is `@TenantScoped` (carries a `tenantScoped` config in its\n * `@smrt()`/`@TenantScoped()` decorator). Drives tenant-context establishment in\n * generated routes (#1540, facet 2).\n */\nfunction isTenantScoped(objectDef: SmartObjectDefinition): boolean {\n return !!objectDef.decoratorConfig?.tenantScoped;\n}\n\n/**\n * Whether generated routes must publish the authenticated principal into the\n * tenancy ALS without making the model itself tenant-scoped. This is an\n * explicit model-level opt-in: body data is never an identity source.\n */\nfunction usesPrincipalContext(objectDef: SmartObjectDefinition): boolean {\n const api = getApiConfigObject(objectDef.decoratorConfig?.api);\n return api?.principalContext === true;\n}\n\nfunction needsRouteTenantContext(objectDef: SmartObjectDefinition): boolean {\n return isTenantScoped(objectDef) || usesPrincipalContext(objectDef);\n}\n\n/**\n * Emit the page-bounds guard and the deterministic ordering constant for a\n * generated list route (#2367).\n *\n * The route used to parse its own bounds with\n * `Number(url.searchParams.get('limit')) || 50`, which has three faults: it\n * accepts `NaN` from any non-numeric input and binds it (PostgreSQL answers\n * `invalid input syntax for type bigint` — a 500 for a caller typo), it folds a\n * deliberate `limit=0` into 50, and it has no ceiling, so `?limit=100000000` is\n * a full table scan plus a full hydration pass on a public endpoint.\n *\n * The helper is emitted into the route rather than imported from\n * `@happyvertical/smrt-core` so the generated file stays readable on its own and\n * the bound is visible at the call site; the constants come from core so there\n * is still one source of truth.\n */\nfunction generateListBoundsHelper(objectDef: SmartObjectDefinition): string {\n const orderBy = resolveDefaultListOrderBy(objectDef);\n return `\n/** Deterministic list ordering (#2367); matching index is #2363. */\nconst LIST_ORDER_BY = ${JSON.stringify(orderBy)};\n\n/**\n * Parse \\`?limit\\`/\\`?offset\\` (#2367): default when absent, 400 when malformed,\n * clamped to ${MAX_LIST_LIMIT} when oversized.\n */\nfunction listBounds(url: URL): { limit: number; offset: number } {\n const parse = (name: 'limit' | 'offset', fallback: number, max?: number): number => {\n const raw = url.searchParams.get(name);\n if (raw === null || raw === '') {\n return max === undefined ? fallback : Math.min(fallback, max);\n }\n if (!/^\\\\d+$/.test(raw.trim())) {\n throw error(400, \\`Invalid \\${name}: '\\${raw}' is not a non-negative integer.\\`);\n }\n const value = Number(raw.trim());\n if (!Number.isSafeInteger(value)) {\n throw error(400, \\`Invalid \\${name}: '\\${raw}' is not a non-negative integer.\\`);\n }\n return max === undefined ? value : Math.min(value, max);\n };\n\n return {\n limit: parse('limit', ${DEFAULT_LIST_LIMIT}, ${MAX_LIST_LIMIT}),\n offset: parse('offset', 0),\n };\n}\n`;\n}\n\n/**\n * Deterministic default ordering for a generated list route (#2367).\n *\n * The list route pages with `LIMIT`/`OFFSET` and previously emitted no\n * `ORDER BY` at all. That is not pagination: without an ordering PostgreSQL may\n * return rows in any order and is free to pick a different one per query, so\n * page 2 can repeat rows from page 1 and skip others entirely — silently, and\n * only under concurrency or a plan change, which is why it survived review.\n *\n * `created_at DESC` alone is not enough (rows created in the same tick tie), so\n * the primary key follows as a total-order tiebreak. The matching index is\n * #2363.\n */\nfunction resolveDefaultListOrderBy(\n objectDef: SmartObjectDefinition,\n): readonly string[] {\n // A class declaring its own primary key has no `id` column to tie-break on\n // (`id`/`slug`/`context` are omitted for custom-PK classes), so order by the\n // declared key instead.\n //\n // The flag is read from BOTH `_meta.primaryKey` and the top level: scanner\n // manifests — the input this generator actually runs on — carry it under\n // `_meta`, while decorator option bags mirror some flags at the top level.\n // Checking only the top level silently never matches, which is exactly the\n // case that would emit an `id` tiebreak for a table without an `id` column.\n const customPrimaryKey = Object.entries(objectDef.fields ?? {}).find(\n ([, fieldDef]) =>\n fieldDef?._meta?.primaryKey === true ||\n (fieldDef as { primaryKey?: boolean } | undefined)?.primaryKey === true,\n )?.[0];\n\n return buildDefaultListOrderBy(customPrimaryKey);\n}\n\n/**\n * Emit the tenant-context establishment + fail-closed read-scope helpers for\n * `@TenantScoped` objects (#1540 facet 2; #1782). Generated handlers call\n * `establishTenantContext(locals)` after the auth guard so every query runs\n * inside the tenant context derived from the authenticated principal — engaging\n * the `@TenantScoped` interceptors that auto-filter by tenant.\n *\n * `establishTenantContext` reads the canonical `locals.tenantId` set by the\n * smrt-users auth hook (with `user`/`session` fallbacks). It is a no-op when a\n * context is already active (e.g. an upstream tenancy handle) or when the\n * request carries no tenant (anonymous / global principal).\n *\n * When no context could be established, an `optional`-mode read would otherwise\n * fall through the interceptor UNFILTERED and return rows from ALL tenants (the\n * interceptor only hard-fails `required` mode) — the #1782 leak. So read\n * handlers additionally call `tenantReadScope()`, which restricts reads to\n * NULL-tenant (global) rows only when tenancy is enabled but no context is\n * active. Both helpers are imported only for tenant-scoped routes, which already\n * depend on `@happyvertical/smrt-tenancy`.\n */\nfunction generateTenantContextHelper(\n requirePrincipal: boolean,\n includeReadScope: boolean,\n): string {\n const principalGuard = requirePrincipal\n ? ` if (\n typeof tenantId !== 'string' || !tenantId ||\n typeof userId !== 'string' || !userId ||\n !permissions\n ) return;\n`\n : '';\n const contextArgument = requirePrincipal\n ? '{ tenantId, userId, permissions }'\n : '{ tenantId }';\n const tenancyImport = includeReadScope\n ? 'enterTenantContext, getCurrentTenant, hasTenantContext, isSuperAdminBypass, isTenancyEnabled'\n : 'enterTenantContext, hasTenantContext';\n const readScopeHelpers = includeReadScope\n ? `\n// Fail-closed read scope (#1782): a public/anonymous read on a @TenantScoped\n// model has no tenant context, so the tenancy interceptor (optional mode) would\n// pass the query through UNFILTERED and return every tenant's rows. When tenancy\n// is enabled but no context was established, restrict reads to NULL-tenant\n// (global) rows only — mirroring the dispatch resolver + _changes convention:\n// tenancy enforced with no context => global rows only. Returns undefined when a\n// context is active (the interceptor filters by it) or tenancy is disabled.\nfunction tenantReadScope(): { tenantId: null } | undefined {\n return isTenancyEnabled() && !hasTenantContext()\n ? { tenantId: null }\n : undefined;\n}\n\n// Custom GET actions that accept a single options object may perform their\n// own reads instead of calling generated list/get handlers. Give those actions\n// an explicit tenant scope: active tenant when present, NULL-tenant global rows\n// when tenancy is enabled but no tenant context exists. Super-admin bypass\n// stays unscoped so admin callers keep deliberate cross-tenant access.\nfunction tenantReadOptionsScope(): { tenantId: string | null } | undefined {\n if (!isTenancyEnabled() || isSuperAdminBypass()) {\n return undefined;\n }\n return { tenantId: getCurrentTenant()?.tenantId ?? null };\n}\n`\n : '';\n return `\nimport { ${tenancyImport} } from '@happyvertical/smrt-tenancy';\n\nfunction establishTenantContext(locals: unknown): void {\n if (hasTenantContext()) return;\n if (!locals || typeof locals !== 'object') return;\n const l = locals as Record<string, unknown>;\n const user = l.user as Record<string, unknown> | undefined;\n const session = l.session as Record<string, unknown> | undefined;\n const tenantId = l.tenantId ?? user?.tenantId ?? session?.tenantId;\n const userId = l.userId ?? user?.id ?? user?.userId ?? session?.userId;\n const rawPermissions = l.permissions;\n const permissions =\n rawPermissions instanceof Set && [...rawPermissions].every((value) => typeof value === 'string')\n ? rawPermissions\n : Array.isArray(rawPermissions) && rawPermissions.every((value) => typeof value === 'string')\n ? new Set(rawPermissions)\n : undefined;\n${principalGuard}\n if (typeof tenantId === 'string' && tenantId) {\n enterTenantContext(\n ${contextArgument},\n );\n }\n}\n${readScopeHelpers}\n`;\n}\n\n/**\n * The per-handler guard preamble: the fail-closed auth check (#1540 2c) plus, for\n * tenant-scoped objects, tenant-context establishment (#1540 facet 2).\n */\nfunction routeGuardPreamble(\n objectDef: SmartObjectDefinition,\n mutating: boolean,\n): string {\n const lines = [` requireRouteAuth(locals, ${mutating});`];\n if (needsRouteTenantContext(objectDef)) {\n lines.push(' establishTenantContext(locals);');\n }\n return lines.join('\\n');\n}\n\nfunction normalizeApiHttpMethod(method?: string): ApiHttpMethod {\n switch (method?.toUpperCase()) {\n case 'GET':\n case 'POST':\n case 'PUT':\n case 'PATCH':\n case 'DELETE':\n return method.toUpperCase() as ApiHttpMethod;\n default:\n return 'POST';\n }\n}\n\n/**\n * Convert a camelCase / PascalCase method name to a kebab-case URL segment.\n * Examples:\n * discoverFromUrl -> discover-from-url\n * XMLExport -> xml-export\n * URL -> url\n * a1B2c3 -> a1-b2c3\n *\n * Known limitation: consecutive uppercase acronyms aren't split apart, e.g.\n * `HTMLAPIExport` becomes `htmlapi-export` rather than `html-api-export`.\n * Override with an explicit `api.routes[name].path` if you need a specific\n * segmentation.\n */\nexport function methodNameToKebab(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n .toLowerCase();\n}\n\nfunction normalizeCustomRoutePath(\n actionName: string,\n path?: string,\n options: { kebabRoutes?: boolean } = {},\n): string[] {\n // Explicit path override always wins, and is used verbatim (split on /).\n if (path) {\n const segments = path\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean);\n if (segments.length > 0) {\n return segments;\n }\n }\n\n const segment = options.kebabRoutes\n ? methodNameToKebab(actionName)\n : actionName;\n return [segment];\n}\n\nfunction extractRoutePathParamNames(pathSegments: string[]): string[] {\n return pathSegments\n .filter((segment) => /^\\[[^\\]]+\\]$/.test(segment))\n .map((segment) => segment.slice(1, -1))\n .filter(Boolean);\n}\n\nexport function resolveApiActionRouteConfig(\n actionName: string,\n actionDef: { isStatic?: boolean; decoratorConfig?: Record<string, unknown> },\n apiConfig: unknown,\n routeOptions: { kebabRoutes?: boolean } = {},\n defaultScope: 'item' | 'collection' = actionDef.isStatic\n ? 'collection'\n : 'item',\n): ResolvedApiActionRouteConfig {\n // `@method({ httpMethod, path })` wins field by field over the class-level\n // `api.routes[action]` entry, so migrating one option off the map does not\n // reset the ones left on it (#2686).\n const effective = resolveEffectiveActionMetadata({\n actionName,\n method: actionDef,\n apiConfig,\n });\n\n const pathSegments = normalizeCustomRoutePath(\n actionName,\n effective.path,\n routeOptions,\n );\n\n const scope = resolveCustomActionMetadata({\n actionName,\n method: actionDef,\n apiConfig,\n defaultScope,\n }).scope;\n\n return {\n scope,\n method: normalizeApiHttpMethod(effective.httpMethod),\n pathSegments,\n pathParamNames: extractRoutePathParamNames(pathSegments),\n };\n}\n\nfunction buildRouteHandlerArgs(\n includeParams: boolean,\n includeRequest: boolean,\n): string {\n // `locals` is always destructured so the fail-closed auth guard (#1540) can\n // inspect the authenticated principal.\n const args: string[] = ['locals'];\n\n if (includeParams) {\n args.push('params');\n }\n\n if (includeRequest) {\n args.push('request');\n }\n\n return `{ ${args.join(', ')} }`;\n}\n\nfunction buildPathParamsObjectLiteral(pathParamNames: string[]): string {\n if (pathParamNames.length === 0) {\n return '{}';\n }\n\n return `{\n${pathParamNames\n .map(\n (paramName) =>\n ` ${buildObjectTypeProperty(paramName)}: ${buildRouteParamAccess(paramName)},`,\n )\n .join('\\n')}\n }`;\n}\n\nfunction hasSingleOptionsParameter(actionDef: MethodDefinition): boolean {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n return parameters.length === 1 && parameters[0]?.name === 'options';\n}\n\nfunction buildActionInvocationArgs(\n actionDef: MethodDefinition,\n optionsIdentifier = 'options',\n httpMethod?: string,\n): string[] {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n if (parameters.length === 0) {\n return [];\n }\n\n if (hasSingleOptionsParameter(actionDef)) {\n return [optionsIdentifier];\n }\n\n return parameters.map((parameter, index) => {\n const access = buildOptionsPropertyAccess(parameter.name);\n // A JSON body and a query string can only carry a `Date` as its ISO\n // string, so hydrate it here. The wire-ability gate accepts a `Date`\n // parameter precisely BECAUSE this conversion exists; drop one and the\n // other must go too, or the generator writes a route that 500s on the\n // first `getTime()` (#2686). The cast restores the declared parameter\n // type, which the runtime helper widens to `unknown`.\n // A GET handler builds its options from `URLSearchParams`, so EVERY value\n // is a string and `limit: number` reached the method as `'2'`. A JSON body\n // carries real numbers and booleans, so decode only on GET; `Date` is\n // hydrated on both because a JSON body cannot carry one either (#2686).\n const decoder =\n httpMethod === 'GET'\n ? queryStringDecoderFor(parameter.type)\n : declaredTypeAcceptsDate(parameter.type)\n ? 'toCustomActionDate'\n : undefined;\n return decoder ? `${decoder}(${access}) as ActionArgs[${index}]` : access;\n });\n}\n\nfunction buildObjectTypeProperty(propertyName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propertyName)) {\n return propertyName;\n }\n\n return JSON.stringify(propertyName);\n}\n\nfunction buildSingleQuotedStringLiteral(value: string): string {\n return `'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}'`;\n}\n\nfunction buildRouteParamAccess(paramName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(paramName)) {\n return `params.${paramName}`;\n }\n\n return `params[${buildSingleQuotedStringLiteral(paramName)}]`;\n}\n\nfunction buildActionTargetTypeExpression(\n targetTypeName: string,\n isStatic: boolean,\n): string {\n return isStatic ? `(typeof ${targetTypeName})` : targetTypeName;\n}\n\nfunction buildActionArgsTypeAlias(\n actionName: string,\n targetTypeName: string,\n isStatic: boolean,\n): string {\n const targetTypeExpression = buildActionTargetTypeExpression(\n targetTypeName,\n isStatic,\n );\n return ` type ActionArgs = Parameters<${targetTypeExpression}[${buildSingleQuotedStringLiteral(actionName)}]>;`;\n}\n\nfunction buildActionOptionsTypeAlias(actionDef: MethodDefinition): string {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n if (parameters.length <= 1 && parameters[0]?.name === 'options') {\n return '';\n }\n\n return [\n ' type ActionOptions = {',\n ...parameters.map(\n (parameter, index) =>\n ` ${buildObjectTypeProperty(parameter.name)}: ActionArgs[${index}];`,\n ),\n ' };',\n ].join('\\n');\n}\n\nfunction buildActionOptionsLoad(\n actionName: string,\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n targetTypeName: string,\n isStatic: boolean,\n): string {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n if (parameters.length === 0) {\n return '';\n }\n\n const hasPathParams = routeConfig.pathParamNames.length > 0;\n const pathParamsObjectLiteral = buildPathParamsObjectLiteral(\n routeConfig.pathParamNames,\n );\n const isSingleOptionsParameter =\n parameters.length === 1 && parameters[0]?.name === 'options';\n const lines = [\n buildActionArgsTypeAlias(actionName, targetTypeName, isStatic),\n ];\n const optionsTypeAlias = buildActionOptionsTypeAlias(actionDef);\n if (optionsTypeAlias) {\n lines.push(optionsTypeAlias);\n }\n\n if (routeConfig.method === 'GET') {\n if (hasPathParams) {\n lines.push(\n ` const pathParams = ${pathParamsObjectLiteral};`,\n ' const options = {',\n ' ...Object.fromEntries(new URL(request.url).searchParams.entries()),',\n ' ...pathParams,',\n ` } as ${isSingleOptionsParameter ? 'ActionArgs[0]' : 'ActionOptions'};`,\n '',\n );\n } else {\n lines.push(\n ...(isSingleOptionsParameter\n ? [\n ' const searchParams = new URL(request.url).searchParams;',\n \" const optionsMarker = searchParams.get('__smrt_options');\",\n ' const options = (',\n \" optionsMarker === 'undefined' ||\",\n ' (optionsMarker === null && searchParams.size === 0)',\n ' ? undefined',\n \" : optionsMarker === 'null'\",\n ' ? null',\n \" : optionsMarker === 'object'\",\n ' ? {}',\n ' : Object.fromEntries(',\n ' [...searchParams.entries()].filter(',\n \" ([key]) => key !== '__smrt_options',\",\n ' ),',\n ' )',\n ' ) as ActionArgs[0];',\n ]\n : [\n ' const options = Object.fromEntries(',\n ' new URL(request.url).searchParams.entries(),',\n ' ) as ActionOptions;',\n ]),\n '',\n );\n }\n return lines.join('\\n');\n }\n\n if (hasPathParams) {\n lines.push(\n ` const pathParams = ${pathParamsObjectLiteral};`,\n ' const rawBody = await request.text();',\n \" const body: unknown = rawBody.trim() === '' ? undefined : JSON.parse(rawBody);\",\n ' const options = {',\n ' ...readJsonRecord(body),',\n ' ...pathParams,',\n ` } as ${isSingleOptionsParameter ? 'ActionArgs[0]' : 'ActionOptions'};`,\n '',\n );\n return lines.join('\\n');\n }\n\n lines.push(\n ' const rawBody = await request.text();',\n \" const body: unknown = rawBody.trim() === '' ? undefined : JSON.parse(rawBody);\",\n );\n if (isSingleOptionsParameter) {\n lines.push(' const options = body as ActionArgs[0];', '');\n } else {\n lines.push(' const options = readJsonRecord(body) as ActionOptions;', '');\n }\n return lines.join('\\n');\n}\n\nfunction buildOptionsPropertyAccess(propertyName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propertyName)) {\n return `options.${propertyName}`;\n }\n\n const escapedPropertyName = propertyName\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\");\n\n return `options['${escapedPropertyName}']`;\n}\n\nfunction buildActionInvocationExpression(\n receiverExpression: string,\n actionName: string,\n invocationArgs: string[],\n): string {\n const singleLineInvocation = `await ${receiverExpression}.${actionName}(${invocationArgs.join(', ')})`;\n const singleLineResultAssignment = ` const result = ${singleLineInvocation};`;\n\n if (singleLineResultAssignment.length <= 100) {\n return singleLineInvocation;\n }\n\n return [\n `await ${receiverExpression}.${actionName}(`,\n ...invocationArgs.map((argument) => ` ${argument},`),\n ' )',\n ].join('\\n');\n}\n\nfunction buildScopedOptionsForTenantRead(\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n tenantScoped: boolean,\n): { source: string; optionsIdentifier: string } {\n // The generator can only pass tenant read scope to methods that expose an\n // options object. Zero-argument methods that perform their own raw reads must\n // infer tenant scope in their implementation or adopt the options contract.\n if (\n !tenantScoped ||\n routeConfig.method !== 'GET' ||\n !hasSingleOptionsParameter(actionDef)\n ) {\n return { source: '', optionsIdentifier: 'options' };\n }\n\n return {\n source: ` const readScope = tenantReadOptionsScope();\n const scopedOptions = readScope\n ? ({ ...options, ...readScope } as ActionArgs[0])\n : options;\n\n`,\n optionsIdentifier: 'scopedOptions',\n };\n}\n\nfunction findItemClassRegistryKey(\n className: string,\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): string {\n const itemObject = resolveCollectionItemObject(manifest, objectDef);\n if (!itemObject) {\n return resolveCollectionItemTypeName(manifest, objectDef) || className;\n }\n\n const manifestMatch = Object.entries(manifest.objects).find(\n ([, manifestObject]) => manifestObject === itemObject,\n );\n return manifestMatch?.[0] || itemObject.className;\n}\n\ntype CustomActionRouteGroupSpec = Pick<\n GeneratedActionRouteSpec,\n 'actionName' | 'hostType' | 'lookupClassName' | 'routeConfig'\n>;\n\nfunction assertCompatibleCustomActionRouteSpecs(\n routeSpecs: readonly CustomActionRouteGroupSpec[],\n): void {\n const [firstSpec] = routeSpecs;\n if (!firstSpec) return;\n\n const { hostType, lookupClassName, routeConfig } = firstSpec;\n const hasMixedHosts = routeSpecs.some(\n (spec) =>\n spec.hostType !== hostType ||\n spec.lookupClassName !== lookupClassName ||\n spec.routeConfig.scope !== routeConfig.scope,\n );\n\n if (hasMixedHosts) {\n throw new Error(\n `Cannot generate mixed custom route handlers for ${lookupClassName}. ` +\n 'All handlers sharing a route path must target the same host type and scope.',\n );\n }\n}\n\nfunction groupCustomActionRoutes<T extends CustomActionRouteGroupSpec>(\n actionSpecs: Array<{\n routeDir: string;\n spec: T;\n }>,\n): Map<string, T[]> {\n const groupedRoutes = new Map<string, T[]>();\n\n for (const { routeDir, spec } of actionSpecs) {\n const existing = groupedRoutes.get(routeDir) || [];\n const duplicateMethod = existing.find(\n (candidate) => candidate.routeConfig.method === spec.routeConfig.method,\n );\n\n if (duplicateMethod) {\n throw new Error(\n `Duplicate custom API route handler for ${routeDir} (${spec.routeConfig.method}). ` +\n `Methods ${duplicateMethod.actionName} and ${spec.actionName} resolve to the same generated route.`,\n );\n }\n\n existing.push(spec);\n groupedRoutes.set(routeDir, existing);\n }\n\n for (const routeSpecs of groupedRoutes.values()) {\n assertCompatibleCustomActionRouteSpecs(routeSpecs);\n }\n\n return groupedRoutes;\n}\n\n/** Reject selected identities that would write the same endpoint file. */\nexport function assertNoCrossObjectRouteCollisions(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n exposureManifest: SmartObjectManifest,\n reservedRoutePaths: ReadonlySet<string> = new Set(),\n): void {\n type RouteWriter =\n | 'crud-collection'\n | 'crud-item'\n | 'custom-action'\n | 'sync-apply'\n | 'changes'\n | 'dev-plane'\n | 'events'\n | 'resources'\n | 'knowledge';\n const claims = new Map<string, { owner: string; writer: RouteWriter }>();\n const claimPath = (\n routePath: string,\n routeDir: string,\n owner: string,\n writer: RouteWriter,\n ) => {\n const canonicalRoutePath = canonicalSvelteKitPath(routePath);\n const prior = claims.get(canonicalRoutePath);\n if (prior && (prior.owner !== owner || prior.writer !== writer)) {\n throw new Error(\n `Conflicting SvelteKit route ${routeDir}: ${prior.owner} (${prior.writer}) and ${owner} (${writer}) would write the same handler`,\n );\n }\n claims.set(canonicalRoutePath, { owner, writer });\n };\n const claim = (routeDir: string, owner: string, writer: RouteWriter) =>\n claimPath(\n join(projectRoot, routeDir, '+server.ts'),\n routeDir,\n owner,\n writer,\n );\n for (const routePath of reservedRoutePaths) {\n claimPath(\n resolve(routePath),\n relative(projectRoot, routePath),\n 'producer knowledge',\n 'knowledge',\n );\n }\n for (const [className, objectDef] of orderedManifestObjectEntries(manifest)) {\n if (isFrameworkBaseClass(objectDef.className, objectDef.packageName))\n continue;\n const routeDir = join(options.routesDir, objectDef.collection);\n if (isCollectionManifestClass(manifest, objectDef)) {\n const actionSpecs = resolveApiCustomActions(\n objectDef,\n exposureManifest,\n true,\n ).exposed.map(([actionName, actionDef]) => {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n objectDef.decoratorConfig?.api,\n { kebabRoutes: options.kebabRoutes },\n 'collection',\n );\n return {\n routeDir: join(routeDir, ...routeConfig.pathSegments),\n spec: {\n actionName,\n hostType: 'collection' as const,\n lookupClassName: findItemClassRegistryKey(\n className,\n objectDef,\n manifest,\n ),\n routeConfig,\n },\n };\n });\n for (const [actionRouteDir] of groupCustomActionRoutes(actionSpecs)) {\n claim(actionRouteDir, className, 'custom-action');\n }\n continue;\n }\n const actions = resolveStandardCrudActions(objectDef.decoratorConfig?.api);\n if (actions.some((action) => action === 'list' || action === 'create'))\n claim(routeDir, className, 'crud-collection');\n if (\n actions.some(\n (action) =>\n action === 'get' || action === 'update' || action === 'delete',\n )\n )\n claim(join(routeDir, '[id]'), className, 'crud-item');\n const actionSpecs = resolveApiCustomActions(\n objectDef,\n exposureManifest,\n false,\n ).exposed.map(([actionName, actionDef]) => {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n objectDef.decoratorConfig?.api,\n { kebabRoutes: options.kebabRoutes },\n );\n return {\n routeDir: join(\n routeConfig.scope === 'collection'\n ? routeDir\n : join(routeDir, '[id]'),\n ...routeConfig.pathSegments,\n ),\n spec: {\n actionName,\n hostType: 'item' as const,\n lookupClassName: className,\n routeConfig,\n },\n };\n });\n for (const [actionRouteDir] of groupCustomActionRoutes(actionSpecs)) {\n claim(actionRouteDir, className, 'custom-action');\n }\n }\n // These generator-owned utility files share the same filesystem namespace.\n // Claim only paths their current output predicates can emit.\n if (collectSyncApplyTargets(manifest).length > 0) {\n claim(join(options.routesDir, 'sync', 'apply'), 'sync/apply', 'sync-apply');\n }\n const hasAnchor = Object.values(manifest.objects).some(\n (objectDef) => !isCollectionManifestClass(manifest, objectDef),\n );\n if (hasAnchor && options.changesRoute?.enabled !== false) {\n claim(join(options.routesDir, '_changes'), '_changes', 'changes');\n }\n if (willGenerateDevPlaneRoute(projectRoot, options)) {\n claim(join(options.routesDir, '_dev', '[...tool]'), '_dev', 'dev-plane');\n }\n if (hasAnchor && options.eventsRoute?.enabled !== false) {\n claim(join(options.routesDir, '_events'), '_events', 'events');\n }\n if (reservesResourcesRoute(projectRoot, options)) {\n claim(join(options.routesDir, '_resources'), '_resources', 'resources');\n }\n if (options.knowledge?.api?.enabled) {\n const routeDir = knowledgeRouteDir(projectRoot, options);\n claimPath(join(routeDir, '+server.ts'), routeDir, 'knowledge', 'knowledge');\n }\n}\n\n/**\n * Generates SvelteKit API routes from the selected route manifest.\n * `semanticManifest` preserves the complete class inventory for authorization,\n * STI ancestry, cache safety, and custom-action wireability when the route\n * manifest is a deliberately selected output subset.\n */\nexport interface SvelteKitUtilityManifests {\n sync: SmartObjectManifest;\n changes: SmartObjectManifest;\n events: SmartObjectManifest;\n eventsSemantic: SmartObjectManifest;\n /** Only the contribution that owns knowledge generation may reconcile it. */\n clearKnowledgeRoute?: boolean;\n /** Exact foreign producer outputs that this route root must neither clear nor overwrite. */\n protectedRoutePaths?: ReadonlySet<string>;\n /** Active foreign route roots that cleanup must not traverse through links. */\n protectedRouteRoots?: ReadonlySet<string>;\n}\n\n/** Coordinator callbacks that run around validated generated-output mutation. */\nexport interface SvelteKitGenerationHooks {\n beforeCleanup?: () => void | Promise<void>;\n}\n\nexport async function generateSvelteKitRoutes(\n projectRoot: string,\n routeManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n semanticManifest: SmartObjectManifest = routeManifest,\n utilityManifests: SvelteKitUtilityManifests = {\n sync: routeManifest,\n changes: routeManifest,\n events: routeManifest,\n eventsSemantic: semanticManifest,\n clearKnowledgeRoute: true,\n },\n registrationManifest: SmartObjectManifest = routeManifest,\n hooks: SvelteKitGenerationHooks = {},\n): Promise<void> {\n if (!options.enabled) return;\n\n console.log('[smrt] Generating SvelteKit routes...');\n\n if (options.rejectRouteCollisions) {\n assertNoCrossObjectRouteCollisions(\n projectRoot,\n routeManifest,\n options,\n semanticManifest,\n utilityManifests.protectedRoutePaths,\n );\n }\n\n await hooks.beforeCleanup?.();\n\n clearGeneratedSvelteKitRouteFiles(\n join(projectRoot, options.routesDir),\n utilityManifests.protectedRoutePaths,\n utilityManifests.protectedRouteRoots,\n );\n if (utilityManifests.clearKnowledgeRoute !== false) {\n clearGeneratedKnowledgeRoute(projectRoot, options);\n }\n\n // Generate centralized configuration file first (if it doesn't exist)\n await generateSmrtConfigFile(projectRoot, registrationManifest, options);\n\n const generatedRoutePaths: string[] = [];\n let generatedCount = 0;\n let skippedCollections = 0;\n for (const [className, objectDef] of orderedManifestObjectEntries(\n routeManifest,\n )) {\n // The framework's own abstract base classes (SmrtObject,\n // SmrtCollection, ...) are scaffolding, not resources — never generate\n // a route directory for them, regardless of config (#2642).\n if (isFrameworkBaseClass(objectDef.className, objectDef.packageName)) {\n continue;\n }\n if (isCollectionManifestClass(semanticManifest, objectDef)) {\n const collectionRoutePaths = await generateCollectionRoutesForObject(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(...collectionRoutePaths);\n if (collectionRoutePaths.length > 0) {\n generatedCount++;\n } else {\n console.log(\n `[smrt] Skipping ${className} - no collection API routes to generate`,\n );\n skippedCollections++;\n }\n continue;\n }\n generatedRoutePaths.push(\n ...(await generateRoutesForObject(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n options,\n )),\n );\n generatedCount++;\n }\n\n if (options.knowledge?.api?.enabled) {\n generatedRoutePaths.push(generateKnowledgeRoute(projectRoot, options));\n }\n\n // Batch write contract route (#1759): {routesDir}/sync/apply/+server.ts.\n if (generateSyncApplyRoute(projectRoot, utilityManifests.sync, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, 'sync', 'apply', '+server.ts'),\n );\n }\n // Change-feed route (#1758) — cleanup rides clearGeneratedRouteFiles above.\n if (generateChangesRoute(projectRoot, utilityManifests.changes, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_changes', '+server.ts'),\n );\n }\n if (generateDevPlaneRoute(projectRoot, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_dev', '[...tool]', '+server.ts'),\n );\n }\n // Live change-signal SSE route (#1763) — cleanup rides the sweep above.\n if (\n generateEventsRoute(\n projectRoot,\n utilityManifests.events,\n options,\n computeWebManifestHash(utilityManifests.eventsSemantic),\n )\n ) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_events', '+server.ts'),\n );\n }\n\n // CLI discovery route (#2663) — cleanup rides the sweep above; skipped\n // when smrt-users isn't resolvable or a hand-written route already exists.\n if (generateResourcesRoute(projectRoot, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_resources', '+server.ts'),\n );\n }\n\n // Ignore only the concrete route files generated in this pass. This keeps\n // handwritten handlers below routesDir visible to Git.\n updateGitignore(\n projectRoot,\n generatedRoutePaths,\n join(projectRoot, svelteKitRouteRoot(options.routesDir)),\n );\n\n const skippedMsg =\n skippedCollections > 0\n ? ` (skipped ${skippedCollections} collection classes)`\n : '';\n console.log(\n `[smrt] Generated routes for ${generatedCount} SMRT objects${skippedMsg}`,\n );\n}\n\n/** Remove only SMRT header-owned SvelteKit handlers below one route root. */\nexport function clearGeneratedSvelteKitRouteFiles(\n routesRoot: string,\n excludedPaths: ReadonlySet<string> = new Set(),\n protectedRouteRoots: ReadonlySet<string> = new Set(),\n visitedRoots: Set<string> = new Set(),\n): void {\n const canonicalRoot = canonicalSvelteKitPath(routesRoot);\n if (\n protectedRouteRoots.has(canonicalRoot) ||\n visitedRoots.has(canonicalRoot)\n ) {\n return;\n }\n if (!existsSync(routesRoot)) {\n return;\n }\n visitedRoots.add(canonicalRoot);\n\n for (const entry of readdirSync(routesRoot, { withFileTypes: true })) {\n const entryPath = join(routesRoot, entry.name);\n\n if (isSvelteKitRouteDirectory(entryPath, entry)) {\n clearGeneratedSvelteKitRouteFiles(\n entryPath,\n excludedPaths,\n protectedRouteRoots,\n visitedRoots,\n );\n continue;\n }\n\n if (!entry.isFile() || entry.name !== '+server.ts') {\n continue;\n }\n if (excludedPaths.has(canonicalSvelteKitPath(entryPath))) continue;\n\n const fileContent = readFileSync(entryPath, 'utf-8');\n if (fileContent.startsWith(AUTO_GENERATED_ROUTE_HEADER)) {\n unlinkSync(entryPath);\n }\n }\n}\n\nfunction isSvelteKitRouteDirectory(\n entryPath: string,\n entry: { isDirectory(): boolean; isSymbolicLink?(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink?.()) return false;\n try {\n return statSync(entryPath).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** Refresh the managed ignore block after an externally coordinated cleanup. */\nexport function reconcileSvelteKitRouteGitignore(\n projectRoot: string,\n routesDir: string,\n): void {\n updateGitignore(\n projectRoot,\n [],\n join(projectRoot, svelteKitRouteRoot(routesDir)),\n );\n}\n\nfunction knowledgeRouteDir(projectRoot: string, options: SvelteKitOptions) {\n const basePath = String(\n options.knowledge?.api?.basePath || '/__smrt/knowledge',\n );\n const routeRoot = svelteKitRouteRoot(options.routesDir);\n const segments = basePath\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean);\n\n return join(projectRoot, routeRoot, ...segments);\n}\n\n/** Exact generated knowledge handler path for coordinator-owned cleanup. */\nexport function knowledgeRoutePath(\n projectRoot: string,\n options: SvelteKitOptions,\n): string {\n return join(knowledgeRouteDir(projectRoot, options), '+server.ts');\n}\n\nfunction svelteKitRouteRoot(routesDir: string): string {\n const normalized = routesDir.replaceAll('\\\\', '/').replace(/\\/+$/, '');\n const marker = '/routes';\n const markerIndex = normalized.indexOf(marker);\n\n if (normalized === 'src/routes' || normalized.endsWith('/routes')) {\n return normalized;\n }\n if (markerIndex !== -1) {\n return normalized.slice(0, markerIndex + marker.length);\n }\n return 'src/routes';\n}\n\nfunction clearGeneratedKnowledgeRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): void {\n const routePath = knowledgeRoutePath(projectRoot, options);\n if (!existsSync(routePath)) return;\n\n const content = readFileSync(routePath, 'utf-8');\n if (content.startsWith(AUTO_GENERATED_ROUTE_HEADER)) {\n unlinkSync(routePath);\n }\n}\n\nfunction generateKnowledgeRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): string {\n const routeDir = knowledgeRouteDir(projectRoot, options);\n const route = generateKnowledgeRouteTemplate(\n options.knowledge ?? {},\n readKnowledgeRouteArtifact(projectRoot),\n );\n return writeRoute(routeDir, '+server.ts', route);\n}\n\nfunction readKnowledgeRouteArtifact(\n projectRoot: string,\n): Record<string, unknown> | null {\n for (const relativePath of [\n '.smrt/smrt-knowledge.json',\n 'dist/smrt-knowledge.json',\n ]) {\n const fullPath = join(projectRoot, relativePath);\n if (!existsSync(fullPath)) continue;\n try {\n return JSON.parse(readFileSync(fullPath, 'utf-8'));\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\n/**\n * Generates SMRT object registration file\n * This file imports all SMRT objects to trigger their @smrt() decorators\n */\nasync function generateRegistrationFile(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<void> {\n const configPath = options.configPath || 'src/lib/server';\n const configDir = join(projectRoot, configPath);\n const registrationFilePath = join(configDir, 'smrt-register.ts');\n\n // Group objects by package for efficient imports\n const localObjects: Array<[string, (typeof manifest.objects)[string]]> = [];\n const packageObjects = new Map<\n string,\n {\n objects: Array<{\n simpleName: string;\n bindingName: string;\n }>;\n hasCollectionImport: boolean;\n }\n >();\n const registrationBindings = buildRegistrationBindings(manifest);\n\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n if (isLocalObject(projectRoot, objectDef)) {\n // Local object (source in project, not node_modules) - use $lib path\n localObjects.push([className, objectDef]);\n } else if (objectDef.packageName) {\n // External packages may publish canonical object exports from a subpath\n // under an aliased export name. Registry identity stays keyed by the\n // manifest's qualified class name; only the emitted module binding uses\n // that canonical import contract.\n const externalImportPath = objectDef.importPath || objectDef.packageName;\n const packageEntry = packageObjects.get(externalImportPath) || {\n objects: [],\n hasCollectionImport: false,\n };\n\n if (isCollectionManifestClass(manifest, objectDef)) {\n packageEntry.hasCollectionImport = true;\n } else {\n packageEntry.objects.push({\n simpleName: objectDef.exportName || extractSimpleClassName(className),\n bindingName:\n registrationBindings.get(className) ||\n extractSimpleClassName(className),\n });\n }\n\n packageObjects.set(externalImportPath, packageEntry);\n } else {\n // No package name and not local - treat as local fallback\n localObjects.push([className, objectDef]);\n }\n }\n\n // Generate imports for local objects\n // Issue #870: Extract simple class names from qualified names\n const localNamedImports = new Map<\n string,\n Array<{ simpleName: string; bindingName: string }>\n >();\n const localSideEffectImports = new Set<string>();\n\n for (const [className, objectDef] of localObjects) {\n const simpleClassName = extractSimpleClassName(className);\n\n // Calculate direct relative path from the configDir where smrt-register.ts lives\n // to the actual source file of the object.\n let importPath = '';\n if (objectDef.filePath) {\n const relativeToConfig = relative(configDir, objectDef.filePath);\n const normalized = relativeToConfig\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n importPath = normalized.startsWith('.') ? normalized : `./${normalized}`;\n } else {\n // Fallback for missing file paths\n importPath = getSvelteKitImportPath(\n projectRoot,\n undefined,\n options.objectsDir,\n simpleClassName,\n );\n }\n\n if (isCollectionManifestClass(manifest, objectDef)) {\n localSideEffectImports.add(importPath);\n continue;\n }\n\n const existing = localNamedImports.get(importPath) ?? [];\n existing.push({\n simpleName: simpleClassName,\n bindingName: registrationBindings.get(className) || simpleClassName,\n });\n localNamedImports.set(importPath, existing);\n }\n\n const localImports = [\n ...Array.from(localNamedImports.entries())\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([importPath, importedObjects]) => {\n const sortedNames = importedObjects\n .sort((a, b) => a.bindingName.localeCompare(b.bindingName))\n .map(formatRegistrationImport);\n return `import { ${sortedNames.join(', ')} } from '${importPath}';`;\n }),\n ...Array.from(localSideEffectImports.values())\n .sort((a, b) => a.localeCompare(b))\n .map((importPath) => `import '${importPath}';`),\n ].join('\\n');\n\n // Generate imports for external packages\n // Issue #870: Extract simple class names from qualified names\n const packageImports = Array.from(packageObjects.entries())\n .sort(([left], [right]) => left.localeCompare(right))\n .flatMap(([packageName, packageEntry]) => {\n const imports: string[] = [];\n\n if (packageEntry.hasCollectionImport) {\n imports.push(`import '${packageName}';`);\n }\n\n if (packageEntry.objects.length > 0) {\n const simpleNames = packageEntry.objects\n .sort((a, b) => a.bindingName.localeCompare(b.bindingName))\n .map(formatRegistrationImport);\n imports.push(\n `import { ${simpleNames.join(', ')} } from '${packageName}';`,\n );\n }\n\n return imports;\n })\n .join('\\n');\n\n const imports = [packageImports, localImports].filter(Boolean).join('\\n');\n const externalRuntimeDependencies = (manifest.smrtDependencies || []).filter(\n (dependency) => dependency !== '@happyvertical/smrt-core',\n );\n const consumerRegistrationPaths =\n options.consumerRegistrationPaths ??\n (externalRuntimeDependencies.length > 0\n ? [join(projectRoot, '.smrt', 'register.js')]\n : []);\n let consumerRegistrationImport = '';\n if (consumerRegistrationPaths.length > 0) {\n consumerRegistrationImport = [...new Set(consumerRegistrationPaths)]\n .sort()\n .map((registerPath) => {\n const consumerRegistrationPath = relative(\n configDir,\n registerPath,\n ).replace(/\\\\/g, '/');\n return `import '${consumerRegistrationPath.startsWith('.') ? consumerRegistrationPath : `./${consumerRegistrationPath}`}';`;\n })\n .join('\\n');\n }\n /**\n * Strip machine specifics from an object definition before it is embedded in\n * generated source.\n *\n * `smrt-register.ts` is a tracked file in consumer repositories, and the\n * scanner records `filePath` as an absolute path. Embedding it verbatim wrote\n * the generating machine's home directory into the repository, so the file\n * could never be committed without breaking every other checkout and CI, and\n * every build left a dirty working tree (#2341). The field is only produced\n * at scan time — nothing reads it back through `_manifest` at runtime — so a\n * project-relative path keeps the shape without the machine.\n */\n function portableObjectManifest(\n root: string,\n objectDef: SmartObjectDefinition,\n ): SmartObjectDefinition {\n const { filePath } = objectDef;\n if (typeof filePath !== 'string' || !isAbsolute(filePath)) {\n return objectDef;\n }\n return {\n ...objectDef,\n filePath: relative(root, filePath).split(sep).join('/'),\n };\n }\n\n const registrationManifests = Object.fromEntries(\n Object.entries(manifest.objects).flatMap(([className, objectDef]) => {\n if (isCollectionManifestClass(manifest, objectDef)) return [];\n const localObject = isLocalObject(projectRoot, objectDef);\n const packageName = getRegistrationPackageName(\n manifest,\n objectDef,\n localObject,\n );\n if (!packageName) return [];\n return [\n [\n className,\n {\n ...manifest,\n packageName,\n objects: {\n [className]: portableObjectManifest(projectRoot, objectDef),\n },\n },\n ],\n ];\n }),\n );\n const registrationManifestLiteral = JSON.stringify(\n JSON.stringify(registrationManifests),\n );\n const registrations = Object.entries(manifest.objects)\n .map(([className, objectDef]) => {\n if (isCollectionManifestClass(manifest, objectDef)) {\n // Importing the collection class is enough to trigger its decorator.\n // Explicit package-qualified re-registration only applies to object\n // classes, because ObjectRegistry.register() is object-only.\n return null;\n }\n\n const simpleClassName = extractSimpleClassName(className);\n const bindingName =\n registrationBindings.get(className) || simpleClassName;\n const localObject = isLocalObject(projectRoot, objectDef);\n const packageName = getRegistrationPackageName(\n manifest,\n objectDef,\n localObject,\n );\n\n if (!packageName) {\n return null;\n }\n\n const packageNameLiteral = toSingleQuotedStringLiteral(packageName);\n const manifestKeyLiteral = toSingleQuotedStringLiteral(className);\n const singleLineRegistration = `ObjectRegistry.register(${bindingName}, { name: '${simpleClassName}', packageName: ${packageNameLiteral}, _manifest: smrtRegistrationManifests[${manifestKeyLiteral}], _manifestKey: ${manifestKeyLiteral} });`;\n\n if (singleLineRegistration.length <= BIOME_LINE_WIDTH) {\n return singleLineRegistration;\n }\n\n return [\n `ObjectRegistry.register(${bindingName}, {`,\n ` name: '${simpleClassName}',`,\n ` packageName: ${packageNameLiteral},`,\n ` _manifest: smrtRegistrationManifests[${manifestKeyLiteral}],`,\n ` _manifestKey: ${manifestKeyLiteral},`,\n `});`,\n ].join('\\n');\n })\n .filter((registration): registration is string => registration !== null)\n .join('\\n');\n\n const registrationContent = `/**\n * Auto-generated SMRT object registration\n * DO NOT EDIT - changes will be overwritten\n *\n * Importing these modules triggers their @smrt() decorators, which perform\n * the initial registration. The explicit re-registration below is intentional:\n * it upgrades bundled runtimes to deterministic qualified registrations.\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${consumerRegistrationImport}\n${imports}\n\nconst smrtRegistrationManifests = JSON.parse(${registrationManifestLiteral});\n\n// Re-register imported objects with explicit package names for bundled runtimes\n${registrations}\n`;\n\n // Create directory if it doesn't exist\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(registrationFilePath, registrationContent, 'utf-8');\n console.log(`[smrt] Generated registration file: ${registrationFilePath}`);\n}\n\nfunction buildRegistrationBindings(\n manifest: SmartObjectManifest,\n): Map<string, string> {\n const keysBySimpleName = new Map<string, string[]>();\n const reservedBindings = new Set<string>();\n for (const [manifestKey, objectDef] of Object.entries(manifest.objects)) {\n if (isCollectionManifestClass(manifest, objectDef)) continue;\n const simpleName = extractSimpleClassName(manifestKey);\n reservedBindings.add(simpleName);\n const keys = keysBySimpleName.get(simpleName) ?? [];\n keys.push(manifestKey);\n keysBySimpleName.set(simpleName, keys);\n }\n\n const bindings = new Map<string, string>();\n const generatedBindings = new Set<string>();\n for (const [simpleName, keys] of keysBySimpleName) {\n const sortedKeys = keys.sort((a, b) => a.localeCompare(b));\n for (const [index, manifestKey] of sortedKeys.entries()) {\n let bindingName = simpleName;\n if (sortedKeys.length > 1) {\n let suffix = index + 1;\n do {\n bindingName = `__smrt_${simpleName}_${suffix}`;\n suffix += 1;\n } while (\n reservedBindings.has(bindingName) ||\n generatedBindings.has(bindingName)\n );\n generatedBindings.add(bindingName);\n }\n bindings.set(manifestKey, bindingName);\n }\n }\n return bindings;\n}\n\nfunction formatRegistrationImport(importedObject: {\n simpleName: string;\n bindingName: string;\n}): string {\n return importedObject.simpleName === importedObject.bindingName\n ? importedObject.simpleName\n : `${importedObject.simpleName} as ${importedObject.bindingName}`;\n}\n\n/**\n * Generates centralized SMRT configuration file\n * Only creates if file doesn't exist (preserves user customizations)\n */\nasync function generateSmrtConfigFile(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<void> {\n const configPath = options.configPath || 'src/lib/server';\n const configFileName = options.configFileName || 'smrt.ts';\n const configDir = join(projectRoot, configPath);\n const configFilePath = join(configDir, configFileName);\n\n // Always generate registration file (it gets overwritten)\n await generateRegistrationFile(projectRoot, manifest, options);\n\n // Don't overwrite existing config file\n if (existsSync(configFilePath)) {\n console.log('[smrt] Config file already exists, skipping generation');\n return;\n }\n\n const configContent = `/**\n * Centralized SMRT configuration with per-object overrides\n * Generated by @smrt/core vite plugin\n *\n * Most objects will use the default configuration.\n * Add entries to \\`objectOverrides\\` for objects that need different backends.\n */\n\n// Import SMRT objects to register them via @smrt() decorators\nimport './smrt-register.js';\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\nimport type { SmrtClassOptions } from '@happyvertical/smrt-core';\n\n// \\`__smrtGetRequestScopedDatabase\\` is declared canonically by\n// @happyvertical/smrt-core; importing its types above is enough to see it.\n// Do not redeclare it here — duplicate \\`declare global\\` entries must be\n// type-identical, and a second declaration broke consumer checks (#2342).\n\n/**\n * Per-object configuration overrides\n * Define specific backends for objects that differ from project defaults\n *\n * @example\n * const objectOverrides: Record<string, Partial<SmrtClassOptions>> = {\n * // Analytics uses a separate PostgreSQL database\n * Analytics: {\n * db: {\n * url: process.env.ANALYTICS_DATABASE_URL!,\n * type: 'postgres'\n * }\n * },\n *\n * // AuditLog uses dedicated database with no AI\n * AuditLog: {\n * db: {\n * url: process.env.AUDIT_DATABASE_URL!,\n * type: 'postgres'\n * },\n * ai: undefined\n * },\n *\n * // Cache uses REST adapter (e.g., Redis)\n * Cache: {\n * persistence: {\n * type: 'rest',\n * baseUrl: process.env.REDIS_URL!\n * }\n * }\n * };\n */\nconst objectOverrides: Record<string, Partial<SmrtClassOptions>> = {\n // Add your per-object configuration overrides here\n};\n\n/**\n * Default configuration for most SMRT objects\n * Customize this to change project-wide defaults\n */\nfunction getDefaultConfig(): SmrtClassOptions {\n return {\n db: {\n url: process.env.DATABASE_URL || ':memory:',\n type: (process.env.DATABASE_TYPE as 'sqlite' | 'postgres') || 'sqlite'\n },\n ai: process.env.OPENAI_API_KEY ? {\n type: 'openai',\n apiKey: process.env.OPENAI_API_KEY\n } : process.env.ANTHROPIC_API_KEY ? {\n type: 'anthropic',\n apiKey: process.env.ANTHROPIC_API_KEY\n } : undefined\n };\n}\n\nfunction getRequestScopedDatabase(): SmrtClassOptions['db'] | undefined {\n const getter = globalThis.__smrtGetRequestScopedDatabase;\n return typeof getter === 'function' ? getter() : undefined;\n}\n\n/**\n * Get configuration for a specific SMRT object\n * Merges project defaults with per-object overrides if defined\n */\nexport function getSmrtConfig(className: string): SmrtClassOptions {\n const defaults = getDefaultConfig();\n const override = objectOverrides[className];\n\n if (override) {\n // Deep merge: override specific properties while keeping defaults\n return {\n ...defaults,\n ...override,\n // Ensure nested objects are merged properly\n db: override.db\n ? { ...(defaults.db as any), ...(override.db as any) }\n : defaults.db,\n ai: override.ai !== undefined ? override.ai : defaults.ai\n };\n }\n\n return defaults;\n}\n\n/**\n * Helper to get a collection with centralized configuration\n * Automatically applies project defaults or object-specific overrides\n */\nexport async function getCollection<\n T extends import('@happyvertical/smrt-core').SmrtObject,\n>(className: string, overrides: Partial<SmrtClassOptions> = {}) {\n const config = getSmrtConfig(className);\n const objectOverride = objectOverrides[className];\n const requestScopedDb =\n !overrides.db && !objectOverride?.db\n ? getRequestScopedDatabase()\n : undefined;\n\n return await ObjectRegistry.getCollection<T>(\n className,\n {\n ...config,\n ...overrides,\n db: overrides.db\n ? { ...(config.db as any), ...(overrides.db as any) }\n : requestScopedDb ?? config.db,\n ai: overrides.ai !== undefined ? overrides.ai : config.ai\n }\n );\n}\n`;\n\n // Create directory if it doesn't exist\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(configFilePath, configContent, 'utf-8');\n console.log(`[smrt] Generated configuration file: ${configFilePath}`);\n}\n\n/**\n * Generates route files for a single SMRT object\n */\nasync function generateRoutesForObject(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<string[]> {\n const collectionName = objectDef.collection;\n const routeDir = join(projectRoot, options.routesDir, collectionName);\n const generatedRoutePaths: string[] = [];\n\n // Check if API is enabled for this object\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) {\n console.log(`[smrt] Skipping ${className} - API disabled`);\n return generatedRoutePaths;\n }\n\n // Determine which CRUD actions to include via the shared resolver.\n const includedActions = resolveStandardCrudActions(apiConfig);\n\n // Generate collection route (list, create)\n if (includedActions.includes('list') || includedActions.includes('create')) {\n const collectionRoute = generateCollectionRouteTemplate(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n includedActions,\n options,\n routeDir,\n );\n generatedRoutePaths.push(\n writeRoute(routeDir, '+server.ts', collectionRoute),\n );\n }\n\n // Generate item route (get, update, delete)\n if (\n includedActions.includes('get') ||\n includedActions.includes('update') ||\n includedActions.includes('delete')\n ) {\n const itemRoute = generateItemRouteTemplate(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n includedActions,\n options,\n join(routeDir, '[id]'),\n );\n generatedRoutePaths.push(\n writeRoute(join(routeDir, '[id]'), '+server.ts', itemRoute),\n );\n }\n\n // Generate custom action routes. Eligibility -- CRUD reservation, framework\n // lifecycle methods, include/exclude, `@method()` overrides, wire-ability,\n // and the receiver check -- comes from the ONE shared resolver every API\n // consumer reads, so a route is written exactly when `resolveApiActionSet`\n // and the knowledge artifact say one exists (#2686).\n const { exposed: customActions, rejected } = resolveApiCustomActions(\n objectDef,\n semanticManifest,\n false,\n );\n warnUnhostedActions(className, rejected);\n\n const actionSpecs: Array<{\n routeDir: string;\n spec: GeneratedActionRouteSpec;\n }> = [];\n\n for (const [actionName, actionDef] of customActions) {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n apiConfig,\n { kebabRoutes: options.kebabRoutes },\n );\n warnDeclaredScopeMismatch(\n className,\n actionName,\n actionDef,\n apiConfig,\n routeConfig.scope,\n );\n\n const actionBaseDir =\n routeConfig.scope === 'collection' ? routeDir : join(routeDir, '[id]');\n actionSpecs.push({\n routeDir: join(actionBaseDir, ...routeConfig.pathSegments),\n spec: {\n lookupClassName: className,\n lookupObjectDef: objectDef,\n hostClassName: className,\n actionName,\n actionDef,\n routeConfig,\n hostType: 'item',\n },\n });\n }\n\n for (const [actionRouteDir, routeSpecs] of groupCustomActionRoutes(\n actionSpecs,\n )) {\n const actionRoute = generateActionRouteTemplate(\n projectRoot,\n actionRouteDir,\n routeSpecs,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(\n writeRoute(actionRouteDir, '+server.ts', actionRoute),\n );\n }\n\n return generatedRoutePaths;\n}\n\nasync function generateCollectionRoutesForObject(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<string[]> {\n const generatedRoutePaths: string[] = [];\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) {\n console.log(`[smrt] Skipping ${className} - API disabled`);\n return generatedRoutePaths;\n }\n\n const routeDir = join(projectRoot, options.routesDir, objectDef.collection);\n const lookupClassName = findItemClassRegistryKey(\n className,\n objectDef,\n semanticManifest,\n );\n const lookupObjectDef = findObjectDefByRegistryKey(\n semanticManifest,\n lookupClassName,\n );\n\n const { exposed: customActions, rejected } = resolveApiCustomActions(\n objectDef,\n semanticManifest,\n true,\n );\n warnUnhostedActions(className, rejected);\n\n if (customActions.length === 0) {\n return generatedRoutePaths;\n }\n const actionSpecs: Array<{\n routeDir: string;\n spec: GeneratedActionRouteSpec;\n }> = [];\n\n for (const [actionName, actionDef] of customActions) {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n apiConfig,\n { kebabRoutes: options.kebabRoutes },\n 'collection',\n );\n warnDeclaredScopeMismatch(\n className,\n actionName,\n actionDef,\n apiConfig,\n routeConfig.scope,\n );\n\n actionSpecs.push({\n routeDir: join(routeDir, ...routeConfig.pathSegments),\n spec: {\n lookupClassName,\n lookupObjectDef,\n hostClassName: className,\n actionName,\n actionDef,\n routeConfig,\n hostType: 'collection',\n },\n });\n }\n\n for (const [actionRouteDir, routeSpecs] of groupCustomActionRoutes(\n actionSpecs,\n )) {\n const actionRoute = generateActionRouteTemplate(\n projectRoot,\n actionRouteDir,\n routeSpecs,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(\n writeRoute(actionRouteDir, '+server.ts', actionRoute),\n );\n }\n\n return generatedRoutePaths;\n}\n\n/**\n * Resolve the list of standard CRUD actions exposed by the API for a given\n * apiConfig. Single source of truth for both the route generator and the\n * cli↔api coherence lint.\n */\nfunction resolveStandardCrudActions(apiConfig: unknown): string[] {\n if (apiConfig === false) return [];\n if (apiConfig === true || apiConfig === undefined) {\n return [...CRUD_OPERATIONS];\n }\n if (typeof apiConfig !== 'object' || apiConfig === null) {\n return [...CRUD_OPERATIONS];\n }\n\n const config = apiConfig as { include?: string[]; exclude?: string[] };\n let crud: string[] = Array.isArray(config.include)\n ? config.include.filter((a) => isCrudOperation(a))\n : [...CRUD_OPERATIONS];\n if (Array.isArray(config.exclude)) {\n const exclude = config.exclude;\n crud = crud.filter((a) => !exclude.includes(a));\n }\n return crud;\n}\n\n/**\n * Partition an object's custom (non-CRUD) methods into the ones the API\n * exposes and the ones it withholds, with a reason for each rejection.\n *\n * The ONE place route generation, `resolveApiActionSet`, and the knowledge\n * artifact's API projection agree, by all three reading\n * {@link resolveApiMethodExposure}. Before #2686 each re-derived a subset and\n * could disagree — most damagingly, a gate applied only to the coherence\n * resolver would report a method unreachable while the emitter next door still\n * wrote its route file.\n */\nexport function resolveApiCustomActions(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest | undefined,\n objectIsCollectionClass: boolean,\n wireability: WireabilityOptions = {},\n): {\n exposed: Array<[string, MethodDefinition]>;\n rejected: Array<[string, ApiMethodExposure]>;\n} {\n const apiConfig = objectDef.decoratorConfig?.api;\n const isModelClassName =\n wireability.isModelClassName ?? createManifestClassNamePredicate(manifest);\n const exposed: Array<[string, MethodDefinition]> = [];\n const rejected: Array<[string, ApiMethodExposure]> = [];\n\n for (const [name, method] of Object.entries(objectDef.methods || {})) {\n const decision = resolveApiMethodExposure({\n actionName: name,\n method,\n apiConfig,\n isCollectionClass: objectIsCollectionClass,\n ...(isModelClassName ? { isModelClassName } : {}),\n });\n if (decision.exposed) {\n exposed.push([name, method]);\n continue;\n }\n // CRUD reservation and non-public methods are not \"rejections\" worth\n // reporting: neither was ever a candidate custom action, and listing every\n // private helper would bury the rejections a developer can act on.\n if (decision.code === 'crud-reserved' || decision.code === 'not-public') {\n continue;\n }\n rejected.push([name, decision]);\n }\n\n return { exposed, rejected };\n}\n\n/**\n * Warn about the one rejection class that would be a structural failure rather\n * than a configuration choice: an action whose declared scope has no receiver\n * to bind. Both emitters carried this warning before #2686 moved the check into\n * the shared resolver, and the message text is preserved.\n *\n * It cannot currently fire — `resolveCustomActionMetadata` collapses a\n * contradicting scope back to the receiver-derived one, as it did before this\n * change; see `resolveActionReceiver` in `generators/custom-action.ts`. The\n * warning a developer actually sees for a contradicting declaration is\n * `warnDeclaredScopeMismatch` below.\n *\n * Every other rejection is silent here and reported with its reason through\n * the knowledge artifact instead, so a normal build is not buried in output\n * for the 2% of methods the heuristic legitimately withholds.\n */\nfunction warnUnhostedActions(\n className: string,\n rejected: Array<[string, ApiMethodExposure]>,\n): void {\n for (const [actionName, decision] of rejected) {\n if (decision.code !== 'no-receiver') continue;\n console.warn(\n `[smrt] Skipping ${className}.${actionName} - ${decision.reason}`,\n );\n }\n}\n\n/**\n * Report a declared `scope` that contradicts the method's actual receiver.\n *\n * The declaration is honored only where it AGREES; nothing in config can move\n * an instance method onto the class. Warning is the whole remedy — the route\n * is still emitted at the receiver-derived URL, so an author who expected the\n * other one learns why it is missing instead of silently getting nothing at\n * either address (#2686).\n */\nfunction warnDeclaredScopeMismatch(\n className: string,\n actionName: string,\n actionDef: MethodDefinition,\n apiConfig: unknown,\n effectiveScope: 'item' | 'collection',\n): void {\n const declared = resolveDeclaredScopeMismatch({\n actionName,\n method: actionDef,\n apiConfig,\n effectiveScope,\n });\n if (!declared) return;\n console.warn(\n `[smrt] ${className}.${actionName} declares scope '${declared}' but its receiver is ` +\n `${effectiveScope}-scoped, so the declared scope is ignored. A scope describes where a ` +\n `method already lives; it cannot move it. Make ${actionName} static to reach it on the ` +\n 'collection, or drop the scope option.',\n );\n}\n\n/**\n * Compute the set of action names (standard CRUD + custom methods) that the\n * API exposes for a given object definition. This is the same resolution used\n * to drive route generation, exposed so coherence checks (e.g. CLI vs API)\n * can ask \"what does the API expose?\" without re-implementing the logic.\n *\n * Pass a class inventory: without one the wire-ability heuristic cannot tell a\n * model class from an options interface and therefore accepts both, so the\n * caller silently disagrees with the emitters on the LARGEST group of withheld\n * methods (see `WireabilityOptions.isModelClassName`). Supply either\n * `manifest`, or `wireability.isModelClassName` when the caller's inventory is\n * the live registry rather than a manifest — `@happyvertical/smrt-users`' CLI\n * resource listing is the second kind. Both stay optional only because this is\n * public API.\n */\nexport function resolveApiActionSet(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n wireability: WireabilityOptions = {},\n): Set<string> {\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) return new Set();\n\n const objectIsCollectionClass = manifest\n ? isCollectionManifestClass(manifest, objectDef)\n : isCollectionClass(objectDef);\n const actions = objectIsCollectionClass\n ? new Set<string>()\n : new Set<string>(resolveStandardCrudActions(apiConfig));\n\n for (const [name] of resolveApiCustomActions(\n objectDef,\n manifest,\n objectIsCollectionClass,\n wireability,\n ).exposed) {\n actions.add(name);\n }\n\n return actions;\n}\n\n/**\n * Detail for a single cli-vs-api coherence violation.\n */\nexport interface CliApiCoherenceViolation {\n className: string;\n unreachable: string[];\n}\n\n/**\n * Resolve the effective CLI command set for an object, for the cli↔api\n * coherence lint. Two distinct resolutions, chosen by whether `cli.include`\n * is spelled out:\n *\n * **Explicit `cli.include`** (preserves the lint's exact pre-#2638\n * algorithm): the literal `include − exclude`, verbatim, whether or not an\n * entry resolves to a real CRUD verb or a scanned public method. This is\n * deliberate, not an oversight -- an `include` entry that names a typo, a\n * getter (never in the manifest's `methods` map), or a private/protected\n * method (the scanner drops these rather than recording `isPublic: false`,\n * so nothing else catches it) must still surface as \"unreachable\" so the\n * build fails loudly on the config mistake, the same way it always has.\n * Resolving it instead through `resolveCustomActionNames` -- which only\n * iterates real scanned methods -- would silently drop such an entry with no\n * error at all (final review, #2638).\n *\n * **Bare `cli: true`/`cli: {}`** (#2638, the new case this lint now\n * inspects): every public custom method minus exclude, exactly the \"every\n * public method minus exclude\" resolution this function shares with\n * `packages/core/src/generators/custom-action.ts`'s `resolveCustomActionNames`\n * -- lifecycle methods excluded, same as everywhere else. (Pre-#2664, core's\n * now-retired `CLIGenerator.listCommands()` applied the same resolution via\n * that helper too.)\n * CRUD verbs are NOT checked in this branch: a class that closes its API\n * entirely (`api: false`) while keeping a default-open, CLI/MCP-only admin\n * surface (`cli: true`/omitted) is a common, intentional combination (see\n * `cli.skipApiCheck`'s own \"in-process, no HTTP\" doc comment); blanket-\n * checking CRUD reachability for every such class would flag that existing,\n * legitimate pattern across the whole codebase, not just the #2638 defect\n * (confirmed by running this against the full monorepo build during\n * development — it did exactly that).\n */\nfunction resolveCliActionSet(objectDef: SmartObjectDefinition): Set<string> {\n const cliConfig = objectDef.decoratorConfig?.cli;\n if (cliConfig === false) return new Set();\n\n const included: string[] | undefined =\n typeof cliConfig === 'object' && cliConfig !== null\n ? cliConfig.include\n : undefined;\n const excluded: string[] =\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n Array.isArray(cliConfig.exclude)\n ? cliConfig.exclude\n : [];\n\n if (included) {\n return new Set(included.filter((cmd) => !excluded.includes(cmd)));\n }\n\n return resolveCustomActionNames(\n Object.entries(objectDef.methods || {}),\n { include: undefined, exclude: excluded },\n CRUD_OPERATIONS,\n );\n}\n\n/**\n * Inspect a manifest and return classes whose effective CLI command set —\n * `cli.include`/`cli.exclude` when spelled out, or (#2638) the same \"every\n * public method minus exclude\" default `cli: true`/`cli: {}` resolves to —\n * references a command not exposed via the API. Classes that opt out via\n * `cli: { skipApiCheck: true }` are skipped, and so is a class with\n * `cli: false` (no CLI surface at all).\n *\n * Throws nothing; returns the violation list so callers can choose to throw\n * or warn.\n */\nexport function findCliApiCoherenceViolations(\n manifest: SmartObjectManifest,\n): CliApiCoherenceViolation[] {\n const violations: CliApiCoherenceViolation[] = [];\n\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n const cliConfig = objectDef.decoratorConfig?.cli;\n if (cliConfig === false) continue;\n if (\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n cliConfig.skipApiCheck\n ) {\n continue;\n }\n\n const effectiveCliCommands = resolveCliActionSet(objectDef);\n if (effectiveCliCommands.size === 0) continue;\n\n const apiActionSet = resolveApiActionSet(objectDef, manifest);\n const unreachable = [...effectiveCliCommands]\n .filter((action) => !apiActionSet.has(action))\n .sort();\n\n if (unreachable.length > 0) {\n violations.push({ className, unreachable });\n }\n }\n\n return violations;\n}\n\n/**\n * Throw if any class in the manifest has an EXPLICIT `cli.include` command\n * that isn't reachable via the API. Default build-time gate; opt-out\n * per-class via `cli: { skipApiCheck: true }` (or globally via the vite\n * plugin option `validateCliApiCoherence: false`).\n *\n * This is deliberately narrower than `findCliApiCoherenceViolations` above.\n * That function is now fully correct for the broader `cli: true`/`cli: {}`\n * default surface too (#2638: same \"every public method minus exclude\"\n * resolution core's now-retired `CLIGenerator.listCommands()` used (#2664),\n * so a bare `cli: true` is inspected the same as an explicit `include`).\n * But `smrtPlugin()`'s default\n * `validateCliApiCoherence: true` calls this THROWING gate unconditionally\n * from every consuming package's own build (`configResolved`,\n * `vite-plugin/index.ts`) -- and a full-monorepo build during #2638\n * development showed that broader surface has thousands of pre-existing\n * public getters/business-logic methods (e.g.\n * `@happyvertical/smrt-ads:AdGroup.hasStarted`,\n * `@happyvertical/smrt-tags:Tag.getParent`) across ~28 packages that were\n * never meant to be REST-reachable and have no API route today. That\n * over-exposure is real, pre-existing, and unrelated to #2638's framework-\n * lifecycle-method defect -- flipping this gate to enforce it unconditionally\n * would break every one of those packages' builds today, which is a\n * repo-wide triage effort (add routes, or an explicit `cli.exclude`/\n * `skipApiCheck` per owner) this PR did not undertake and is out of its\n * file boundary. So the gate keeps its pre-#2638 blast radius -- classes\n * that spell out a non-empty `cli.include` -- while `findCliApiCoherenceViolations`\n * is complete and available (and covered by its own tests) for the broader\n * check once that pre-existing surface is triaged.\n */\nexport function validateCliIncludeAgainstApi(\n manifest: SmartObjectManifest,\n): void {\n const violations = findCliApiCoherenceViolations(manifest).filter(\n ({ className }) => {\n const cliConfig = manifest.objects[className]?.decoratorConfig?.cli;\n return (\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n Array.isArray(cliConfig.include) &&\n cliConfig.include.length > 0\n );\n },\n );\n if (violations.length === 0) return;\n\n const messages = violations.flatMap(({ className, unreachable }) =>\n unreachable.map(\n (action) =>\n `[smrt] ${className}.${action} is exposed as a CLI command but is not exposed via the api.\\n` +\n ` Either:\\n` +\n ` - Decorate '${action}' with @method({ expose: true }) to route it, or\\n` +\n ` - Add '${action}' to api.include, or\\n` +\n ` - Remove '${action}' from cli.include / add it to cli.exclude.\\n` +\n ` The CLI invokes methods over HTTP; methods without API routes are unreachable.\\n` +\n ` A public method is routed by default only when every parameter can be\\n` +\n ` built from JSON; @method({ expose: true }) overrides that for one method\\n` +\n ` without widening api.include. See withheldSurfaces in the knowledge\\n` +\n ` artifact for the reason this one was withheld (#2686).\\n` +\n ` If this CLI is intentionally invoked in-process (no HTTP), set\\n` +\n ` \\`cli: { skipApiCheck: true }\\` on the @smrt() decorator to acknowledge.`,\n ),\n );\n\n throw new Error(messages.join('\\n\\n'));\n}\n\n/**\n * Writes a route file, creating directories as needed\n */\nfunction writeRoute(dir: string, filename: string, content: string): string {\n try {\n // Create directory if needed\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write the file (writeFileSync is synchronous and will throw on failure)\n const filePath = join(dir, filename);\n writeFileSync(filePath, content, 'utf-8');\n console.log(`[smrt] Generated: ${filePath}`);\n return filePath;\n } catch (error) {\n console.error(`[smrt] [ERROR] Failed to write route file:`);\n console.error(`[smrt] [ERROR] Directory: ${dir}`);\n console.error(`[smrt] [ERROR] Filename: ${filename}`);\n console.error(`[smrt] [ERROR] Error:`, error);\n throw error;\n }\n}\n\n/**\n * Converts absolute file path to SvelteKit $lib alias import\n * For SvelteKit projects, uses $lib alias for better module resolution\n */\nfunction getSvelteKitImportPath(\n projectRoot: string,\n objectFilePath: string | undefined,\n objectsDir: string,\n className?: string,\n): string {\n // Handle undefined filePath by generating a default path\n // This allows tests to work without providing explicit file paths\n const filePath =\n objectFilePath ||\n join(projectRoot, objectsDir, `${className || 'Object'}.ts`);\n\n // Convert objectsDir to absolute path if it's relative\n const absoluteObjectsDir = objectsDir.startsWith('/')\n ? objectsDir\n : join(projectRoot, objectsDir);\n\n // Get the relative path from objectsDir to the file\n const relativePath = relative(absoluteObjectsDir, filePath);\n\n // Convert to forward slashes and remove extension\n const normalizedPath = relativePath.replace(/\\\\/g, '/');\n const withoutExtension = normalizedPath.replace(/\\.(ts|js|tsx|jsx)$/, '');\n\n // If objectsDir is under src/lib, use $lib alias\n if (objectsDir.includes('src/lib')) {\n const libSubpath = objectsDir.split('src/lib')[1] || '';\n const fullPath = libSubpath\n ? `${libSubpath}/${withoutExtension}`\n : withoutExtension;\n return `$lib${fullPath}`.replace(/\\/+/g, '/'); // Clean up double slashes\n }\n\n // Otherwise use relative path (fallback for non-standard layouts)\n return withoutExtension.startsWith('.')\n ? withoutExtension\n : `./${withoutExtension}`;\n}\n\n/**\n * Check if an object's source file is local to the project (not in node_modules).\n * The scanner sets packageName for all objects (including local ones from the\n * project's own package.json), so we check the filePath to distinguish.\n */\nfunction isLocalObject(\n projectRoot: string,\n objectDef: SmartObjectDefinition,\n): boolean {\n if (!objectDef.filePath) return false;\n return (\n objectDef.filePath.startsWith(projectRoot) &&\n !objectDef.filePath.includes('/node_modules/')\n );\n}\n\n/**\n * Generates collection route template (GET list, POST create)\n */\nfunction generateTypedRouteErrorHelper(): string {\n return `\nfunction smrtRouteErrorResponse(cause: unknown) {\n const failure = normalizeTypedHttpError(cause);\n if (failure) return json({ error: failure }, { status: failure.status });\n return json({ error: 'Internal server error' }, { status: 500 });\n}\n`;\n}\n\nfunction generateCollectionRouteTemplate(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n includedActions: string[],\n options: SvelteKitOptions,\n routeDir: string,\n): string {\n const hasGet = includedActions.includes('list');\n const hasPost = includedActions.includes('create');\n const modelType = resolveObjectTypeReference(\n projectRoot,\n className,\n objectDef,\n options,\n routeDir,\n );\n const serializers = resolveStandardRouteSerializers(\n objectDef.decoratorConfig?.api,\n );\n const serializerImports = serializers.importStatements.join('\\n');\n // A custom list serializer can render related-table data the per-table\n // change-feed version cannot observe (#1765), so such routes keep the v1\n // body-hash ETag; the default toPublicJSON path uses the v2 version source.\n const listUsesSerializer = !!serializers.listItemSerializerName;\n const readPermissionFields = collectReadPermissionFields(\n objectDef,\n semanticManifest,\n );\n const listUsesPermissionScopedBody = readPermissionFields.length > 0;\n const listUsesBodyHash = listUsesSerializer || listUsesPermissionScopedBody;\n // The build-time web-collection shape digest (#1764) salts the v2 read ETag so\n // a shape-only deploy (no table write) busts every read validator. Deterministic\n // for a given manifest — same value the generated virt-web module exports and\n // the client persistence namespace keys on.\n const webManifestHash = computeWebManifestHash(semanticManifest);\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n\n const imports = `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { error${hasPost ? ', json' : ''} } from '@sveltejs/kit';\n${\n serializerImports ? `${serializerImports}\\n` : ''\n}import { getCollection } from '${configImport}';\n${hasPost ? \"import { normalizeTypedHttpError } from '@happyvertical/smrt-core';\\n\" : ''}\n${modelType.importStatement ? `${modelType.importStatement}\\n` : ''}import type { RequestHandler } from './$types';\n// Note: ${className} is auto-registered by the Vite plugin scanner\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsRouteTenantContext(objectDef) ? generateTenantContextHelper(usesPrincipalContext(objectDef), isTenantScoped(objectDef)) : ''}${hasPost ? generateWritablePolicyHelper(objectDef) : ''}${hasPost ? generateTypedRouteErrorHelper() : ''}${hasGet ? generateListBoundsHelper(objectDef) : ''}${hasGet ? generateConditionalGetRouteHelper(objectDef.decoratorConfig?.api, { tenantScoped: isTenantScoped(objectDef), permissionScoped: listUsesPermissionScopedBody, modelName: className, useBodyHash: listUsesBodyHash, manifestHash: webManifestHash }) : ''}`;\n\n // #1782: tenant-scoped reads fail closed to global (NULL-tenant) rows when no\n // tenant context is active (public/anonymous read). Non-tenant models keep the\n // plain list/count.\n // #2367: every generated page is ordered. `LIST_ORDER_BY` is emitted as a\n // module constant so the ordering is visible in the generated file rather\n // than implied by the database's row order.\n const listAndCount = isTenantScoped(objectDef)\n ? ` const readScope = tenantReadScope();\n const items = await collection.list({ limit, offset, orderBy: LIST_ORDER_BY, where: readScope });\n const count = await collection.count({ where: readScope });`\n : ` const items = await collection.list({ limit, offset, orderBy: LIST_ORDER_BY });\n const count = await collection.count();`;\n\n const getHandler = hasGet\n ? `\n// List all ${className.toLowerCase()}s\nexport const GET: RequestHandler = async ({ locals, url, request }) => {\n${routeGuardPreamble(objectDef, false)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const { limit, offset } = listBounds(url);\n\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n${\n listUsesSerializer\n ? `${listAndCount}\n // Custom serializer may render related-table data → v1 body-hash ETag (#1765).\n const serializedItems = await Promise.all(\n items.map(async (item) =>\n applyReadPermissionRedaction(\n await ${serializers.listItemSerializerName}(item),\n publicJsonOptions,\n ),\n ),\n );\n return conditionalJson(request, { items: serializedItems, count, limit, offset });`\n : listUsesPermissionScopedBody\n ? `${listAndCount}\n // Field read permissions make the body vary by caller permissions → v1 body-hash ETag (#1565).\n const items_public = items.map((item) => item.toPublicJSON(publicJsonOptions));\n return conditionalJson(request, { items: items_public, count, limit, offset });`\n : ` // ETag v2 (#1765): the table-version ETag is checked first; on a concrete\n // If-None-Match the list query below never runs (zero-query 304).\n return conditionalVersionedRead(request, collection.db, collection.tableName, async () => {\n${listAndCount}\n const items_public = items.map((item) => item.toPublicJSON(publicJsonOptions));\n return { items: items_public, count, limit, offset };\n });`\n}\n};\n`\n : '';\n\n const postHandler = hasPost\n ? `\n// Create new ${className.toLowerCase()}\nexport const POST: RequestHandler = async ({ locals, request }) => {\n${routeGuardPreamble(objectDef, true)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const body: unknown = await request.json();\n const data = applyWritablePolicy(body);\n\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n try {\n const item = await collection.create(data);\n${\n serializers.itemSerializerName\n ? `\n const serializedItem = await ${serializers.itemSerializerName}(item);\n\n return json(\n applyReadPermissionRedaction(serializedItem, publicJsonOptions),\n { status: 201 },\n );`\n : `\n return json(item.toPublicJSON(publicJsonOptions), { status: 201 });`\n}\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n};\n`\n : '';\n\n return imports + getHandler + postHandler;\n}\n\nfunction generateCollectionLoad(\n className: string,\n options: { typeName?: string } = {},\n): string {\n const genericSuffix = options.typeName ? `<${options.typeName}>` : '';\n\n return [\n ` const collection = await getCollection${genericSuffix}(`,\n ` '${className}',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateNotFoundError(className: string): string {\n const singleLineNotFoundError = ` if (!item) throw error(404, '${className} not found');`;\n\n if (singleLineNotFoundError.length <= 100) {\n return singleLineNotFoundError;\n }\n\n return [\n ' if (!item)',\n ' throw error(',\n ' 404,',\n ` '${className} not found',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateCollectionNotRegisteredError(className: string): string {\n return [\n ' if (!collection)',\n ' throw error(',\n ' 500,',\n ` '${className} collection is not registered',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateClassNotRegisteredError(className: string): string {\n return [\n ' if (!registered)',\n ' throw error(',\n ' 500,',\n ` '${className} is not registered',`,\n ' );',\n ].join('\\n');\n}\n\n/**\n * Generates item route template (GET, PUT, DELETE)\n */\nfunction generateItemRouteTemplate(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n includedActions: string[],\n options: SvelteKitOptions,\n routeDir: string,\n): string {\n const hasGet = includedActions.includes('get');\n const hasPut = includedActions.includes('update');\n const hasDelete = includedActions.includes('delete');\n const simpleClassName = extractSimpleClassName(className);\n const modelType = resolveObjectTypeReference(\n projectRoot,\n className,\n objectDef,\n options,\n routeDir,\n );\n const serializers = resolveStandardRouteSerializers(\n objectDef.decoratorConfig?.api,\n );\n const serializerImports = serializers.importStatements.join('\\n');\n // A custom item serializer can render related-table data the per-table\n // change-feed version cannot observe (#1765), so such routes keep the v1\n // body-hash ETag; the default toPublicJSON path uses the v2 version source.\n const getUsesSerializer = !!serializers.itemSerializerName;\n const readPermissionFields = collectReadPermissionFields(\n objectDef,\n semanticManifest,\n );\n const getUsesPermissionScopedBody = readPermissionFields.length > 0;\n const getUsesBodyHash = getUsesSerializer || getUsesPermissionScopedBody;\n // The build-time web-collection shape digest (#1764) salts the v2 read ETag —\n // same value as the list route and the generated virt-web module (see above).\n const webManifestHash = computeWebManifestHash(semanticManifest);\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n\n const imports = `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { error${hasPut || hasDelete ? ', json' : ''} } from '@sveltejs/kit';\n${serializerImports ? `${serializerImports}\\n` : ''}import { getCollection } from '${configImport}';\n${hasPut || hasDelete ? \"import { normalizeTypedHttpError } from '@happyvertical/smrt-core';\\n\" : ''}\n${modelType.importStatement ? `${modelType.importStatement}\\n` : ''}import type { RequestHandler } from './$types';\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsRouteTenantContext(objectDef) ? generateTenantContextHelper(usesPrincipalContext(objectDef), isTenantScoped(objectDef)) : ''}${hasPut ? generateWritablePolicyHelper(objectDef) : ''}${hasPut || hasDelete ? generateTypedRouteErrorHelper() : ''}${hasGet ? generateConditionalGetRouteHelper(objectDef.decoratorConfig?.api, { tenantScoped: isTenantScoped(objectDef), permissionScoped: getUsesPermissionScopedBody, modelName: className, useBodyHash: getUsesBodyHash, manifestHash: webManifestHash }) : ''}`;\n\n // #1782: a tenant-scoped single read fails closed to global (NULL-tenant)\n // rows when no tenant context is active, so a public/anonymous GET /:id can't\n // fetch another tenant's row by id. Mutations (PUT/DELETE) require auth, so\n // they keep the plain id lookup and rely on the interceptor.\n const getForRead = isTenantScoped(objectDef)\n ? ` const readScope = tenantReadScope();\n const item = await collection.get(\n readScope ? { id: params.id, ...readScope } : params.id,\n );`\n : ` const item = await collection.get(params.id);`;\n\n const getHandler = hasGet\n ? `\n// Get single ${simpleClassName.toLowerCase()}\nexport const GET: RequestHandler = async ({ locals, params, request }) => {\n${routeGuardPreamble(objectDef, false)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n${\n getUsesSerializer\n ? `${getForRead}\n${generateNotFoundError(className)}\n // Custom serializer may render related-table data → v1 body-hash ETag (#1765).\n const serializedItem = await ${serializers.itemSerializerName}(item);\n return conditionalJson(\n request,\n applyReadPermissionRedaction(serializedItem, publicJsonOptions),\n );`\n : getUsesPermissionScopedBody\n ? `${getForRead}\n${generateNotFoundError(className)}\n // Field read permissions make the body vary by caller permissions → v1 body-hash ETag (#1565).\n return conditionalJson(request, item.toPublicJSON(publicJsonOptions));`\n : ` // ETag v2 (#1765): a concrete If-None-Match answers 304 without the row fetch\n // (a delete advances the version, so a since-deleted row can't false-match);\n // a wildcard \\`*\\` is deferred until the fetch confirms the row exists.\n return conditionalVersionedRead(request, collection.db, collection.tableName, async () => {\n${getForRead}\n${generateNotFoundError(className)}\n return item.toPublicJSON(publicJsonOptions);\n });`\n}\n};\n`\n : '';\n\n const putHandler = hasPut\n ? `\n// Update ${simpleClassName.toLowerCase()}\nexport const PUT: RequestHandler = async ({ locals, params, request }) => {\n${routeGuardPreamble(objectDef, true)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n const item = await collection.get(params.id);\n${generateNotFoundError(className)}\n\n const body: unknown = await request.json();\n const data = applyWritablePolicy(body);\n Object.assign(item, data);\n try {\n await item.save();\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n${\n serializers.itemSerializerName\n ? `\n const serializedItem = await ${serializers.itemSerializerName}(item);\n\n return json(applyReadPermissionRedaction(serializedItem, publicJsonOptions));`\n : `\n return json(item.toPublicJSON(publicJsonOptions));`\n}\n};\n`\n : '';\n\n const deleteHandler = hasDelete\n ? `\n// Delete ${simpleClassName.toLowerCase()}\nexport const DELETE: RequestHandler = async ({ locals, params }) => {\n${routeGuardPreamble(objectDef, true)}\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n const item = await collection.get(params.id);\n${generateNotFoundError(className)}\n\n try {\n await item.delete();\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n return json({ success: true });\n};\n`\n : '';\n\n return imports + getHandler + putHandler + deleteHandler;\n}\n\n/**\n * Generates custom action route template\n */\nfunction generateActionRouteTemplate(\n projectRoot: string,\n routeDir: string,\n routeSpecs: GeneratedActionRouteSpec[],\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): string {\n if (routeSpecs.length === 0) {\n throw new Error('Cannot generate a custom action route without handlers');\n }\n\n const [firstSpec] = routeSpecs;\n const { lookupClassName, routeConfig, hostType } = firstSpec;\n assertCompatibleCustomActionRouteSpecs(routeSpecs);\n const lookupModelType = resolveObjectTypeReference(\n projectRoot,\n lookupClassName,\n firstSpec.lookupObjectDef,\n options,\n routeDir,\n );\n const hostModelType = resolveObjectTypeReference(\n projectRoot,\n firstSpec.hostClassName,\n objectDef,\n options,\n routeDir,\n );\n const typeImports = mergeImportStatements([\n lookupModelType.importStatement,\n hostModelType.importStatement,\n ]);\n\n // Import only the decoders a handler in this file actually calls -- an\n // unconditional import would leave unused symbols in every generated action\n // route. A GET handler may need the number/boolean query-string decoders too,\n // since `URLSearchParams` hands it strings for both (#2686).\n const decoderImports = new Set<string>();\n for (const spec of routeSpecs) {\n if (hasSingleOptionsParameter(spec.actionDef)) continue;\n for (const parameter of spec.actionDef.parameters ?? []) {\n const decoder =\n spec.routeConfig?.method === 'GET'\n ? queryStringDecoderFor(parameter.type)\n : declaredTypeAcceptsDate(parameter.type)\n ? 'toCustomActionDate'\n : undefined;\n if (decoder) decoderImports.add(decoder);\n }\n }\n const coreImports = [\n 'normalizeCustomActionFailure',\n 'normalizeTypedHttpError',\n ...[...decoderImports].sort(),\n ].join(', ');\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n const importBlock = [\n \"import { error, json } from '@sveltejs/kit';\",\n `import { ${coreImports} } from '@happyvertical/smrt-core';`,\n hostType === 'collection' || routeConfig.scope !== 'collection'\n ? `import { getCollection } from '${configImport}';`\n : [\n `import '${configImport}';`,\n \"import { ObjectRegistry } from '@happyvertical/smrt-core';\",\n ].join('\\n'),\n typeImports,\n \"import type { RequestHandler } from './$types';\",\n ]\n .filter(Boolean)\n .join('\\n');\n\n const tenantScoped =\n isTenantScoped(objectDef) ||\n routeSpecs.some(\n (spec) => !!spec.lookupObjectDef && isTenantScoped(spec.lookupObjectDef),\n );\n const principalContext =\n usesPrincipalContext(objectDef) ||\n routeSpecs.some(\n (spec) =>\n !!spec.lookupObjectDef && usesPrincipalContext(spec.lookupObjectDef),\n );\n const needsTenantContext = tenantScoped || principalContext;\n const handlers = routeSpecs\n .map((spec) =>\n generateActionRouteHandler(\n spec.lookupClassName,\n spec.actionName,\n spec.actionDef,\n spec.routeConfig,\n spec.hostType,\n tenantScoped,\n needsTenantContext,\n lookupModelType.typeName,\n hostModelType.typeName,\n ),\n )\n .join('\\n');\n\n return `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\n${importBlock}\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsTenantContext ? generateTenantContextHelper(principalContext, tenantScoped) : ''}\n${generateTypedRouteErrorHelper()}\n${handlers}`;\n}\n\nfunction generateActionRouteHandler(\n lookupClassName: string,\n actionName: string,\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n hostType: 'item' | 'collection',\n tenantScoped: boolean,\n needsTenantContext: boolean,\n lookupTypeName: string,\n hostTypeName: string,\n): string {\n const handlerName = routeConfig.method;\n // Mutating verbs require auth even when reads are public (#1540). Tenant-scoped\n // objects also establish tenant context so the action runs filtered.\n const guardLines = [\n ` requireRouteAuth(locals, ${routeConfig.method !== 'GET'});`,\n ];\n if (needsTenantContext) {\n guardLines.push(' establishTenantContext(locals);');\n }\n const authGuardLine = guardLines.join('\\n');\n const hasInput = actionDef.parameters.length > 0;\n const needsRequest = hasInput;\n const collectionHandlerArgs = buildRouteHandlerArgs(\n routeConfig.pathParamNames.length > 0,\n needsRequest,\n );\n const itemHandlerArgs = buildRouteHandlerArgs(true, needsRequest);\n\n if (hostType === 'collection') {\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n actionDef.isStatic,\n );\n const receiverExpression = actionDef.isStatic\n ? 'CollectionClass'\n : 'typedCollection';\n const staticTargetLoad = actionDef.isStatic\n ? ` const CollectionClass = typedCollection.constructor as typeof ${hostTypeName};\\n`\n : '';\n const scopedOptions = buildScopedOptionsForTenantRead(\n actionDef,\n routeConfig,\n tenantScoped,\n );\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n scopedOptions.optionsIdentifier,\n routeConfig.method,\n );\n\n return `// Custom collection method: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${collectionHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(lookupClassName, { typeName: lookupTypeName })}\n const typedCollection = collection as unknown as ${hostTypeName};\n${generateCollectionNotRegisteredError(lookupClassName)}\n${staticTargetLoad}\n\n${optionsLoad}${scopedOptions.source} let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n receiverExpression,\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n }\n\n if (routeConfig.scope === 'collection') {\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n true,\n );\n const scopedOptions = buildScopedOptionsForTenantRead(\n actionDef,\n routeConfig,\n tenantScoped,\n );\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n scopedOptions.optionsIdentifier,\n routeConfig.method,\n );\n return `// Custom collection action: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${collectionHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const registered = ObjectRegistry.getClass('${lookupClassName}');\n${generateClassNotRegisteredError(lookupClassName)}\n\n${optionsLoad}${scopedOptions.source} const ClassRef = registered.constructor as typeof ${hostTypeName};\n let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n 'ClassRef',\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n }\n\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n false,\n );\n const scopedItemLoad =\n tenantScoped && routeConfig.method === 'GET'\n ? ` const readScope = tenantReadScope();\n const item = await collection.get(\n readScope ? { id: params.id, ...readScope } : params.id,\n );`\n : ' const item = await collection.get(params.id);';\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n 'options',\n routeConfig.method,\n );\n return `// Custom action: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${itemHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(lookupClassName, { typeName: lookupTypeName })}\n${scopedItemLoad}\n${generateNotFoundError(lookupClassName)}\n\n${optionsLoad} let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n 'item',\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n}\n\nfunction generateKnowledgeRouteTemplate(\n knowledge: DomainKnowledgeConfig,\n artifact: Record<string, unknown> | null,\n): string {\n const api = knowledge.api ?? {};\n const includeDocs = api.includeDocs === true;\n const includePrompts = api.includePrompts === true;\n const requireAdmin = api.requireAdmin !== false;\n const artifactLiteral = artifact ? JSON.stringify(artifact) : 'null';\n\n return `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { dev } from '$app/environment';\nimport { error, json } from '@sveltejs/kit';\nimport type { RequestHandler } from './$types';\n\nconst INCLUDE_DOCS_BY_DEFAULT = ${JSON.stringify(includeDocs)};\nconst INCLUDE_PROMPTS_BY_DEFAULT = ${JSON.stringify(includePrompts)};\nconst REQUIRE_ADMIN = ${JSON.stringify(requireAdmin)};\nconst KNOWLEDGE_ARTIFACT: Record<string, unknown> | null = ${artifactLiteral};\n\nif (!dev && !REQUIRE_ADMIN) {\n console.warn('[smrt] PUBLIC knowledge API route enabled; unauthenticated responses are sanitized.');\n}\n\nexport const GET: RequestHandler = async ({ locals, url, setHeaders }) => {\n setHeaders({ 'cache-control': 'private, no-store' });\n\n if (!dev && REQUIRE_ADMIN && !isKnowledgeAdmin(locals)) {\n throw error(403, 'SMRT knowledge requires dev mode or admin access');\n }\n\n const artifact = readKnowledgeArtifact();\n const includeDocs = queryBoolean(url, 'includeDocs', INCLUDE_DOCS_BY_DEFAULT);\n const includePrompts = queryBoolean(\n url,\n 'includePrompts',\n INCLUDE_PROMPTS_BY_DEFAULT,\n );\n\n return json(sanitizeKnowledgeArtifact(artifact, {\n includeDocs,\n includePrompts,\n publicAccess: !REQUIRE_ADMIN,\n }));\n};\n\nfunction readKnowledgeArtifact(): Record<string, unknown> {\n if (!KNOWLEDGE_ARTIFACT) throw error(404, 'SMRT knowledge artifact not found');\n return KNOWLEDGE_ARTIFACT;\n}\n\nfunction queryBoolean(url: URL, name: string, defaultValue: boolean): boolean {\n const value = url.searchParams.get(name);\n if (value === null) return defaultValue;\n return value === 'true';\n}\n\nfunction sanitizeKnowledgeArtifact(\n artifact: Record<string, unknown>,\n options: { includeDocs: boolean; includePrompts: boolean; publicAccess: boolean },\n): Record<string, unknown> {\n const sanitized = { ...artifact };\n\n if (!options.includeDocs) {\n delete sanitized.agentDoc;\n // Linked module docs (#2108) are the same authored prose as agentDoc, just\n // split across siblings — they must drop with it, not leak past the flag.\n delete sanitized.moduleDocs;\n }\n\n if (!options.includePrompts) {\n sanitized.prompts = [];\n }\n\n if (options.publicAccess) {\n delete sanitized.dependencies;\n delete sanitized.sourceHashes;\n delete sanitized.sourceManifestPath;\n delete sanitized.agentDocPath;\n }\n\n return sanitized;\n}\n\nfunction recordValue(value: unknown, key: string): unknown {\n if (!value || typeof value !== 'object') return undefined;\n return (value as Record<string, unknown>)[key];\n}\n\nfunction isKnowledgeAdmin(locals: unknown): boolean {\n if (!locals || typeof locals !== 'object') return false;\n const localRecord = locals as Record<string, unknown>;\n if (\n localRecord.smrtKnowledgeAdmin === true ||\n localRecord.smrtAdmin === true\n ) {\n return true;\n }\n\n const userRoles = rolesFrom(localRecord.user);\n const sessionRoles = rolesFrom(recordValue(localRecord.session, 'user'));\n return [...userRoles, ...sessionRoles].some((role) =>\n ['admin', 'owner', 'superadmin'].includes(role),\n );\n}\n\nfunction rolesFrom(value: unknown): string[] {\n if (!value || typeof value !== 'object') return [];\n const roleList = recordValue(value, 'roles');\n const roles = Array.isArray(roleList) ? roleList : [recordValue(value, 'role')];\n return roles\n .filter((role): role is string => typeof role === 'string')\n .map((role) => role.toLowerCase());\n}\n`;\n}\n\n/**\n * Updates .gitignore to exclude auto-generated routes\n */\nfunction updateGitignore(\n projectRoot: string,\n generatedRoutePaths: readonly string[],\n routeRoot: string,\n): void {\n const gitignorePath = join(projectRoot, '.gitignore');\n\n // Read existing .gitignore or create empty string\n let gitignoreContent = '';\n if (existsSync(gitignorePath)) {\n gitignoreContent = readFileSync(gitignorePath, 'utf-8');\n }\n\n const generatedPaths = [\n ...new Set(\n [...generatedRoutePaths, ...findGeneratedRouteFiles(routeRoot)].map(\n (path) => gitignorePatternForPath(relative(projectRoot, path)),\n ),\n ),\n ].sort((a, b) => a.localeCompare(b));\n const updatedContent = updateGeneratedRouteIgnoreBlock(\n gitignoreContent,\n generatedPaths,\n );\n\n if (updatedContent !== gitignoreContent) {\n writeFileSync(gitignorePath, updatedContent, 'utf-8');\n console.log('[smrt] Updated .gitignore with generated route paths');\n }\n}\n\nfunction findGeneratedRouteFiles(routeRoot: string): string[] {\n if (!existsSync(routeRoot)) return [];\n const files: string[] = [];\n for (const entry of readdirSync(routeRoot, { withFileTypes: true })) {\n const path = join(routeRoot, entry.name);\n if (entry.isDirectory()) {\n files.push(...findGeneratedRouteFiles(path));\n } else if (\n entry.isFile() &&\n entry.name === '+server.ts' &&\n readFileSync(path, 'utf-8').startsWith(AUTO_GENERATED_ROUTE_HEADER)\n ) {\n files.push(path);\n }\n }\n return files;\n}\n\nfunction gitignorePatternForPath(path: string): string {\n // Generated SvelteKit item routes include literal `[id]` segments. Escape\n // every Git pattern metacharacter so the managed block ignores files, not\n // glob expressions that happen to resemble their paths.\n return path.replaceAll('\\\\', '/').replaceAll(/([*?[\\]\\\\!#])/g, '\\\\$1');\n}\n\n/**\n * Whether a line has the shape versions before #2185 wrote beneath the legacy\n * header: a recursive `+server.ts` wildcard, optionally negated. The pattern is\n * matched by shape rather than against the currently configured `routesDir`,\n * because a project that moved `routesDir` after adopting the plugin (as\n * `@happyvertical/smrt-content` did, `src/routes/api` -> `src/routes/api/v1`)\n * still carries the pair its earlier `routesDir` produced.\n */\nfunction isLegacyGeneratedRoutePattern(line: string): boolean {\n // A comment is a boundary, never part of the run — otherwise a note that\n // happens to end in the same suffix would be swallowed with it.\n if (line.startsWith('#')) {\n return false;\n }\n return /^!?[^\\s].*\\/\\*\\*\\/\\+server\\.ts$/.test(line);\n}\n\n/**\n * Drop the generator-owned legacy header together with the contiguous run of\n * legacy-shaped patterns directly beneath it. Only that recognized run is\n * migrated: the first line that is not legacy-shaped ends it, so an application\n * rule — including an identical broad pattern the project owns elsewhere in the\n * file — survives untouched.\n */\nfunction stripLegacyGeneratedRouteIgnores(lines: string[]): void {\n const headerIndex = lines.indexOf(LEGACY_GITIGNORE_HEADER);\n if (headerIndex === -1) {\n return;\n }\n\n let end = headerIndex + 1;\n while (end < lines.length && isLegacyGeneratedRoutePattern(lines[end])) {\n end += 1;\n }\n\n // A header with nothing recognizable beneath it is left alone rather than\n // guessed at, matching the bounded-marker handling above.\n if (end > headerIndex + 1) {\n lines.splice(headerIndex, end - headerIndex);\n }\n}\n\nfunction updateGeneratedRouteIgnoreBlock(\n gitignoreContent: string,\n generatedPaths: readonly string[],\n): string {\n const lines = gitignoreContent.split('\\n');\n const managedBlock = [\n GITIGNORE_MANAGED_BLOCK_START,\n ...generatedPaths,\n GITIGNORE_MANAGED_BLOCK_END,\n ];\n\n if (\n lines.includes(GITIGNORE_MANAGED_BLOCK_START) ||\n lines.includes(GITIGNORE_MANAGED_BLOCK_END)\n ) {\n // Migration runs even once the bounded block exists: a project generated by\n // the first #2185 release kept its unmatched legacy pair, and the negation\n // in that pair silently re-includes anything the bounded block stops\n // listing. Strip it before locating the markers so the indices stay valid.\n stripLegacyGeneratedRouteIgnores(lines);\n\n const startIndex = lines.indexOf(GITIGNORE_MANAGED_BLOCK_START);\n const endIndex = lines.indexOf(GITIGNORE_MANAGED_BLOCK_END);\n if (startIndex === -1 || endIndex < startIndex) {\n // An incomplete marker pair may have been authored by a consumer. Do\n // not guess at its boundary or remove any user-managed ignore rules.\n return gitignoreContent;\n }\n\n lines.splice(\n startIndex,\n endIndex - startIndex + 1,\n ...(generatedPaths.length > 0 ? managedBlock : []),\n );\n return lines.join('\\n');\n }\n\n stripLegacyGeneratedRouteIgnores(lines);\n\n if (generatedPaths.length === 0) {\n return lines.join('\\n');\n }\n\n let updatedContent = lines.join('\\n');\n if (updatedContent.length > 0 && !updatedContent.endsWith('\\n')) {\n updatedContent += '\\n';\n }\n if (updatedContent.length > 0 && !updatedContent.endsWith('\\n\\n')) {\n updatedContent += '\\n';\n }\n\n return `${updatedContent}${managedBlock.join('\\n')}\\n`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sveltekit-generator.js","names":[],"sources":["../../src/vite-plugin/sveltekit-generator.ts"],"sourcesContent":["/**\n * SvelteKit route auto-generation from SMRT objects\n * Generates real TypeScript files in src/routes/api/ based on discovered SMRT objects\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport type { DomainKnowledgeConfig } from '@happyvertical/smrt-types';\nimport { generateConditionalGetRouteHelper } from '../generators/conditional-get.js';\nimport {\n type ApiMethodExposure,\n CRUD_OPERATIONS,\n createManifestClassNamePredicate,\n declaredTypeAcceptsDate,\n isCrudOperation,\n isFrameworkLifecycleMethod,\n queryStringDecoderFor,\n resolveApiMethodExposure,\n resolveCustomActionMetadata,\n resolveCustomActionNames,\n resolveDeclaredScopeMismatch,\n resolveEffectiveActionMetadata,\n type WireabilityOptions,\n} from '../generators/custom-action.js';\nimport {\n buildDefaultListOrderBy,\n DEFAULT_LIST_LIMIT,\n MAX_LIST_LIMIT,\n} from '../query-bounds.js';\nimport { isFrameworkBaseClass } from '../registry/framework-base-classes.js';\nimport type {\n ApiConfig,\n ApiHttpMethod,\n ApiSerializerReference,\n} from '../registry/types.js';\nimport type {\n MethodDefinition,\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nimport { generateChangesRoute } from './changes-route.js';\nimport {\n generateDevPlaneRoute,\n willGenerateDevPlaneRoute,\n} from './dev-plane-route.js';\nimport { generateEventsRoute } from './events-route.js';\nimport {\n generateResourcesRoute,\n reservesResourcesRoute,\n} from './resources-route.js';\nimport { AUTO_GENERATED_ROUTE_HEADER } from './route-header.js';\nimport { resolveSvelteKitConfigImport } from './sveltekit-config-import.js';\nimport { canonicalSvelteKitPath } from './sveltekit-path.js';\nimport {\n collectSyncApplyTargets,\n generateSyncApplyRoute,\n} from './sync-apply-route.js';\nimport {\n computeWebManifestHash,\n isCollectionManifestClass,\n orderedManifestObjectEntries,\n resolveCollectionItemObject,\n resolveCollectionItemTypeName,\n} from './web-collections.js';\n\nexport interface SvelteKitOptions {\n enabled: boolean;\n routesDir: string;\n objectsDir: string;\n configPath?: string; // default: 'src/lib/server'\n configFileName?: string; // default: 'smrt.ts'\n /** Internal absolute consumer registration entrypoints for a coordinated host. */\n consumerRegistrationPaths?: readonly string[];\n /**\n * Apply kebab-case to custom-method URL segments (e.g. `discoverFromUrl`\n * becomes `/discover-from-url`). Opt-in for one minor; default flips in the\n * next major. An explicit `api.routes[name].path` always wins over this.\n */\n kebabRoutes?: boolean;\n /** Domain knowledge API route generation. Disabled unless explicitly enabled. */\n knowledge?: DomainKnowledgeConfig;\n /**\n * Change-feed `_changes` route generation (#1758). Enabled by default\n * (the route is auth-guarded fail-closed); set `enabled: false` to skip.\n */\n changesRoute?: { enabled?: boolean };\n /**\n * Opt-in in-app runtime dev-plane route (`_dev/[...tool]`, #2782). Dev\n * mode only; requires `@happyvertical/smrt-dev-mcp` in the consumer and\n * `SMRT_DEV_MCP_TOKEN` at runtime.\n */\n devPlaneRoute?: { enabled?: boolean };\n /**\n * Live `_events` SSE route generation (#1763). Enabled by default (the route\n * is auth-guarded fail-closed, same-origin only); set `enabled: false` to\n * skip. `maxSubscribers` caps active streams per process (#1860); 0 means\n * unlimited.\n *\n * Cross-origin subscription (#1861) is opt-in and fail-closed: provide\n * `allowedOrigins` (an explicit allowlist — never `*`) and set\n * `allowCredentials: true` so an allow-listed browser client can subscribe\n * with a credentialed `EventSource` (`withCredentials: true`). The generated\n * route echoes the specific request `Origin` only when it is allow-listed,\n * adds `Access-Control-Allow-Credentials: true`, and otherwise stays\n * same-origin only. Auth (an authenticated principal on `locals`) is\n * unchanged — CORS only lets the cookie reach the guard.\n */\n eventsRoute?: {\n enabled?: boolean;\n maxSubscribers?: number;\n allowedOrigins?: string[];\n allowCredentials?: boolean;\n };\n /**\n * CLI discovery `_resources` route generation (#2663). Enabled by default,\n * but only ever emitted when `@happyvertical/smrt-users` is resolvable\n * from the consumer (see `resources-route.ts` for the detection\n * mechanism) — set `enabled: false` to opt out even when it is present. A\n * pre-existing hand-written `_resources` route is always preserved.\n */\n resourcesRoute?: { enabled?: boolean };\n /** Reject route paths owned by distinct selected identities before cleanup. */\n rejectRouteCollisions?: boolean;\n}\n\n// Keep this aligned with biome.json formatter.lineWidth.\nconst BIOME_LINE_WIDTH = 80;\nconst GITIGNORE_MANAGED_BLOCK_START =\n '# BEGIN SMRT auto-generated routes (Vite plugin)';\nconst GITIGNORE_MANAGED_BLOCK_END =\n '# END SMRT auto-generated routes (Vite plugin)';\nconst LEGACY_GITIGNORE_HEADER =\n '# SMRT auto-generated routes (from Vite plugin)';\n\nexport interface ResolvedApiActionRouteConfig {\n scope: 'item' | 'collection';\n method: ApiHttpMethod;\n pathSegments: string[];\n pathParamNames: string[];\n}\n\ninterface GeneratedActionRouteSpec {\n lookupClassName: string;\n lookupObjectDef?: SmartObjectDefinition;\n hostClassName: string;\n actionName: string;\n actionDef: MethodDefinition;\n routeConfig: ResolvedApiActionRouteConfig;\n hostType: 'item' | 'collection';\n}\n\ninterface ResolvedStandardRouteSerializers {\n importStatements: string[];\n itemSerializerName?: string;\n listItemSerializerName?: string;\n}\n\ninterface GeneratedTypeReference {\n typeName: string;\n importStatement?: string;\n}\n\n/**\n * Extract simple class name from potentially qualified name.\n * Qualified names follow the pattern: @scope/package:ClassName\n *\n * Issue #870: Manifests may contain qualified names which generate invalid\n * import statements like: import { @pkg:Class } from '@pkg'\n *\n * @param qualifiedName - Class name that may be qualified (e.g., \"@pkg:Class\" or \"Class\")\n * @returns Simple class name (e.g., \"Class\")\n */\nfunction extractSimpleClassName(qualifiedName: string): string {\n const colonIndex = qualifiedName.indexOf(':');\n if (colonIndex !== -1) {\n return qualifiedName.substring(colonIndex + 1);\n }\n return qualifiedName;\n}\n\n/**\n * Check if an object definition represents a SmrtCollection class.\n * Collection classes share route paths with their item class (via inherited `collection` field),\n * so generating routes for both would cause file collisions.\n */\nfunction isCollectionClass(objectDef: SmartObjectDefinition): boolean {\n return objectDef.extends === 'SmrtCollection' || !!objectDef.extendsTypeArg;\n}\n\nfunction getRegistrationPackageName(\n manifest: SmartObjectManifest,\n objectDef: SmartObjectDefinition,\n isLocal: boolean,\n): string | undefined {\n if (isLocal) {\n return objectDef.packageName ?? manifest.packageName;\n }\n\n return objectDef.packageName;\n}\n\nfunction toSingleQuotedStringLiteral(value: string): string {\n const jsonLiteral = JSON.stringify(value);\n const jsonContent = jsonLiteral.slice(1, -1).replaceAll(\"'\", \"\\\\'\");\n return `'${jsonContent}'`;\n}\n\nfunction getApiConfigObject(apiConfig: unknown): ApiConfig | null {\n if (!apiConfig || typeof apiConfig !== 'object') {\n return null;\n }\n\n return apiConfig as ApiConfig;\n}\n\nfunction isSameSerializerReference(\n left?: ApiSerializerReference,\n right?: ApiSerializerReference,\n): boolean {\n return (\n !!left &&\n !!right &&\n left.importPath === right.importPath &&\n left.exportName === right.exportName\n );\n}\n\nfunction resolveStandardRouteSerializers(\n apiConfig: unknown,\n): ResolvedStandardRouteSerializers {\n const config = getApiConfigObject(apiConfig);\n const itemSerializer = config?.serializers?.item;\n const listItemSerializer =\n config?.serializers?.listItem || config?.serializers?.item;\n\n const importStatements: string[] = [];\n let itemSerializerName: string | undefined;\n let listItemSerializerName: string | undefined;\n\n if (itemSerializer) {\n itemSerializerName = 'serializeItemResponse';\n importStatements.push(\n `import { ${itemSerializer.exportName} as ${itemSerializerName} } from '${itemSerializer.importPath}';`,\n );\n }\n\n if (listItemSerializer) {\n if (isSameSerializerReference(listItemSerializer, itemSerializer)) {\n listItemSerializerName = itemSerializerName;\n } else {\n listItemSerializerName = 'serializeListItemResponse';\n importStatements.push(\n `import { ${listItemSerializer.exportName} as ${listItemSerializerName} } from '${listItemSerializer.importPath}';`,\n );\n }\n }\n\n return {\n importStatements,\n itemSerializerName,\n listItemSerializerName,\n };\n}\n\nfunction isValidTypeIdentifier(name: string): boolean {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);\n}\n\nfunction resolveObjectTypeReference(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition | undefined,\n options: SvelteKitOptions,\n routeDir?: string,\n): GeneratedTypeReference {\n const simpleClassName = extractSimpleClassName(className);\n\n if (!objectDef || !isValidTypeIdentifier(simpleClassName)) {\n return { typeName: \"import('@happyvertical/smrt-core').SmrtObject\" };\n }\n\n const external =\n !isLocalObject(projectRoot, objectDef) && objectDef.packageName;\n const importPath = external\n ? objectDef.importPath || objectDef.packageName\n : getRouteTypeImportPath(\n projectRoot,\n objectDef,\n options,\n simpleClassName,\n routeDir,\n );\n const exportName = external\n ? objectDef.exportName || simpleClassName\n : simpleClassName;\n\n return {\n typeName: simpleClassName,\n importStatement: `import type { ${exportName}${exportName === simpleClassName ? '' : ` as ${simpleClassName}`} } from '${importPath}';`,\n };\n}\n\nfunction getRouteTypeImportPath(\n projectRoot: string,\n objectDef: SmartObjectDefinition,\n options: SvelteKitOptions,\n simpleClassName: string,\n routeDir?: string,\n): string {\n if (objectDef.filePath) {\n const srcLibDir = join(projectRoot, 'src/lib');\n if (objectDef.filePath.startsWith(`${srcLibDir}/`)) {\n const libRelative = relative(srcLibDir, objectDef.filePath)\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n return `$lib/${libRelative}`.replace(/\\/+/g, '/');\n }\n\n if (routeDir) {\n const routeRelative = relative(routeDir, objectDef.filePath)\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n return routeRelative.startsWith('.')\n ? routeRelative\n : `./${routeRelative}`;\n }\n }\n\n return getSvelteKitImportPath(\n projectRoot,\n objectDef.filePath,\n options.objectsDir,\n simpleClassName,\n );\n}\n\nfunction mergeImportStatements(\n importStatements: Array<string | undefined>,\n): string {\n return Array.from(new Set(importStatements.filter(Boolean))).join('\\n');\n}\n\nfunction findObjectDefByRegistryKey(\n manifest: SmartObjectManifest,\n className: string,\n): SmartObjectDefinition | undefined {\n return (\n manifest.objects[className] ??\n Object.values(manifest.objects).find(\n (objectDef) => objectDef.className === extractSimpleClassName(className),\n )\n );\n}\n\n/**\n * Collect property names marked `@field({ readonly: true })` for an object, so\n * the generated write surfaces can strip them from request bodies (#1540, 2b).\n */\nfunction collectReadonlyFieldNames(objectDef: SmartObjectDefinition): string[] {\n const fields = objectDef.fields || {};\n const names: string[] = [];\n for (const [name, def] of Object.entries(fields)) {\n const meta = (def as { _meta?: Record<string, unknown> })._meta;\n if (\n (def as { readonly?: boolean }).readonly === true ||\n meta?.readonly === true\n ) {\n names.push(name);\n }\n }\n return names;\n}\n\n/**\n * Resolve the optional `@smrt({ api: { writable: [...] } })` allowlist. When\n * present, only these fields may be set from a create/update request body.\n */\nfunction getApiWritableAllowlist(apiConfig: unknown): string[] | null {\n const config = getApiConfigObject(apiConfig);\n return Array.isArray(config?.writable) ? config.writable : null;\n}\n\n/**\n * Emit the mass-assignment guard helper injected into generated route files\n * (#1540, 2b). It strips framework/server-managed (`id`, `tenantId`,\n * timestamps, `_`-prefixed) and `@field({ readonly: true })` fields from\n * request bodies, and — when a `writable` allowlist is configured — intersects\n * with it. Applied to every generated `create`/`update` handler.\n */\nfunction generateWritablePolicyHelper(\n objectDef: SmartObjectDefinition,\n): string {\n const readonly = collectReadonlyFieldNames(objectDef);\n const writable = getApiWritableAllowlist(objectDef.decoratorConfig?.api);\n\n return `\n// Mass-assignment guard (#1540): strip framework/server-managed + read-only\n// fields from create/update request bodies before they reach the model.\nconst WRITABLE_ALLOWLIST: string[] | null = ${\n writable ? JSON.stringify(writable) : 'null'\n };\nconst READONLY_FIELDS: string[] = ${JSON.stringify(readonly)};\nconst SERVER_MANAGED_FIELDS = [\n 'id',\n 'tenantId',\n 'tenant_id',\n 'createdAt',\n 'created_at',\n 'updatedAt',\n 'updated_at',\n];\n\nfunction applyWritablePolicy(data: unknown): Record<string, unknown> {\n if (!data || typeof data !== 'object') return {};\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (key.startsWith('_')) continue;\n if (SERVER_MANAGED_FIELDS.includes(key)) continue;\n if (READONLY_FIELDS.includes(key)) continue;\n if (WRITABLE_ALLOWLIST && !WRITABLE_ALLOWLIST.includes(key)) continue;\n result[key] = value;\n }\n return result;\n}\n`;\n}\n\n/**\n * Resolve the `@smrt({ api: { public } })` posture (fail-closed default).\n * - `false`/unset → all routes require an authenticated principal.\n * - `true` → all routes are public.\n * - `'read'` → reads are public, mutations still require auth.\n */\nfunction getApiPublicAccess(apiConfig: unknown): boolean | 'read' {\n const config = getApiConfigObject(apiConfig);\n const value = config?.public;\n if (value === true || value === 'read') {\n return value;\n }\n return false;\n}\n\nfunction toFieldColumnAlias(fieldName: string): string {\n return fieldName\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/[-\\s]+/g, '_')\n .toLowerCase();\n}\n\nfunction manifestObjectKey(objectDef: SmartObjectDefinition): string {\n return objectDef.qualifiedName ?? objectDef.className;\n}\n\nfunction manifestObjectExtends(\n objectDef: SmartObjectDefinition,\n parent: SmartObjectDefinition,\n): boolean {\n const extendsQualified = objectDef.extendsQualified;\n const extendsName = objectDef.extends;\n return (\n (typeof extendsQualified === 'string' &&\n extendsQualified === parent.qualifiedName) ||\n (typeof extendsName === 'string' &&\n (extendsName === parent.className ||\n extendsName === parent.qualifiedName))\n );\n}\n\nfunction findManifestParent(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): SmartObjectDefinition | undefined {\n return Object.values(manifest.objects).find((candidate) =>\n manifestObjectExtends(objectDef, candidate),\n );\n}\n\nfunction collectStiHierarchyObjects(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): SmartObjectDefinition[] {\n if (!manifest) return [objectDef];\n\n let cursor: SmartObjectDefinition | undefined = objectDef;\n let stiBase: SmartObjectDefinition | undefined =\n cursor.decoratorConfig?.tableStrategy === 'sti' ? cursor : undefined;\n while (cursor) {\n const parent = findManifestParent(cursor, manifest);\n if (!parent) break;\n if (parent.decoratorConfig?.tableStrategy === 'sti') {\n stiBase = parent;\n }\n cursor = parent;\n }\n\n if (!stiBase) return [objectDef];\n\n const members = new Map<string, SmartObjectDefinition>();\n const visit = (current: SmartObjectDefinition) => {\n const key = manifestObjectKey(current);\n if (members.has(key)) return;\n members.set(key, current);\n for (const candidate of Object.values(manifest.objects)) {\n if (candidate === current) continue;\n if (manifestObjectExtends(candidate, current)) {\n visit(candidate);\n }\n }\n };\n\n visit(stiBase);\n return [...members.values()];\n}\n\nfunction collectReadPermissionFields(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): Array<[string, string]> {\n const result: Array<[string, string]> = [];\n const seen = new Set<string>();\n for (const member of collectStiHierarchyObjects(objectDef, manifest)) {\n for (const [name, def] of Object.entries(member.fields ?? {})) {\n const permission =\n typeof def.readPermission === 'string'\n ? def.readPermission\n : typeof def._meta?.readPermission === 'string'\n ? def._meta.readPermission\n : undefined;\n if (!permission) continue;\n for (const fieldName of [name, toFieldColumnAlias(name)]) {\n const key = `${fieldName}\\0${permission}`;\n if (seen.has(key)) continue;\n seen.add(key);\n result.push([fieldName, permission]);\n }\n }\n }\n return result;\n}\n\n/**\n * Emit the fail-closed authorization guard injected into generated route files\n * (#1540, 2c). Every generated CRUD/action handler calls `requireRouteAuth`,\n * which throws 401 unless the route is `public` or `locals` carries an\n * authenticated principal. Mirrors the knowledge-route `isKnowledgeAdmin`\n * precedent. Mutating verbs require auth even when reads are public.\n */\nfunction generateAuthGuardHelper(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n): string {\n const publicAccess = getApiPublicAccess(objectDef.decoratorConfig?.api);\n const readPermissionFields = collectReadPermissionFields(objectDef, manifest);\n\n return `\n// Fail-closed authorization (#1540): generated routes require an authenticated\n// principal on \\`locals\\` unless explicitly marked \\`@smrt({ api: { public } })\\`.\nconst PUBLIC_ACCESS: boolean | 'read' = ${JSON.stringify(publicAccess)};\nconst READ_PERMISSION_FIELDS: Array<[string, string]> = ${JSON.stringify(readPermissionFields)};\n\ninterface PublicJsonOptions {\n permissions?: Iterable<string>;\n}\n\nfunction hasAuthenticatedPrincipal(locals: unknown): boolean {\n if (!locals || typeof locals !== 'object') return false;\n const l = locals as Record<string, unknown>;\n // Only a resolved, object-shaped principal counts. We intentionally do NOT\n // treat \\`locals.auth\\` as a signal: Auth.js/SvelteKit put a callable\n // \\`auth()\\` helper on every request (including anonymous ones), so honoring\n // it would fail OPEN. Booleans don't count either (no convention sets\n // \\`locals.user = true\\`); the only boolean accepted is the explicit\n // \\`smrtAuth\\` opt-in marker.\n const isResolvedPrincipal = (v: unknown) =>\n typeof v === 'object' && v !== null;\n return (\n isResolvedPrincipal(l.user) ||\n isResolvedPrincipal(l.session) ||\n l.smrtAuth === true\n );\n}\n\nfunction requireRouteAuth(locals: unknown, mutating: boolean): void {\n if (PUBLIC_ACCESS === true) return;\n if (PUBLIC_ACCESS === 'read' && !mutating) return;\n if (!hasAuthenticatedPrincipal(locals)) {\n throw error(401, 'Authentication required');\n }\n}\n\nfunction getPublicJsonOptions(locals: unknown): PublicJsonOptions {\n const l = readJsonRecord(locals);\n const permissions = l.permissions ?? l.permissionSet ?? l.smrtPermissions;\n if (Array.isArray(permissions) || permissions instanceof Set) {\n return { permissions };\n }\n return {};\n}\n\nfunction hasReadPermission(\n options: PublicJsonOptions,\n permission: string,\n): boolean {\n if (!options.permissions) return false;\n for (const granted of options.permissions) {\n if (granted === permission) return true;\n }\n return false;\n}\n\nfunction applyReadPermissionRedaction(\n value: unknown,\n options: PublicJsonOptions,\n seen: WeakSet<object> = new WeakSet(),\n): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return null;\n if (hasPublicJson(value)) {\n seen.add(value);\n return applyReadPermissionRedaction(\n value.toPublicJSON(options),\n options,\n seen,\n );\n }\n if (Array.isArray(value)) {\n seen.add(value);\n return value.map((entry) =>\n applyReadPermissionRedaction(entry, options, seen),\n );\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n seen.add(value);\n const out = { ...(value as Record<string, unknown>) };\n const metaData =\n out._meta_data && typeof out._meta_data === 'object'\n ? { ...(out._meta_data as Record<string, unknown>) }\n : null;\n for (const [fieldName, permission] of READ_PERMISSION_FIELDS) {\n if (hasReadPermission(options, permission)) continue;\n delete out[fieldName];\n if (metaData) delete metaData[fieldName];\n }\n if (metaData) out._meta_data = metaData;\n for (const [key, entry] of Object.entries(out)) {\n out[key] = applyReadPermissionRedaction(entry, options, seen);\n }\n return out;\n}\n\n// Sensitive-field-safe serialization for custom-action results (#1540): a\n// custom method may return a SmrtObject (or one nested in an array/plain\n// object), so recurse and route each through toPublicJSON() rather than letting\n// JSON.stringify call toJSON(). Non-plain instances (Date, etc.) and primitives\n// pass through; a cycle guard prevents infinite loops.\ninterface PublicJsonSource {\n toPublicJSON(options?: PublicJsonOptions): unknown;\n}\n\nfunction hasPublicJson(value: object): value is PublicJsonSource {\n return (\n 'toPublicJSON' in value &&\n typeof (value as { toPublicJSON?: unknown }).toPublicJSON === 'function'\n );\n}\n\nfunction readJsonRecord(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return {};\n return value as Record<string, unknown>;\n}\n\nfunction toPublicResult(\n value: unknown,\n options: PublicJsonOptions,\n seen: WeakSet<object> = new WeakSet(),\n): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (seen.has(value)) return null;\n if (hasPublicJson(value)) {\n seen.add(value);\n return toPublicResult(value.toPublicJSON(options), options, seen);\n }\n if (Array.isArray(value)) {\n seen.add(value);\n return value.map((entry) => toPublicResult(entry, options, seen));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(\n value as Record<string, unknown>,\n )) {\n out[key] = toPublicResult(entry, options, seen);\n }\n return out;\n}\n`;\n}\n\n/**\n * Whether an object is `@TenantScoped` (carries a `tenantScoped` config in its\n * `@smrt()`/`@TenantScoped()` decorator). Drives tenant-context establishment in\n * generated routes (#1540, facet 2).\n */\nfunction isTenantScoped(objectDef: SmartObjectDefinition): boolean {\n return !!objectDef.decoratorConfig?.tenantScoped;\n}\n\n/**\n * Whether generated routes must publish the authenticated principal into the\n * tenancy ALS without making the model itself tenant-scoped. This is an\n * explicit model-level opt-in: body data is never an identity source.\n */\nfunction usesPrincipalContext(objectDef: SmartObjectDefinition): boolean {\n const api = getApiConfigObject(objectDef.decoratorConfig?.api);\n return api?.principalContext === true;\n}\n\nfunction needsRouteTenantContext(objectDef: SmartObjectDefinition): boolean {\n return isTenantScoped(objectDef) || usesPrincipalContext(objectDef);\n}\n\n/**\n * Emit the page-bounds guard and the deterministic ordering constant for a\n * generated list route (#2367).\n *\n * The route used to parse its own bounds with\n * `Number(url.searchParams.get('limit')) || 50`, which has three faults: it\n * accepts `NaN` from any non-numeric input and binds it (PostgreSQL answers\n * `invalid input syntax for type bigint` — a 500 for a caller typo), it folds a\n * deliberate `limit=0` into 50, and it has no ceiling, so `?limit=100000000` is\n * a full table scan plus a full hydration pass on a public endpoint.\n *\n * The helper is emitted into the route rather than imported from\n * `@happyvertical/smrt-core` so the generated file stays readable on its own and\n * the bound is visible at the call site; the constants come from core so there\n * is still one source of truth.\n */\nfunction generateListBoundsHelper(objectDef: SmartObjectDefinition): string {\n const orderBy = resolveDefaultListOrderBy(objectDef);\n return `\n/** Deterministic list ordering (#2367); matching index is #2363. */\nconst LIST_ORDER_BY = ${JSON.stringify(orderBy)};\n\n/**\n * Parse \\`?limit\\`/\\`?offset\\` (#2367): default when absent, 400 when malformed,\n * clamped to ${MAX_LIST_LIMIT} when oversized.\n */\nfunction listBounds(url: URL): { limit: number; offset: number } {\n const parse = (name: 'limit' | 'offset', fallback: number, max?: number): number => {\n const raw = url.searchParams.get(name);\n if (raw === null || raw === '') {\n return max === undefined ? fallback : Math.min(fallback, max);\n }\n if (!/^\\\\d+$/.test(raw.trim())) {\n throw error(400, \\`Invalid \\${name}: '\\${raw}' is not a non-negative integer.\\`);\n }\n const value = Number(raw.trim());\n if (!Number.isSafeInteger(value)) {\n throw error(400, \\`Invalid \\${name}: '\\${raw}' is not a non-negative integer.\\`);\n }\n return max === undefined ? value : Math.min(value, max);\n };\n\n return {\n limit: parse('limit', ${DEFAULT_LIST_LIMIT}, ${MAX_LIST_LIMIT}),\n offset: parse('offset', 0),\n };\n}\n`;\n}\n\n/**\n * Deterministic default ordering for a generated list route (#2367).\n *\n * The list route pages with `LIMIT`/`OFFSET` and previously emitted no\n * `ORDER BY` at all. That is not pagination: without an ordering PostgreSQL may\n * return rows in any order and is free to pick a different one per query, so\n * page 2 can repeat rows from page 1 and skip others entirely — silently, and\n * only under concurrency or a plan change, which is why it survived review.\n *\n * `created_at DESC` alone is not enough (rows created in the same tick tie), so\n * the primary key follows as a total-order tiebreak. The matching index is\n * #2363.\n */\nfunction resolveDefaultListOrderBy(\n objectDef: SmartObjectDefinition,\n): readonly string[] {\n // A class declaring its own primary key has no `id` column to tie-break on\n // (`id`/`slug`/`context` are omitted for custom-PK classes), so order by the\n // declared key instead.\n //\n // The flag is read from BOTH `_meta.primaryKey` and the top level: scanner\n // manifests — the input this generator actually runs on — carry it under\n // `_meta`, while decorator option bags mirror some flags at the top level.\n // Checking only the top level silently never matches, which is exactly the\n // case that would emit an `id` tiebreak for a table without an `id` column.\n const customPrimaryKey = Object.entries(objectDef.fields ?? {}).find(\n ([, fieldDef]) =>\n fieldDef?._meta?.primaryKey === true ||\n (fieldDef as { primaryKey?: boolean } | undefined)?.primaryKey === true,\n )?.[0];\n\n return buildDefaultListOrderBy(customPrimaryKey);\n}\n\n/**\n * Emit the tenant-context establishment + fail-closed read-scope helpers for\n * `@TenantScoped` objects (#1540 facet 2; #1782). Generated handlers call\n * `establishTenantContext(locals)` after the auth guard so every query runs\n * inside the tenant context derived from the authenticated principal — engaging\n * the `@TenantScoped` interceptors that auto-filter by tenant.\n *\n * `establishTenantContext` reads the canonical `locals.tenantId` set by the\n * smrt-users auth hook (with `user`/`session` fallbacks). It is a no-op when a\n * context is already active (e.g. an upstream tenancy handle) or when the\n * request carries no tenant (anonymous / global principal).\n *\n * When no context could be established, an `optional`-mode read would otherwise\n * fall through the interceptor UNFILTERED and return rows from ALL tenants (the\n * interceptor only hard-fails `required` mode) — the #1782 leak. So read\n * handlers additionally call `tenantReadScope()`, which restricts reads to\n * NULL-tenant (global) rows only when tenancy is enabled but no context is\n * active. Both helpers are imported only for tenant-scoped routes, which already\n * depend on `@happyvertical/smrt-tenancy`.\n */\nfunction generateTenantContextHelper(\n requirePrincipal: boolean,\n includeReadScope: boolean,\n): string {\n const principalGuard = requirePrincipal\n ? ` if (\n typeof tenantId !== 'string' || !tenantId ||\n typeof userId !== 'string' || !userId ||\n !permissions\n ) return;\n`\n : '';\n const contextArgument = requirePrincipal\n ? '{ tenantId, userId, permissions }'\n : '{ tenantId }';\n const tenancyImport = includeReadScope\n ? 'enterTenantContext, getCurrentTenant, hasTenantContext, isSuperAdminBypass, isTenancyEnabled'\n : 'enterTenantContext, hasTenantContext';\n const readScopeHelpers = includeReadScope\n ? `\n// Fail-closed read scope (#1782): a public/anonymous read on a @TenantScoped\n// model has no tenant context, so the tenancy interceptor (optional mode) would\n// pass the query through UNFILTERED and return every tenant's rows. When tenancy\n// is enabled but no context was established, restrict reads to NULL-tenant\n// (global) rows only — mirroring the dispatch resolver + _changes convention:\n// tenancy enforced with no context => global rows only. Returns undefined when a\n// context is active (the interceptor filters by it) or tenancy is disabled.\nfunction tenantReadScope(): { tenantId: null } | undefined {\n return isTenancyEnabled() && !hasTenantContext()\n ? { tenantId: null }\n : undefined;\n}\n\n// Custom GET actions that accept a single options object may perform their\n// own reads instead of calling generated list/get handlers. Give those actions\n// an explicit tenant scope: active tenant when present, NULL-tenant global rows\n// when tenancy is enabled but no tenant context exists. Super-admin bypass\n// stays unscoped so admin callers keep deliberate cross-tenant access.\nfunction tenantReadOptionsScope(): { tenantId: string | null } | undefined {\n if (!isTenancyEnabled() || isSuperAdminBypass()) {\n return undefined;\n }\n return { tenantId: getCurrentTenant()?.tenantId ?? null };\n}\n`\n : '';\n return `\nimport { ${tenancyImport} } from '@happyvertical/smrt-tenancy';\n\nfunction establishTenantContext(locals: unknown): void {\n if (hasTenantContext()) return;\n if (!locals || typeof locals !== 'object') return;\n const l = locals as Record<string, unknown>;\n const user = l.user as Record<string, unknown> | undefined;\n const session = l.session as Record<string, unknown> | undefined;\n const tenantId = l.tenantId ?? user?.tenantId ?? session?.tenantId;\n const userId = l.userId ?? user?.id ?? user?.userId ?? session?.userId;\n const rawPermissions = l.permissions;\n const permissions =\n rawPermissions instanceof Set && [...rawPermissions].every((value) => typeof value === 'string')\n ? rawPermissions\n : Array.isArray(rawPermissions) && rawPermissions.every((value) => typeof value === 'string')\n ? new Set(rawPermissions)\n : undefined;\n${principalGuard}\n if (typeof tenantId === 'string' && tenantId) {\n enterTenantContext(\n ${contextArgument},\n );\n }\n}\n${readScopeHelpers}\n`;\n}\n\n/**\n * The per-handler guard preamble: the fail-closed auth check (#1540 2c) plus, for\n * tenant-scoped objects, tenant-context establishment (#1540 facet 2).\n */\nfunction routeGuardPreamble(\n objectDef: SmartObjectDefinition,\n mutating: boolean,\n): string {\n const lines = [` requireRouteAuth(locals, ${mutating});`];\n if (needsRouteTenantContext(objectDef)) {\n lines.push(' establishTenantContext(locals);');\n }\n return lines.join('\\n');\n}\n\nfunction normalizeApiHttpMethod(method?: string): ApiHttpMethod {\n switch (method?.toUpperCase()) {\n case 'GET':\n case 'POST':\n case 'PUT':\n case 'PATCH':\n case 'DELETE':\n return method.toUpperCase() as ApiHttpMethod;\n default:\n return 'POST';\n }\n}\n\n/**\n * Convert a camelCase / PascalCase method name to a kebab-case URL segment.\n * Examples:\n * discoverFromUrl -> discover-from-url\n * XMLExport -> xml-export\n * URL -> url\n * a1B2c3 -> a1-b2c3\n *\n * Known limitation: consecutive uppercase acronyms aren't split apart, e.g.\n * `HTMLAPIExport` becomes `htmlapi-export` rather than `html-api-export`.\n * Override with an explicit `api.routes[name].path` if you need a specific\n * segmentation.\n */\nexport function methodNameToKebab(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n .toLowerCase();\n}\n\nfunction normalizeCustomRoutePath(\n actionName: string,\n path?: string,\n options: { kebabRoutes?: boolean } = {},\n): string[] {\n // Explicit path override always wins, and is used verbatim (split on /).\n if (path) {\n const segments = path\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean);\n if (segments.length > 0) {\n return segments;\n }\n }\n\n const segment = options.kebabRoutes\n ? methodNameToKebab(actionName)\n : actionName;\n return [segment];\n}\n\nfunction extractRoutePathParamNames(pathSegments: string[]): string[] {\n return pathSegments\n .filter((segment) => /^\\[[^\\]]+\\]$/.test(segment))\n .map((segment) => segment.slice(1, -1))\n .filter(Boolean);\n}\n\nexport function resolveApiActionRouteConfig(\n actionName: string,\n actionDef: { isStatic?: boolean; decoratorConfig?: Record<string, unknown> },\n apiConfig: unknown,\n routeOptions: { kebabRoutes?: boolean } = {},\n defaultScope: 'item' | 'collection' = actionDef.isStatic\n ? 'collection'\n : 'item',\n): ResolvedApiActionRouteConfig {\n // `@method({ httpMethod, path })` wins field by field over the class-level\n // `api.routes[action]` entry, so migrating one option off the map does not\n // reset the ones left on it (#2686).\n const effective = resolveEffectiveActionMetadata({\n actionName,\n method: actionDef,\n apiConfig,\n });\n\n const pathSegments = normalizeCustomRoutePath(\n actionName,\n effective.path,\n routeOptions,\n );\n\n const scope = resolveCustomActionMetadata({\n actionName,\n method: actionDef,\n apiConfig,\n defaultScope,\n }).scope;\n\n return {\n scope,\n method: normalizeApiHttpMethod(effective.httpMethod),\n pathSegments,\n pathParamNames: extractRoutePathParamNames(pathSegments),\n };\n}\n\nfunction buildRouteHandlerArgs(\n includeParams: boolean,\n includeRequest: boolean,\n): string {\n // `locals` is always destructured so the fail-closed auth guard (#1540) can\n // inspect the authenticated principal.\n const args: string[] = ['locals'];\n\n if (includeParams) {\n args.push('params');\n }\n\n if (includeRequest) {\n args.push('request');\n }\n\n return `{ ${args.join(', ')} }`;\n}\n\nfunction buildPathParamsObjectLiteral(pathParamNames: string[]): string {\n if (pathParamNames.length === 0) {\n return '{}';\n }\n\n return `{\n${pathParamNames\n .map(\n (paramName) =>\n ` ${buildObjectTypeProperty(paramName)}: ${buildRouteParamAccess(paramName)},`,\n )\n .join('\\n')}\n }`;\n}\n\nfunction hasSingleOptionsParameter(actionDef: MethodDefinition): boolean {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n return parameters.length === 1 && parameters[0]?.name === 'options';\n}\n\nfunction buildActionInvocationArgs(\n actionDef: MethodDefinition,\n optionsIdentifier = 'options',\n httpMethod?: string,\n): string[] {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n if (parameters.length === 0) {\n return [];\n }\n\n if (hasSingleOptionsParameter(actionDef)) {\n return [optionsIdentifier];\n }\n\n return parameters.map((parameter, index) => {\n const access = buildOptionsPropertyAccess(parameter.name);\n // A JSON body and a query string can only carry a `Date` as its ISO\n // string, so hydrate it here. The wire-ability gate accepts a `Date`\n // parameter precisely BECAUSE this conversion exists; drop one and the\n // other must go too, or the generator writes a route that 500s on the\n // first `getTime()` (#2686). The cast restores the declared parameter\n // type, which the runtime helper widens to `unknown`.\n // A GET handler builds its options from `URLSearchParams`, so EVERY value\n // is a string and `limit: number` reached the method as `'2'`. A JSON body\n // carries real numbers and booleans, so decode only on GET; `Date` is\n // hydrated on both because a JSON body cannot carry one either (#2686).\n const decoder =\n httpMethod === 'GET'\n ? queryStringDecoderFor(parameter.type)\n : declaredTypeAcceptsDate(parameter.type)\n ? 'toCustomActionDate'\n : undefined;\n return decoder ? `${decoder}(${access}) as ActionArgs[${index}]` : access;\n });\n}\n\nfunction buildObjectTypeProperty(propertyName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propertyName)) {\n return propertyName;\n }\n\n return JSON.stringify(propertyName);\n}\n\nfunction buildSingleQuotedStringLiteral(value: string): string {\n return `'${value.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}'`;\n}\n\nfunction buildRouteParamAccess(paramName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(paramName)) {\n return `params.${paramName}`;\n }\n\n return `params[${buildSingleQuotedStringLiteral(paramName)}]`;\n}\n\nfunction buildActionTargetTypeExpression(\n targetTypeName: string,\n isStatic: boolean,\n): string {\n return isStatic ? `(typeof ${targetTypeName})` : targetTypeName;\n}\n\nfunction buildActionArgsTypeAlias(\n actionName: string,\n targetTypeName: string,\n isStatic: boolean,\n): string {\n const targetTypeExpression = buildActionTargetTypeExpression(\n targetTypeName,\n isStatic,\n );\n return ` type ActionArgs = Parameters<${targetTypeExpression}[${buildSingleQuotedStringLiteral(actionName)}]>;`;\n}\n\nfunction buildActionOptionsTypeAlias(actionDef: MethodDefinition): string {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n\n if (parameters.length <= 1 && parameters[0]?.name === 'options') {\n return '';\n }\n\n return [\n ' type ActionOptions = {',\n ...parameters.map(\n (parameter, index) =>\n ` ${buildObjectTypeProperty(parameter.name)}: ActionArgs[${index}];`,\n ),\n ' };',\n ].join('\\n');\n}\n\nfunction buildActionOptionsLoad(\n actionName: string,\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n targetTypeName: string,\n isStatic: boolean,\n): string {\n const parameters = Array.isArray(actionDef.parameters)\n ? actionDef.parameters\n : [];\n if (parameters.length === 0) {\n return '';\n }\n\n const hasPathParams = routeConfig.pathParamNames.length > 0;\n const pathParamsObjectLiteral = buildPathParamsObjectLiteral(\n routeConfig.pathParamNames,\n );\n const isSingleOptionsParameter =\n parameters.length === 1 && parameters[0]?.name === 'options';\n const lines = [\n buildActionArgsTypeAlias(actionName, targetTypeName, isStatic),\n ];\n const optionsTypeAlias = buildActionOptionsTypeAlias(actionDef);\n if (optionsTypeAlias) {\n lines.push(optionsTypeAlias);\n }\n\n if (routeConfig.method === 'GET') {\n if (hasPathParams) {\n lines.push(\n ` const pathParams = ${pathParamsObjectLiteral};`,\n ' const options = {',\n ' ...Object.fromEntries(new URL(request.url).searchParams.entries()),',\n ' ...pathParams,',\n ` } as ${isSingleOptionsParameter ? 'ActionArgs[0]' : 'ActionOptions'};`,\n '',\n );\n } else {\n lines.push(\n ...(isSingleOptionsParameter\n ? [\n ' const searchParams = new URL(request.url).searchParams;',\n \" const optionsMarker = searchParams.get('__smrt_options');\",\n ' const options = (',\n \" optionsMarker === 'undefined' ||\",\n ' (optionsMarker === null && searchParams.size === 0)',\n ' ? undefined',\n \" : optionsMarker === 'null'\",\n ' ? null',\n \" : optionsMarker === 'object'\",\n ' ? {}',\n ' : Object.fromEntries(',\n ' [...searchParams.entries()].filter(',\n \" ([key]) => key !== '__smrt_options',\",\n ' ),',\n ' )',\n ' ) as ActionArgs[0];',\n ]\n : [\n ' const options = Object.fromEntries(',\n ' new URL(request.url).searchParams.entries(),',\n ' ) as ActionOptions;',\n ]),\n '',\n );\n }\n return lines.join('\\n');\n }\n\n if (hasPathParams) {\n lines.push(\n ` const pathParams = ${pathParamsObjectLiteral};`,\n ' const rawBody = await request.text();',\n \" const body: unknown = rawBody.trim() === '' ? undefined : JSON.parse(rawBody);\",\n ' const options = {',\n ' ...readJsonRecord(body),',\n ' ...pathParams,',\n ` } as ${isSingleOptionsParameter ? 'ActionArgs[0]' : 'ActionOptions'};`,\n '',\n );\n return lines.join('\\n');\n }\n\n lines.push(\n ' const rawBody = await request.text();',\n \" const body: unknown = rawBody.trim() === '' ? undefined : JSON.parse(rawBody);\",\n );\n if (isSingleOptionsParameter) {\n lines.push(' const options = body as ActionArgs[0];', '');\n } else {\n lines.push(' const options = readJsonRecord(body) as ActionOptions;', '');\n }\n return lines.join('\\n');\n}\n\nfunction buildOptionsPropertyAccess(propertyName: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propertyName)) {\n return `options.${propertyName}`;\n }\n\n const escapedPropertyName = propertyName\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\");\n\n return `options['${escapedPropertyName}']`;\n}\n\nfunction buildActionInvocationExpression(\n receiverExpression: string,\n actionName: string,\n invocationArgs: string[],\n): string {\n const singleLineInvocation = `await ${receiverExpression}.${actionName}(${invocationArgs.join(', ')})`;\n const singleLineResultAssignment = ` const result = ${singleLineInvocation};`;\n\n if (singleLineResultAssignment.length <= 100) {\n return singleLineInvocation;\n }\n\n return [\n `await ${receiverExpression}.${actionName}(`,\n ...invocationArgs.map((argument) => ` ${argument},`),\n ' )',\n ].join('\\n');\n}\n\nfunction buildScopedOptionsForTenantRead(\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n tenantScoped: boolean,\n): { source: string; optionsIdentifier: string } {\n // The generator can only pass tenant read scope to methods that expose an\n // options object. Zero-argument methods that perform their own raw reads must\n // infer tenant scope in their implementation or adopt the options contract.\n if (\n !tenantScoped ||\n routeConfig.method !== 'GET' ||\n !hasSingleOptionsParameter(actionDef)\n ) {\n return { source: '', optionsIdentifier: 'options' };\n }\n\n return {\n source: ` const readScope = tenantReadOptionsScope();\n const scopedOptions = readScope\n ? ({ ...options, ...readScope } as ActionArgs[0])\n : options;\n\n`,\n optionsIdentifier: 'scopedOptions',\n };\n}\n\nfunction findItemClassRegistryKey(\n className: string,\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): string {\n const itemObject = resolveCollectionItemObject(manifest, objectDef);\n if (!itemObject) {\n return resolveCollectionItemTypeName(manifest, objectDef) || className;\n }\n\n const manifestMatch = Object.entries(manifest.objects).find(\n ([, manifestObject]) => manifestObject === itemObject,\n );\n return manifestMatch?.[0] || itemObject.className;\n}\n\ntype CustomActionRouteGroupSpec = Pick<\n GeneratedActionRouteSpec,\n 'actionName' | 'hostType' | 'lookupClassName' | 'routeConfig'\n>;\n\nfunction assertCompatibleCustomActionRouteSpecs(\n routeSpecs: readonly CustomActionRouteGroupSpec[],\n): void {\n const [firstSpec] = routeSpecs;\n if (!firstSpec) return;\n\n const { hostType, lookupClassName, routeConfig } = firstSpec;\n const hasMixedHosts = routeSpecs.some(\n (spec) =>\n spec.hostType !== hostType ||\n spec.lookupClassName !== lookupClassName ||\n spec.routeConfig.scope !== routeConfig.scope,\n );\n\n if (hasMixedHosts) {\n throw new Error(\n `Cannot generate mixed custom route handlers for ${lookupClassName}. ` +\n 'All handlers sharing a route path must target the same host type and scope.',\n );\n }\n}\n\nfunction groupCustomActionRoutes<T extends CustomActionRouteGroupSpec>(\n actionSpecs: Array<{\n routeDir: string;\n spec: T;\n }>,\n): Map<string, T[]> {\n const groupedRoutes = new Map<string, T[]>();\n\n for (const { routeDir, spec } of actionSpecs) {\n const existing = groupedRoutes.get(routeDir) || [];\n const duplicateMethod = existing.find(\n (candidate) => candidate.routeConfig.method === spec.routeConfig.method,\n );\n\n if (duplicateMethod) {\n throw new Error(\n `Duplicate custom API route handler for ${routeDir} (${spec.routeConfig.method}). ` +\n `Methods ${duplicateMethod.actionName} and ${spec.actionName} resolve to the same generated route.`,\n );\n }\n\n existing.push(spec);\n groupedRoutes.set(routeDir, existing);\n }\n\n for (const routeSpecs of groupedRoutes.values()) {\n assertCompatibleCustomActionRouteSpecs(routeSpecs);\n }\n\n return groupedRoutes;\n}\n\n/** Reject selected identities that would write the same endpoint file. */\nexport function assertNoCrossObjectRouteCollisions(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n exposureManifest: SmartObjectManifest,\n reservedRoutePaths: ReadonlySet<string> = new Set(),\n): void {\n type RouteWriter =\n | 'crud-collection'\n | 'crud-item'\n | 'custom-action'\n | 'sync-apply'\n | 'changes'\n | 'dev-plane'\n | 'events'\n | 'resources'\n | 'knowledge';\n const claims = new Map<string, { owner: string; writer: RouteWriter }>();\n const claimPath = (\n routePath: string,\n routeDir: string,\n owner: string,\n writer: RouteWriter,\n ) => {\n const canonicalRoutePath = canonicalSvelteKitPath(routePath);\n const prior = claims.get(canonicalRoutePath);\n if (prior && (prior.owner !== owner || prior.writer !== writer)) {\n throw new Error(\n `Conflicting SvelteKit route ${routeDir}: ${prior.owner} (${prior.writer}) and ${owner} (${writer}) would write the same handler`,\n );\n }\n claims.set(canonicalRoutePath, { owner, writer });\n };\n const claim = (routeDir: string, owner: string, writer: RouteWriter) =>\n claimPath(\n join(projectRoot, routeDir, '+server.ts'),\n routeDir,\n owner,\n writer,\n );\n for (const routePath of reservedRoutePaths) {\n claimPath(\n resolve(routePath),\n relative(projectRoot, routePath),\n 'producer knowledge',\n 'knowledge',\n );\n }\n for (const [className, objectDef] of orderedManifestObjectEntries(manifest)) {\n if (isFrameworkBaseClass(objectDef.className, objectDef.packageName))\n continue;\n const routeDir = join(options.routesDir, objectDef.collection);\n if (isCollectionManifestClass(manifest, objectDef)) {\n const actionSpecs = resolveApiCustomActions(\n objectDef,\n exposureManifest,\n true,\n ).exposed.map(([actionName, actionDef]) => {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n objectDef.decoratorConfig?.api,\n { kebabRoutes: options.kebabRoutes },\n 'collection',\n );\n return {\n routeDir: join(routeDir, ...routeConfig.pathSegments),\n spec: {\n actionName,\n hostType: 'collection' as const,\n lookupClassName: findItemClassRegistryKey(\n className,\n objectDef,\n manifest,\n ),\n routeConfig,\n },\n };\n });\n for (const [actionRouteDir] of groupCustomActionRoutes(actionSpecs)) {\n claim(actionRouteDir, className, 'custom-action');\n }\n continue;\n }\n const actions = resolveStandardCrudActions(objectDef.decoratorConfig?.api);\n if (actions.some((action) => action === 'list' || action === 'create'))\n claim(routeDir, className, 'crud-collection');\n if (\n actions.some(\n (action) =>\n action === 'get' || action === 'update' || action === 'delete',\n )\n )\n claim(join(routeDir, '[id]'), className, 'crud-item');\n const actionSpecs = resolveApiCustomActions(\n objectDef,\n exposureManifest,\n false,\n ).exposed.map(([actionName, actionDef]) => {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n objectDef.decoratorConfig?.api,\n { kebabRoutes: options.kebabRoutes },\n );\n return {\n routeDir: join(\n routeConfig.scope === 'collection'\n ? routeDir\n : join(routeDir, '[id]'),\n ...routeConfig.pathSegments,\n ),\n spec: {\n actionName,\n hostType: 'item' as const,\n lookupClassName: className,\n routeConfig,\n },\n };\n });\n for (const [actionRouteDir] of groupCustomActionRoutes(actionSpecs)) {\n claim(actionRouteDir, className, 'custom-action');\n }\n }\n // These generator-owned utility files share the same filesystem namespace.\n // Claim only paths their current output predicates can emit.\n if (collectSyncApplyTargets(manifest).length > 0) {\n claim(join(options.routesDir, 'sync', 'apply'), 'sync/apply', 'sync-apply');\n }\n const hasAnchor = Object.values(manifest.objects).some(\n (objectDef) => !isCollectionManifestClass(manifest, objectDef),\n );\n if (hasAnchor && options.changesRoute?.enabled !== false) {\n claim(join(options.routesDir, '_changes'), '_changes', 'changes');\n }\n if (willGenerateDevPlaneRoute(projectRoot, options)) {\n claim(join(options.routesDir, '_dev', '[...tool]'), '_dev', 'dev-plane');\n }\n if (hasAnchor && options.eventsRoute?.enabled !== false) {\n claim(join(options.routesDir, '_events'), '_events', 'events');\n }\n if (reservesResourcesRoute(projectRoot, options)) {\n claim(join(options.routesDir, '_resources'), '_resources', 'resources');\n }\n if (options.knowledge?.api?.enabled) {\n const routeDir = knowledgeRouteDir(projectRoot, options);\n claimPath(join(routeDir, '+server.ts'), routeDir, 'knowledge', 'knowledge');\n }\n}\n\n/**\n * Generates SvelteKit API routes from the selected route manifest.\n * `semanticManifest` preserves the complete class inventory for authorization,\n * STI ancestry, cache safety, and custom-action wireability when the route\n * manifest is a deliberately selected output subset.\n */\nexport interface SvelteKitUtilityManifests {\n sync: SmartObjectManifest;\n changes: SmartObjectManifest;\n events: SmartObjectManifest;\n eventsSemantic: SmartObjectManifest;\n /** Only the contribution that owns knowledge generation may reconcile it. */\n clearKnowledgeRoute?: boolean;\n /** Exact foreign producer outputs that this route root must neither clear nor overwrite. */\n protectedRoutePaths?: ReadonlySet<string>;\n /** Active foreign route roots that cleanup must not traverse through links. */\n protectedRouteRoots?: ReadonlySet<string>;\n}\n\n/** Coordinator callbacks that run around validated generated-output mutation. */\nexport interface SvelteKitGenerationHooks {\n beforeCleanup?: () => void | Promise<void>;\n}\n\nexport async function generateSvelteKitRoutes(\n projectRoot: string,\n routeManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n semanticManifest: SmartObjectManifest = routeManifest,\n utilityManifests: SvelteKitUtilityManifests = {\n sync: routeManifest,\n changes: routeManifest,\n events: routeManifest,\n eventsSemantic: semanticManifest,\n clearKnowledgeRoute: true,\n },\n registrationManifest: SmartObjectManifest = routeManifest,\n hooks: SvelteKitGenerationHooks = {},\n): Promise<void> {\n if (!options.enabled) return;\n\n console.log('[smrt] Generating SvelteKit routes...');\n\n if (options.rejectRouteCollisions) {\n assertNoCrossObjectRouteCollisions(\n projectRoot,\n routeManifest,\n options,\n semanticManifest,\n utilityManifests.protectedRoutePaths,\n );\n }\n\n await hooks.beforeCleanup?.();\n\n clearGeneratedSvelteKitRouteFiles(\n join(projectRoot, options.routesDir),\n utilityManifests.protectedRoutePaths,\n utilityManifests.protectedRouteRoots,\n );\n if (utilityManifests.clearKnowledgeRoute !== false) {\n clearGeneratedKnowledgeRoute(projectRoot, options);\n }\n\n // Generate centralized configuration file first (if it doesn't exist)\n await generateSmrtConfigFile(projectRoot, registrationManifest, options);\n\n const generatedRoutePaths: string[] = [];\n let generatedCount = 0;\n let skippedCollections = 0;\n for (const [className, objectDef] of orderedManifestObjectEntries(\n routeManifest,\n )) {\n // The framework's own abstract base classes (SmrtObject,\n // SmrtCollection, ...) are scaffolding, not resources — never generate\n // a route directory for them, regardless of config (#2642).\n if (isFrameworkBaseClass(objectDef.className, objectDef.packageName)) {\n continue;\n }\n if (isCollectionManifestClass(semanticManifest, objectDef)) {\n const collectionRoutePaths = await generateCollectionRoutesForObject(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(...collectionRoutePaths);\n if (collectionRoutePaths.length > 0) {\n generatedCount++;\n } else {\n console.log(\n `[smrt] Skipping ${className} - no collection API routes to generate`,\n );\n skippedCollections++;\n }\n continue;\n }\n generatedRoutePaths.push(\n ...(await generateRoutesForObject(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n options,\n )),\n );\n generatedCount++;\n }\n\n if (options.knowledge?.api?.enabled) {\n generatedRoutePaths.push(generateKnowledgeRoute(projectRoot, options));\n }\n\n // Batch write contract route (#1759): {routesDir}/sync/apply/+server.ts.\n if (generateSyncApplyRoute(projectRoot, utilityManifests.sync, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, 'sync', 'apply', '+server.ts'),\n );\n }\n // Change-feed route (#1758) — cleanup rides clearGeneratedRouteFiles above.\n if (generateChangesRoute(projectRoot, utilityManifests.changes, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_changes', '+server.ts'),\n );\n }\n if (generateDevPlaneRoute(projectRoot, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_dev', '[...tool]', '+server.ts'),\n );\n }\n // Live change-signal SSE route (#1763) — cleanup rides the sweep above.\n if (\n generateEventsRoute(\n projectRoot,\n utilityManifests.events,\n options,\n computeWebManifestHash(utilityManifests.eventsSemantic),\n )\n ) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_events', '+server.ts'),\n );\n }\n\n // CLI discovery route (#2663) — cleanup rides the sweep above; skipped\n // when smrt-users isn't resolvable or a hand-written route already exists.\n if (generateResourcesRoute(projectRoot, options)) {\n generatedRoutePaths.push(\n join(projectRoot, options.routesDir, '_resources', '+server.ts'),\n );\n }\n\n // Ignore only the concrete route files generated in this pass. This keeps\n // handwritten handlers below routesDir visible to Git.\n updateGitignore(\n projectRoot,\n generatedRoutePaths,\n join(projectRoot, svelteKitRouteRoot(options.routesDir)),\n );\n\n const skippedMsg =\n skippedCollections > 0\n ? ` (skipped ${skippedCollections} collection classes)`\n : '';\n console.log(\n `[smrt] Generated routes for ${generatedCount} SMRT objects${skippedMsg}`,\n );\n}\n\n/** Remove only SMRT header-owned SvelteKit handlers below one route root. */\nexport function clearGeneratedSvelteKitRouteFiles(\n routesRoot: string,\n excludedPaths: ReadonlySet<string> = new Set(),\n protectedRouteRoots: ReadonlySet<string> = new Set(),\n visitedRoots: Set<string> = new Set(),\n): void {\n const canonicalRoot = canonicalSvelteKitPath(routesRoot);\n if (\n protectedRouteRoots.has(canonicalRoot) ||\n visitedRoots.has(canonicalRoot)\n ) {\n return;\n }\n if (!existsSync(routesRoot)) {\n return;\n }\n visitedRoots.add(canonicalRoot);\n\n for (const entry of readdirSync(routesRoot, { withFileTypes: true })) {\n const entryPath = join(routesRoot, entry.name);\n\n if (isSvelteKitRouteDirectory(entryPath, entry)) {\n clearGeneratedSvelteKitRouteFiles(\n entryPath,\n excludedPaths,\n protectedRouteRoots,\n visitedRoots,\n );\n continue;\n }\n\n if (!entry.isFile() || entry.name !== '+server.ts') {\n continue;\n }\n if (excludedPaths.has(canonicalSvelteKitPath(entryPath))) continue;\n\n const fileContent = readFileSync(entryPath, 'utf-8');\n if (fileContent.startsWith(AUTO_GENERATED_ROUTE_HEADER)) {\n unlinkSync(entryPath);\n }\n }\n}\n\nfunction isSvelteKitRouteDirectory(\n entryPath: string,\n entry: { isDirectory(): boolean; isSymbolicLink?(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink?.()) return false;\n try {\n return statSync(entryPath).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** Refresh the managed ignore block after an externally coordinated cleanup. */\nexport function reconcileSvelteKitRouteGitignore(\n projectRoot: string,\n routesDir: string,\n): void {\n updateGitignore(\n projectRoot,\n [],\n join(projectRoot, svelteKitRouteRoot(routesDir)),\n );\n}\n\nfunction knowledgeRouteDir(projectRoot: string, options: SvelteKitOptions) {\n const basePath = String(\n options.knowledge?.api?.basePath || '/__smrt/knowledge',\n );\n const routeRoot = svelteKitRouteRoot(options.routesDir);\n const segments = basePath\n .split('/')\n .map((segment) => segment.trim())\n .filter(Boolean);\n\n return join(projectRoot, routeRoot, ...segments);\n}\n\n/** Exact generated knowledge handler path for coordinator-owned cleanup. */\nexport function knowledgeRoutePath(\n projectRoot: string,\n options: SvelteKitOptions,\n): string {\n return join(knowledgeRouteDir(projectRoot, options), '+server.ts');\n}\n\nfunction svelteKitRouteRoot(routesDir: string): string {\n const normalized = routesDir.replaceAll('\\\\', '/').replace(/\\/+$/, '');\n const marker = '/routes';\n const markerIndex = normalized.indexOf(marker);\n\n if (normalized === 'src/routes' || normalized.endsWith('/routes')) {\n return normalized;\n }\n if (markerIndex !== -1) {\n return normalized.slice(0, markerIndex + marker.length);\n }\n return 'src/routes';\n}\n\nfunction clearGeneratedKnowledgeRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): void {\n const routePath = knowledgeRoutePath(projectRoot, options);\n if (!existsSync(routePath)) return;\n\n const content = readFileSync(routePath, 'utf-8');\n if (content.startsWith(AUTO_GENERATED_ROUTE_HEADER)) {\n unlinkSync(routePath);\n }\n}\n\nfunction generateKnowledgeRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): string {\n const routeDir = knowledgeRouteDir(projectRoot, options);\n const route = generateKnowledgeRouteTemplate(\n options.knowledge ?? {},\n readKnowledgeRouteArtifact(projectRoot),\n );\n return writeRoute(routeDir, '+server.ts', route);\n}\n\nfunction readKnowledgeRouteArtifact(\n projectRoot: string,\n): Record<string, unknown> | null {\n for (const relativePath of [\n '.smrt/smrt-knowledge.json',\n 'dist/smrt-knowledge.json',\n ]) {\n const fullPath = join(projectRoot, relativePath);\n if (!existsSync(fullPath)) continue;\n try {\n return JSON.parse(readFileSync(fullPath, 'utf-8'));\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\n/**\n * Generates SMRT object registration file\n * This file imports all SMRT objects to trigger their @smrt() decorators\n */\nasync function generateRegistrationFile(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<void> {\n const configPath = options.configPath || 'src/lib/server';\n const configDir = join(projectRoot, configPath);\n const registrationFilePath = join(configDir, 'smrt-register.ts');\n\n // Group objects by package for efficient imports\n const localObjects: Array<[string, (typeof manifest.objects)[string]]> = [];\n const packageObjects = new Map<\n string,\n {\n objects: Array<{\n simpleName: string;\n bindingName: string;\n }>;\n hasCollectionImport: boolean;\n }\n >();\n const registrationBindings = buildRegistrationBindings(manifest);\n\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n if (isLocalObject(projectRoot, objectDef)) {\n // Local object (source in project, not node_modules) - use $lib path\n localObjects.push([className, objectDef]);\n } else if (objectDef.packageName) {\n // External packages may publish canonical object exports from a subpath\n // under an aliased export name. Registry identity stays keyed by the\n // manifest's qualified class name; only the emitted module binding uses\n // that canonical import contract.\n const externalImportPath = objectDef.importPath || objectDef.packageName;\n const packageEntry = packageObjects.get(externalImportPath) || {\n objects: [],\n hasCollectionImport: false,\n };\n\n if (isCollectionManifestClass(manifest, objectDef)) {\n packageEntry.hasCollectionImport = true;\n } else {\n packageEntry.objects.push({\n simpleName: objectDef.exportName || extractSimpleClassName(className),\n bindingName:\n registrationBindings.get(className) ||\n extractSimpleClassName(className),\n });\n }\n\n packageObjects.set(externalImportPath, packageEntry);\n } else {\n // No package name and not local - treat as local fallback\n localObjects.push([className, objectDef]);\n }\n }\n\n // Generate imports for local objects\n // Issue #870: Extract simple class names from qualified names\n const localNamedImports = new Map<\n string,\n Array<{ simpleName: string; bindingName: string }>\n >();\n const localSideEffectImports = new Set<string>();\n\n for (const [className, objectDef] of localObjects) {\n const simpleClassName = extractSimpleClassName(className);\n\n // Calculate direct relative path from the configDir where smrt-register.ts lives\n // to the actual source file of the object.\n let importPath = '';\n if (objectDef.filePath) {\n const relativeToConfig = relative(configDir, objectDef.filePath);\n const normalized = relativeToConfig\n .replace(/\\\\/g, '/')\n .replace(/\\.(ts|js|tsx|jsx)$/, '');\n importPath = normalized.startsWith('.') ? normalized : `./${normalized}`;\n } else {\n // Fallback for missing file paths\n importPath = getSvelteKitImportPath(\n projectRoot,\n undefined,\n options.objectsDir,\n simpleClassName,\n );\n }\n\n if (isCollectionManifestClass(manifest, objectDef)) {\n localSideEffectImports.add(importPath);\n continue;\n }\n\n const existing = localNamedImports.get(importPath) ?? [];\n existing.push({\n simpleName: simpleClassName,\n bindingName: registrationBindings.get(className) || simpleClassName,\n });\n localNamedImports.set(importPath, existing);\n }\n\n const localImports = [\n ...Array.from(localNamedImports.entries())\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([importPath, importedObjects]) => {\n const sortedNames = importedObjects\n .sort((a, b) => a.bindingName.localeCompare(b.bindingName))\n .map(formatRegistrationImport);\n return `import { ${sortedNames.join(', ')} } from '${importPath}';`;\n }),\n ...Array.from(localSideEffectImports.values())\n .sort((a, b) => a.localeCompare(b))\n .map((importPath) => `import '${importPath}';`),\n ].join('\\n');\n\n // Generate imports for external packages\n // Issue #870: Extract simple class names from qualified names\n const packageImports = Array.from(packageObjects.entries())\n .sort(([left], [right]) => left.localeCompare(right))\n .flatMap(([packageName, packageEntry]) => {\n const imports: string[] = [];\n\n if (packageEntry.hasCollectionImport) {\n imports.push(`import '${packageName}';`);\n }\n\n if (packageEntry.objects.length > 0) {\n const simpleNames = packageEntry.objects\n .sort((a, b) => a.bindingName.localeCompare(b.bindingName))\n .map(formatRegistrationImport);\n imports.push(\n `import { ${simpleNames.join(', ')} } from '${packageName}';`,\n );\n }\n\n return imports;\n })\n .join('\\n');\n\n const imports = [packageImports, localImports].filter(Boolean).join('\\n');\n const externalRuntimeDependencies = (manifest.smrtDependencies || []).filter(\n (dependency) => dependency !== '@happyvertical/smrt-core',\n );\n const consumerRegistrationPaths =\n options.consumerRegistrationPaths ??\n (externalRuntimeDependencies.length > 0\n ? [join(projectRoot, '.smrt', 'register.js')]\n : []);\n let consumerRegistrationImport = '';\n if (consumerRegistrationPaths.length > 0) {\n consumerRegistrationImport = [...new Set(consumerRegistrationPaths)]\n .sort()\n .map((registerPath) => {\n const consumerRegistrationPath = relative(\n configDir,\n registerPath,\n ).replace(/\\\\/g, '/');\n return `import '${consumerRegistrationPath.startsWith('.') ? consumerRegistrationPath : `./${consumerRegistrationPath}`}';`;\n })\n .join('\\n');\n }\n /**\n * Strip machine specifics from an object definition before it is embedded in\n * generated source.\n *\n * `smrt-register.ts` is a tracked file in consumer repositories, and the\n * scanner records `filePath` as an absolute path. Embedding it verbatim wrote\n * the generating machine's home directory into the repository, so the file\n * could never be committed without breaking every other checkout and CI, and\n * every build left a dirty working tree (#2341). The field is only produced\n * at scan time — nothing reads it back through `_manifest` at runtime — so a\n * project-relative path keeps the shape without the machine.\n */\n function portableObjectManifest(\n root: string,\n objectDef: SmartObjectDefinition,\n ): SmartObjectDefinition {\n const { filePath } = objectDef;\n if (typeof filePath !== 'string' || !isAbsolute(filePath)) {\n return objectDef;\n }\n return {\n ...objectDef,\n filePath: relative(root, filePath).split(sep).join('/'),\n };\n }\n\n const registrationManifests = Object.fromEntries(\n Object.entries(manifest.objects).flatMap(([className, objectDef]) => {\n if (isCollectionManifestClass(manifest, objectDef)) return [];\n const localObject = isLocalObject(projectRoot, objectDef);\n const packageName = getRegistrationPackageName(\n manifest,\n objectDef,\n localObject,\n );\n if (!packageName) return [];\n return [\n [\n className,\n {\n ...manifest,\n packageName,\n objects: {\n [className]: portableObjectManifest(projectRoot, objectDef),\n },\n },\n ],\n ];\n }),\n );\n const registrationManifestLiteral = JSON.stringify(\n JSON.stringify(registrationManifests),\n );\n const registrations = Object.entries(manifest.objects)\n .map(([className, objectDef]) => {\n if (isCollectionManifestClass(manifest, objectDef)) {\n // Importing the collection class is enough to trigger its decorator.\n // Explicit package-qualified re-registration only applies to object\n // classes, because ObjectRegistry.register() is object-only.\n return null;\n }\n\n const simpleClassName = extractSimpleClassName(className);\n const bindingName =\n registrationBindings.get(className) || simpleClassName;\n const localObject = isLocalObject(projectRoot, objectDef);\n const packageName = getRegistrationPackageName(\n manifest,\n objectDef,\n localObject,\n );\n\n if (!packageName) {\n return null;\n }\n\n const packageNameLiteral = toSingleQuotedStringLiteral(packageName);\n const manifestKeyLiteral = toSingleQuotedStringLiteral(className);\n const singleLineRegistration = `ObjectRegistry.register(${bindingName}, { name: '${simpleClassName}', packageName: ${packageNameLiteral}, _manifest: smrtRegistrationManifests[${manifestKeyLiteral}], _manifestKey: ${manifestKeyLiteral} });`;\n\n if (singleLineRegistration.length <= BIOME_LINE_WIDTH) {\n return singleLineRegistration;\n }\n\n return [\n `ObjectRegistry.register(${bindingName}, {`,\n ` name: '${simpleClassName}',`,\n ` packageName: ${packageNameLiteral},`,\n ` _manifest: smrtRegistrationManifests[${manifestKeyLiteral}],`,\n ` _manifestKey: ${manifestKeyLiteral},`,\n `});`,\n ].join('\\n');\n })\n .filter((registration): registration is string => registration !== null)\n .join('\\n');\n\n const registrationContent = `/**\n * Auto-generated SMRT object registration\n * DO NOT EDIT - changes will be overwritten\n *\n * Importing these modules triggers their @smrt() decorators, which perform\n * the initial registration. The explicit re-registration below is intentional:\n * it upgrades bundled runtimes to deterministic qualified registrations.\n */\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n${consumerRegistrationImport}\n${imports}\n\nconst smrtRegistrationManifests = JSON.parse(${registrationManifestLiteral});\n\n// Re-register imported objects with explicit package names for bundled runtimes\n${registrations}\n`;\n\n // Create directory if it doesn't exist\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(registrationFilePath, registrationContent, 'utf-8');\n console.log(`[smrt] Generated registration file: ${registrationFilePath}`);\n}\n\nfunction buildRegistrationBindings(\n manifest: SmartObjectManifest,\n): Map<string, string> {\n const keysBySimpleName = new Map<string, string[]>();\n const reservedBindings = new Set<string>();\n for (const [manifestKey, objectDef] of Object.entries(manifest.objects)) {\n if (isCollectionManifestClass(manifest, objectDef)) continue;\n const simpleName = extractSimpleClassName(manifestKey);\n reservedBindings.add(simpleName);\n const keys = keysBySimpleName.get(simpleName) ?? [];\n keys.push(manifestKey);\n keysBySimpleName.set(simpleName, keys);\n }\n\n const bindings = new Map<string, string>();\n const generatedBindings = new Set<string>();\n for (const [simpleName, keys] of keysBySimpleName) {\n const sortedKeys = keys.sort((a, b) => a.localeCompare(b));\n for (const [index, manifestKey] of sortedKeys.entries()) {\n let bindingName = simpleName;\n if (sortedKeys.length > 1) {\n let suffix = index + 1;\n do {\n bindingName = `__smrt_${simpleName}_${suffix}`;\n suffix += 1;\n } while (\n reservedBindings.has(bindingName) ||\n generatedBindings.has(bindingName)\n );\n generatedBindings.add(bindingName);\n }\n bindings.set(manifestKey, bindingName);\n }\n }\n return bindings;\n}\n\nfunction formatRegistrationImport(importedObject: {\n simpleName: string;\n bindingName: string;\n}): string {\n return importedObject.simpleName === importedObject.bindingName\n ? importedObject.simpleName\n : `${importedObject.simpleName} as ${importedObject.bindingName}`;\n}\n\n/**\n * Generates centralized SMRT configuration file\n * Only creates if file doesn't exist (preserves user customizations)\n */\nasync function generateSmrtConfigFile(\n projectRoot: string,\n manifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<void> {\n const configPath = options.configPath || 'src/lib/server';\n const configFileName = options.configFileName || 'smrt.ts';\n const configDir = join(projectRoot, configPath);\n const configFilePath = join(configDir, configFileName);\n\n // Always generate registration file (it gets overwritten)\n await generateRegistrationFile(projectRoot, manifest, options);\n\n // Don't overwrite existing config file\n if (existsSync(configFilePath)) {\n console.log('[smrt] Config file already exists, skipping generation');\n return;\n }\n\n const configContent = `/**\n * Centralized SMRT configuration with per-object overrides\n * Generated by @smrt/core vite plugin\n *\n * Most objects will use the default configuration.\n * Add entries to \\`objectOverrides\\` for objects that need different backends.\n */\n\n// Import SMRT objects to register them via @smrt() decorators\nimport './smrt-register.js';\n\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\nimport type { SmrtClassOptions } from '@happyvertical/smrt-core';\n\n// \\`__smrtGetRequestScopedDatabase\\` is declared canonically by\n// @happyvertical/smrt-core; importing its types above is enough to see it.\n// Do not redeclare it here — duplicate \\`declare global\\` entries must be\n// type-identical, and a second declaration broke consumer checks (#2342).\n\n/**\n * Per-object configuration overrides\n * Define specific backends for objects that differ from project defaults\n *\n * @example\n * const objectOverrides: Record<string, Partial<SmrtClassOptions>> = {\n * // Analytics uses a separate PostgreSQL database\n * Analytics: {\n * db: {\n * url: process.env.ANALYTICS_DATABASE_URL!,\n * type: 'postgres'\n * }\n * },\n *\n * // AuditLog uses dedicated database with no AI\n * AuditLog: {\n * db: {\n * url: process.env.AUDIT_DATABASE_URL!,\n * type: 'postgres'\n * },\n * ai: undefined\n * },\n *\n * // Cache uses REST adapter (e.g., Redis)\n * Cache: {\n * persistence: {\n * type: 'rest',\n * baseUrl: process.env.REDIS_URL!\n * }\n * }\n * };\n */\nconst objectOverrides: Record<string, Partial<SmrtClassOptions>> = {\n // Add your per-object configuration overrides here\n};\n\n/**\n * Default configuration for most SMRT objects\n * Customize this to change project-wide defaults\n */\nfunction getDefaultConfig(): SmrtClassOptions {\n return {\n db: {\n url: process.env.DATABASE_URL || ':memory:',\n type: (process.env.DATABASE_TYPE as 'sqlite' | 'postgres') || 'sqlite'\n },\n ai: process.env.OPENAI_API_KEY ? {\n type: 'openai',\n apiKey: process.env.OPENAI_API_KEY\n } : process.env.ANTHROPIC_API_KEY ? {\n type: 'anthropic',\n apiKey: process.env.ANTHROPIC_API_KEY\n } : undefined\n };\n}\n\nfunction getRequestScopedDatabase(): SmrtClassOptions['db'] | undefined {\n const getter = globalThis.__smrtGetRequestScopedDatabase;\n return typeof getter === 'function' ? getter() : undefined;\n}\n\n/**\n * Get configuration for a specific SMRT object\n * Merges project defaults with per-object overrides if defined\n */\nexport function getSmrtConfig(className: string): SmrtClassOptions {\n const defaults = getDefaultConfig();\n const override = objectOverrides[className];\n\n if (override) {\n // Deep merge: override specific properties while keeping defaults\n return {\n ...defaults,\n ...override,\n // Ensure nested objects are merged properly\n db: override.db\n ? { ...(defaults.db as any), ...(override.db as any) }\n : defaults.db,\n ai: override.ai !== undefined ? override.ai : defaults.ai\n };\n }\n\n return defaults;\n}\n\n/**\n * Helper to get a collection with centralized configuration\n * Automatically applies project defaults or object-specific overrides\n */\nexport async function getCollection<\n T extends import('@happyvertical/smrt-core').SmrtObject,\n>(className: string, overrides: Partial<SmrtClassOptions> = {}) {\n const config = getSmrtConfig(className);\n const objectOverride = objectOverrides[className];\n const requestScopedDb =\n !overrides.db && !objectOverride?.db\n ? getRequestScopedDatabase()\n : undefined;\n\n return await ObjectRegistry.getCollection<T>(\n className,\n {\n ...config,\n ...overrides,\n db: overrides.db\n ? { ...(config.db as any), ...(overrides.db as any) }\n : requestScopedDb ?? config.db,\n ai: overrides.ai !== undefined ? overrides.ai : config.ai\n }\n );\n}\n`;\n\n // Create directory if it doesn't exist\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n writeFileSync(configFilePath, configContent, 'utf-8');\n console.log(`[smrt] Generated configuration file: ${configFilePath}`);\n}\n\n/**\n * Generates route files for a single SMRT object\n */\nasync function generateRoutesForObject(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<string[]> {\n const collectionName = objectDef.collection;\n const routeDir = join(projectRoot, options.routesDir, collectionName);\n const generatedRoutePaths: string[] = [];\n\n // Check if API is enabled for this object\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) {\n console.log(`[smrt] Skipping ${className} - API disabled`);\n return generatedRoutePaths;\n }\n\n // Determine which CRUD actions to include via the shared resolver.\n const includedActions = resolveStandardCrudActions(apiConfig);\n\n // Generate collection route (list, create)\n if (includedActions.includes('list') || includedActions.includes('create')) {\n const collectionRoute = generateCollectionRouteTemplate(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n includedActions,\n options,\n routeDir,\n );\n generatedRoutePaths.push(\n writeRoute(routeDir, '+server.ts', collectionRoute),\n );\n }\n\n // Generate item route (get, update, delete)\n if (\n includedActions.includes('get') ||\n includedActions.includes('update') ||\n includedActions.includes('delete')\n ) {\n const itemRoute = generateItemRouteTemplate(\n projectRoot,\n className,\n objectDef,\n semanticManifest,\n includedActions,\n options,\n join(routeDir, '[id]'),\n );\n generatedRoutePaths.push(\n writeRoute(join(routeDir, '[id]'), '+server.ts', itemRoute),\n );\n }\n\n // Generate custom action routes. Eligibility -- CRUD reservation, framework\n // lifecycle methods, include/exclude, `@method()` overrides, wire-ability,\n // and the receiver check -- comes from the ONE shared resolver every API\n // consumer reads, so a route is written exactly when `resolveApiActionSet`\n // and the knowledge artifact say one exists (#2686).\n const { exposed: customActions, rejected } = resolveApiCustomActions(\n objectDef,\n semanticManifest,\n false,\n );\n warnUnhostedActions(className, rejected);\n\n const actionSpecs: Array<{\n routeDir: string;\n spec: GeneratedActionRouteSpec;\n }> = [];\n\n for (const [actionName, actionDef] of customActions) {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n apiConfig,\n { kebabRoutes: options.kebabRoutes },\n );\n warnDeclaredScopeMismatch(\n className,\n actionName,\n actionDef,\n apiConfig,\n routeConfig.scope,\n );\n\n const actionBaseDir =\n routeConfig.scope === 'collection' ? routeDir : join(routeDir, '[id]');\n actionSpecs.push({\n routeDir: join(actionBaseDir, ...routeConfig.pathSegments),\n spec: {\n lookupClassName: className,\n lookupObjectDef: objectDef,\n hostClassName: className,\n actionName,\n actionDef,\n routeConfig,\n hostType: 'item',\n },\n });\n }\n\n for (const [actionRouteDir, routeSpecs] of groupCustomActionRoutes(\n actionSpecs,\n )) {\n const actionRoute = generateActionRouteTemplate(\n projectRoot,\n actionRouteDir,\n routeSpecs,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(\n writeRoute(actionRouteDir, '+server.ts', actionRoute),\n );\n }\n\n return generatedRoutePaths;\n}\n\nasync function generateCollectionRoutesForObject(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): Promise<string[]> {\n const generatedRoutePaths: string[] = [];\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) {\n console.log(`[smrt] Skipping ${className} - API disabled`);\n return generatedRoutePaths;\n }\n\n const routeDir = join(projectRoot, options.routesDir, objectDef.collection);\n const lookupClassName = findItemClassRegistryKey(\n className,\n objectDef,\n semanticManifest,\n );\n const lookupObjectDef = findObjectDefByRegistryKey(\n semanticManifest,\n lookupClassName,\n );\n\n const { exposed: customActions, rejected } = resolveApiCustomActions(\n objectDef,\n semanticManifest,\n true,\n );\n warnUnhostedActions(className, rejected);\n\n if (customActions.length === 0) {\n return generatedRoutePaths;\n }\n const actionSpecs: Array<{\n routeDir: string;\n spec: GeneratedActionRouteSpec;\n }> = [];\n\n for (const [actionName, actionDef] of customActions) {\n const routeConfig = resolveApiActionRouteConfig(\n actionName,\n actionDef,\n apiConfig,\n { kebabRoutes: options.kebabRoutes },\n 'collection',\n );\n warnDeclaredScopeMismatch(\n className,\n actionName,\n actionDef,\n apiConfig,\n routeConfig.scope,\n );\n\n actionSpecs.push({\n routeDir: join(routeDir, ...routeConfig.pathSegments),\n spec: {\n lookupClassName,\n lookupObjectDef,\n hostClassName: className,\n actionName,\n actionDef,\n routeConfig,\n hostType: 'collection',\n },\n });\n }\n\n for (const [actionRouteDir, routeSpecs] of groupCustomActionRoutes(\n actionSpecs,\n )) {\n const actionRoute = generateActionRouteTemplate(\n projectRoot,\n actionRouteDir,\n routeSpecs,\n objectDef,\n semanticManifest,\n options,\n );\n generatedRoutePaths.push(\n writeRoute(actionRouteDir, '+server.ts', actionRoute),\n );\n }\n\n return generatedRoutePaths;\n}\n\n/**\n * Resolve the list of standard CRUD actions exposed by the API for a given\n * apiConfig. Single source of truth for both the route generator and the\n * cli↔api coherence lint.\n */\nfunction resolveStandardCrudActions(apiConfig: unknown): string[] {\n if (apiConfig === false) return [];\n if (apiConfig === true || apiConfig === undefined) {\n return [...CRUD_OPERATIONS];\n }\n if (typeof apiConfig !== 'object' || apiConfig === null) {\n return [...CRUD_OPERATIONS];\n }\n\n const config = apiConfig as { include?: string[]; exclude?: string[] };\n let crud: string[] = Array.isArray(config.include)\n ? config.include.filter((a) => isCrudOperation(a))\n : [...CRUD_OPERATIONS];\n if (Array.isArray(config.exclude)) {\n const exclude = config.exclude;\n crud = crud.filter((a) => !exclude.includes(a));\n }\n return crud;\n}\n\n/**\n * Partition an object's custom (non-CRUD) methods into the ones the API\n * exposes and the ones it withholds, with a reason for each rejection.\n *\n * The ONE place route generation, `resolveApiActionSet`, and the knowledge\n * artifact's API projection agree, by all three reading\n * {@link resolveApiMethodExposure}. Before #2686 each re-derived a subset and\n * could disagree — most damagingly, a gate applied only to the coherence\n * resolver would report a method unreachable while the emitter next door still\n * wrote its route file.\n */\nexport function resolveApiCustomActions(\n objectDef: SmartObjectDefinition,\n manifest: SmartObjectManifest | undefined,\n objectIsCollectionClass: boolean,\n wireability: WireabilityOptions = {},\n): {\n exposed: Array<[string, MethodDefinition]>;\n rejected: Array<[string, ApiMethodExposure]>;\n} {\n const apiConfig = objectDef.decoratorConfig?.api;\n const isModelClassName =\n wireability.isModelClassName ?? createManifestClassNamePredicate(manifest);\n const exposed: Array<[string, MethodDefinition]> = [];\n const rejected: Array<[string, ApiMethodExposure]> = [];\n\n for (const [name, method] of Object.entries(objectDef.methods || {})) {\n const decision = resolveApiMethodExposure({\n actionName: name,\n method,\n apiConfig,\n isCollectionClass: objectIsCollectionClass,\n ...(isModelClassName ? { isModelClassName } : {}),\n });\n if (decision.exposed) {\n exposed.push([name, method]);\n continue;\n }\n // CRUD reservation and non-public methods are not \"rejections\" worth\n // reporting: neither was ever a candidate custom action, and listing every\n // private helper would bury the rejections a developer can act on.\n if (decision.code === 'crud-reserved' || decision.code === 'not-public') {\n continue;\n }\n rejected.push([name, decision]);\n }\n\n return { exposed, rejected };\n}\n\n/**\n * Warn about the one rejection class that would be a structural failure rather\n * than a configuration choice: an action whose declared scope has no receiver\n * to bind. Both emitters carried this warning before #2686 moved the check into\n * the shared resolver, and the message text is preserved.\n *\n * It cannot currently fire — `resolveCustomActionMetadata` collapses a\n * contradicting scope back to the receiver-derived one, as it did before this\n * change; see `resolveActionReceiver` in `generators/custom-action.ts`. The\n * warning a developer actually sees for a contradicting declaration is\n * `warnDeclaredScopeMismatch` below.\n *\n * Every other rejection is silent here and reported with its reason through\n * the knowledge artifact instead, so a normal build is not buried in output\n * for the 2% of methods the heuristic legitimately withholds.\n */\nfunction warnUnhostedActions(\n className: string,\n rejected: Array<[string, ApiMethodExposure]>,\n): void {\n for (const [actionName, decision] of rejected) {\n if (decision.code !== 'no-receiver') continue;\n console.warn(\n `[smrt] Skipping ${className}.${actionName} - ${decision.reason}`,\n );\n }\n}\n\n/**\n * Report a declared `scope` that contradicts the method's actual receiver.\n *\n * The declaration is honored only where it AGREES; nothing in config can move\n * an instance method onto the class. Warning is the whole remedy — the route\n * is still emitted at the receiver-derived URL, so an author who expected the\n * other one learns why it is missing instead of silently getting nothing at\n * either address (#2686).\n */\nfunction warnDeclaredScopeMismatch(\n className: string,\n actionName: string,\n actionDef: MethodDefinition,\n apiConfig: unknown,\n effectiveScope: 'item' | 'collection',\n): void {\n const declared = resolveDeclaredScopeMismatch({\n actionName,\n method: actionDef,\n apiConfig,\n effectiveScope,\n });\n if (!declared) return;\n console.warn(\n `[smrt] ${className}.${actionName} declares scope '${declared}' but its receiver is ` +\n `${effectiveScope}-scoped, so the declared scope is ignored. A scope describes where a ` +\n `method already lives; it cannot move it. Make ${actionName} static to reach it on the ` +\n 'collection, or drop the scope option.',\n );\n}\n\n/**\n * Compute the set of action names (standard CRUD + custom methods) that the\n * API exposes for a given object definition. This is the same resolution used\n * to drive route generation, exposed so coherence checks (e.g. CLI vs API)\n * can ask \"what does the API expose?\" without re-implementing the logic.\n *\n * Pass a class inventory: without one the wire-ability heuristic cannot tell a\n * model class from an options interface and therefore accepts both, so the\n * caller silently disagrees with the emitters on the LARGEST group of withheld\n * methods (see `WireabilityOptions.isModelClassName`). Supply either\n * `manifest`, or `wireability.isModelClassName` when the caller's inventory is\n * the live registry rather than a manifest — `@happyvertical/smrt-users`' CLI\n * resource listing is the second kind. Both stay optional only because this is\n * public API.\n */\nexport function resolveApiActionSet(\n objectDef: SmartObjectDefinition,\n manifest?: SmartObjectManifest,\n wireability: WireabilityOptions = {},\n): Set<string> {\n const apiConfig = objectDef.decoratorConfig?.api;\n if (apiConfig === false) return new Set();\n\n const objectIsCollectionClass = manifest\n ? isCollectionManifestClass(manifest, objectDef)\n : isCollectionClass(objectDef);\n const actions = objectIsCollectionClass\n ? new Set<string>()\n : new Set<string>(resolveStandardCrudActions(apiConfig));\n\n for (const [name] of resolveApiCustomActions(\n objectDef,\n manifest,\n objectIsCollectionClass,\n wireability,\n ).exposed) {\n actions.add(name);\n }\n\n return actions;\n}\n\n/**\n * Detail for a single cli-vs-api coherence violation.\n */\nexport interface CliApiCoherenceViolation {\n className: string;\n unreachable: string[];\n /**\n * Names in `cli.skipApiCheck`'s array form that aren't a CRUD verb or a\n * scanned public method on this class -- a typo, most likely. Checked\n * against that real command inventory rather than the (possibly\n * `cli.include`-typo'd) effective CLI command set on purpose: an explicit\n * `cli.include` trusts its own entries verbatim (see `resolveCliActionSet`'s\n * doc comment -- catching an include typo is `unreachable`'s job), so an\n * identical typo duplicated into `skipApiCheck` must not \"recognize\"\n * itself via that untrusted echo (PR #2860 review). Always a build error\n * (smrt#2857): an unrecognized name grants no exemption at all, which\n * would silently reproduce the exact class-wide-waiver drift this check\n * exists to prevent. Present only when non-empty.\n */\n invalidSkipApiCheck?: string[];\n}\n\n/**\n * Resolve the effective CLI command set for an object, for the cli↔api\n * coherence lint. Two distinct resolutions, chosen by whether `cli.include`\n * is spelled out:\n *\n * **Explicit `cli.include`** (preserves the lint's exact pre-#2638\n * algorithm): the literal `include − exclude`, verbatim, whether or not an\n * entry resolves to a real CRUD verb or a scanned public method. This is\n * deliberate, not an oversight -- an `include` entry that names a typo, a\n * getter (never in the manifest's `methods` map), or a private/protected\n * method (the scanner drops these rather than recording `isPublic: false`,\n * so nothing else catches it) must still surface as \"unreachable\" so the\n * build fails loudly on the config mistake, the same way it always has.\n * Resolving it instead through `resolveCustomActionNames` -- which only\n * iterates real scanned methods -- would silently drop such an entry with no\n * error at all (final review, #2638).\n *\n * **Bare `cli: true`/`cli: {}`** (#2638, the new case this lint now\n * inspects): every public custom method minus exclude, exactly the \"every\n * public method minus exclude\" resolution this function shares with\n * `packages/core/src/generators/custom-action.ts`'s `resolveCustomActionNames`\n * -- lifecycle methods excluded, same as everywhere else. (Pre-#2664, core's\n * now-retired `CLIGenerator.listCommands()` applied the same resolution via\n * that helper too.)\n * CRUD verbs are NOT checked in this branch: a class that closes its API\n * entirely (`api: false`) while keeping a default-open, CLI/MCP-only admin\n * surface (`cli: true`/omitted) is a common, intentional combination (see\n * `cli.skipApiCheck`'s own \"in-process, no HTTP\" doc comment); blanket-\n * checking CRUD reachability for every such class would flag that existing,\n * legitimate pattern across the whole codebase, not just the #2638 defect\n * (confirmed by running this against the full monorepo build during\n * development — it did exactly that).\n */\nfunction resolveCliActionSet(objectDef: SmartObjectDefinition): Set<string> {\n const cliConfig = objectDef.decoratorConfig?.cli;\n if (cliConfig === false) return new Set();\n\n const included: string[] | undefined =\n typeof cliConfig === 'object' && cliConfig !== null\n ? cliConfig.include\n : undefined;\n const excluded: string[] =\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n Array.isArray(cliConfig.exclude)\n ? cliConfig.exclude\n : [];\n\n if (included) {\n return new Set(included.filter((cmd) => !excluded.includes(cmd)));\n }\n\n return resolveCustomActionNames(\n Object.entries(objectDef.methods || {}),\n { include: undefined, exclude: excluded },\n CRUD_OPERATIONS,\n );\n}\n\n/**\n * Inspect a manifest and return classes whose effective CLI command set —\n * `cli.include`/`cli.exclude` when spelled out, or (#2638) the same \"every\n * public method minus exclude\" default `cli: true`/`cli: {}` resolves to —\n * references a command not exposed via the API. `cli: { skipApiCheck: true }`\n * skips the whole class; `cli: { skipApiCheck: [...] }` (smrt#2857) skips\n * only the named commands, leaving every other command in the class's\n * effective set checked. So does a class with `cli: false` (no CLI surface\n * at all).\n *\n * A name in the array form that isn't a CRUD verb or a scanned public\n * method on the class is reported back via `invalidSkipApiCheck` on the\n * violation entry -- see `validateCliIncludeAgainstApi`, which always\n * throws for it regardless of that gate's narrower `cli.include` filter.\n *\n * Throws nothing else; returns the violation list so callers can choose to\n * throw or warn.\n */\nexport function findCliApiCoherenceViolations(\n manifest: SmartObjectManifest,\n): CliApiCoherenceViolation[] {\n const violations: CliApiCoherenceViolation[] = [];\n\n for (const [className, objectDef] of Object.entries(manifest.objects)) {\n const cliConfig = objectDef.decoratorConfig?.cli;\n if (cliConfig === false) continue;\n\n const skipApiCheck: boolean | string[] | undefined =\n typeof cliConfig === 'object' && cliConfig !== null\n ? cliConfig.skipApiCheck\n : undefined;\n\n if (skipApiCheck === true) continue;\n\n const effectiveCliCommands = resolveCliActionSet(objectDef);\n\n let invalidSkipApiCheck: string[] = [];\n let skipNames: Set<string> = new Set();\n if (Array.isArray(skipApiCheck) && skipApiCheck.length > 0) {\n // The *typo/stale-entry* check validates against the class's real\n // command inventory -- CRUD verbs plus scanned PUBLIC methods --\n // deliberately NOT against `effectiveCliCommands` for an explicit\n // `cli.include` (PR #2860 review, GitHub Copilot). `resolveCliActionSet`\n // trusts an explicit `cli.include` verbatim, typos included (see its\n // own doc comment: catching that kind of typo is `unreachable`'s job,\n // not this one's) -- so if `knownNames` were `effectiveCliCommands`\n // there, a name mistyped identically in BOTH `cli.include` and\n // `skipApiCheck` (e.g. `include: ['reconclieGame']`,\n // `skipApiCheck: ['reconclieGame']`) would be \"recognized\" only\n // because it's an unverified echo of itself, get silently exempted\n // via `skipNames` below, and never surface as `unreachable` OR\n // `invalidSkipApiCheck` -- defeating the very guarantee this array\n // form exists to provide.\n //\n // A non-public method is excluded from `knownNames` too (recall\n // finding, smrt#2857 review): it is not part of the real CLI surface,\n // so naming one is still a genuine mistake, not a name this lint's\n // narrower `effectiveCliCommands` resolution merely declines to check.\n const knownNames = new Set([\n ...CRUD_OPERATIONS,\n ...Object.entries(objectDef.methods || {})\n .filter(([, method]) => method.isPublic)\n .map(([name]) => name),\n ]);\n\n // Being a real command isn't enough on its own (PR #2860 review,\n // second pass): a name can be a genuine public method yet no longer\n // part of THIS class's effective CLI command set -- e.g. `audit` was\n // dropped from `cli.include` (or moved to `cli.exclude`) after the\n // `skipApiCheck: ['audit']` waiver was written, and nobody removed\n // the now-stale entry. Require membership in `effectiveCliCommands`\n // too, so that case is still an error -- restoring the exact\n // detection the first Copilot-driven fix (5a8f09929) accidentally\n // dropped by switching validity off `effectiveCliCommands` entirely.\n // The carve-out: the bare `cli: true`/`cli: {}` resolution\n // deliberately excludes CRUD verbs AND framework-lifecycle method\n // overrides from `effectiveCliCommands` (see `resolveCliActionSet`'s\n // own doc comment, and `resolveCustomActionNames`'s\n // `isFrameworkLifecycleMethod` skip) -- that omission is this lint's\n // own narrower check declining to look at them there (recall\n // finding, third pass), not a sign that such a name is stale, so\n // neither is ever \"stale\" on that branch.\n const hasExplicitInclude =\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n Array.isArray(cliConfig.include);\n const isInEffectiveSurface = (name: string) =>\n effectiveCliCommands.has(name) ||\n (!hasExplicitInclude &&\n ((CRUD_OPERATIONS as readonly string[]).includes(name) ||\n isFrameworkLifecycleMethod(name)));\n\n invalidSkipApiCheck = skipApiCheck\n .filter((name) => !knownNames.has(name) || !isInEffectiveSurface(name))\n .sort();\n skipNames = new Set(\n skipApiCheck.filter((name) => effectiveCliCommands.has(name)),\n );\n }\n\n if (effectiveCliCommands.size === 0) {\n if (invalidSkipApiCheck.length > 0) {\n violations.push({ className, unreachable: [], invalidSkipApiCheck });\n }\n continue;\n }\n\n const apiActionSet = resolveApiActionSet(objectDef, manifest);\n const unreachable = [...effectiveCliCommands]\n .filter((action) => !apiActionSet.has(action) && !skipNames.has(action))\n .sort();\n\n if (unreachable.length > 0 || invalidSkipApiCheck.length > 0) {\n violations.push({\n className,\n unreachable,\n ...(invalidSkipApiCheck.length > 0 ? { invalidSkipApiCheck } : {}),\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Throw if any class in the manifest has an EXPLICIT `cli.include` command\n * that isn't reachable via the API. Default build-time gate; opt-out\n * per-class via `cli: { skipApiCheck: true }` (or globally via the vite\n * plugin option `validateCliApiCoherence: false`).\n *\n * This is deliberately narrower than `findCliApiCoherenceViolations` above.\n * That function is now fully correct for the broader `cli: true`/`cli: {}`\n * default surface too (#2638: same \"every public method minus exclude\"\n * resolution core's now-retired `CLIGenerator.listCommands()` used (#2664),\n * so a bare `cli: true` is inspected the same as an explicit `include`).\n * But `smrtPlugin()`'s default\n * `validateCliApiCoherence: true` calls this THROWING gate unconditionally\n * from every consuming package's own build (`configResolved`,\n * `vite-plugin/index.ts`) -- and a full-monorepo build during #2638\n * development showed that broader surface has thousands of pre-existing\n * public getters/business-logic methods (e.g.\n * `@happyvertical/smrt-ads:AdGroup.hasStarted`,\n * `@happyvertical/smrt-tags:Tag.getParent`) across ~28 packages that were\n * never meant to be REST-reachable and have no API route today. That\n * over-exposure is real, pre-existing, and unrelated to #2638's framework-\n * lifecycle-method defect -- flipping this gate to enforce it unconditionally\n * would break every one of those packages' builds today, which is a\n * repo-wide triage effort (add routes, or an explicit `cli.exclude`/\n * `skipApiCheck` per owner) this PR did not undertake and is out of its\n * file boundary. So the gate keeps its pre-#2638 blast radius -- classes\n * that spell out a non-empty `cli.include` -- while `findCliApiCoherenceViolations`\n * is complete and available (and covered by its own tests) for the broader\n * check once that pre-existing surface is triaged.\n */\nexport function validateCliIncludeAgainstApi(\n manifest: SmartObjectManifest,\n): void {\n const allViolations = findCliApiCoherenceViolations(manifest);\n\n // An invalid `cli.skipApiCheck` array entry (smrt#2857) is a config bug in\n // its own right -- a typo or stale name grants no exemption at all, which\n // would silently reintroduce the class-wide-waiver drift this check\n // exists to prevent. Always throw for it, independent of the narrower\n // explicit-`cli.include` filter below (that filter exists only to avoid\n // breaking pre-existing broad-surface classes; there is no such\n // pre-existing usage of the array form to protect).\n const invalidSkipApiCheckMessages = allViolations.flatMap(\n ({ className, invalidSkipApiCheck }) =>\n (invalidSkipApiCheck ?? []).map(\n (name) =>\n `[smrt] ${className}: cli.skipApiCheck names '${name}', which isn't a\\n` +\n ` CRUD verb or a scanned public method on this class, or isn't part of\\n` +\n ` its current cli.include/cli.exclude surface (a typo, or a stale\\n` +\n ` entry left behind after the command was dropped from cli.include).\\n` +\n ` Fix the typo, or remove '${name}' from cli.skipApiCheck -- an\\n` +\n ` unrecognized or stale name grants no exemption at all.`,\n ),\n );\n\n const violations = allViolations.filter(({ className, unreachable }) => {\n if (unreachable.length === 0) return false;\n const cliConfig = manifest.objects[className]?.decoratorConfig?.cli;\n return (\n typeof cliConfig === 'object' &&\n cliConfig !== null &&\n Array.isArray(cliConfig.include) &&\n cliConfig.include.length > 0\n );\n });\n\n if (violations.length === 0 && invalidSkipApiCheckMessages.length === 0) {\n return;\n }\n\n const messages = [\n ...invalidSkipApiCheckMessages,\n ...violations.flatMap(({ className, unreachable }) => {\n // Only suggest the narrow `skipApiCheck: ['<action>']` form when\n // `<action>` would actually be accepted by it (PR #2860 review, F1):\n // `unreachable` can also contain a `cli.include` entry that names no\n // real CRUD verb or scanned public method at all (a typo, or a\n // getter -- see `resolveCliActionSet`'s doc comment), and suggesting\n // the array form for THAT case would just route the developer into\n // `invalidSkipApiCheck`'s contradictory-sounding second failure.\n const methods = manifest.objects[className]?.methods ?? {};\n const isRealCommandName = (name: string) =>\n (CRUD_OPERATIONS as readonly string[]).includes(name) ||\n methods[name]?.isPublic === true;\n\n return unreachable.map((action) => {\n const skipApiCheckSuggestion = isRealCommandName(action)\n ? ` (or \\`skipApiCheck: ['${action}']\\` to acknowledge only this command)`\n : '';\n return (\n `[smrt] ${className}.${action} is exposed as a CLI command but is not exposed via the api.\\n` +\n ` Either:\\n` +\n ` - Decorate '${action}' with @method({ expose: true }) to route it, or\\n` +\n ` - Add '${action}' to api.include, or\\n` +\n ` - Remove '${action}' from cli.include / add it to cli.exclude.\\n` +\n ` The CLI invokes methods over HTTP; methods without API routes are unreachable.\\n` +\n ` A public method is routed by default only when every parameter can be\\n` +\n ` built from JSON; @method({ expose: true }) overrides that for one method\\n` +\n ` without widening api.include. See withheldSurfaces in the knowledge\\n` +\n ` artifact for the reason this one was withheld (#2686).\\n` +\n ` If this CLI is intentionally invoked in-process (no HTTP), set\\n` +\n ` \\`cli: { skipApiCheck: true }\\`${skipApiCheckSuggestion} on the\\n` +\n ` @smrt() decorator.`\n );\n });\n }),\n ];\n\n throw new Error(messages.join('\\n\\n'));\n}\n\n/**\n * Writes a route file, creating directories as needed\n */\nfunction writeRoute(dir: string, filename: string, content: string): string {\n try {\n // Create directory if needed\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write the file (writeFileSync is synchronous and will throw on failure)\n const filePath = join(dir, filename);\n writeFileSync(filePath, content, 'utf-8');\n console.log(`[smrt] Generated: ${filePath}`);\n return filePath;\n } catch (error) {\n console.error(`[smrt] [ERROR] Failed to write route file:`);\n console.error(`[smrt] [ERROR] Directory: ${dir}`);\n console.error(`[smrt] [ERROR] Filename: ${filename}`);\n console.error(`[smrt] [ERROR] Error:`, error);\n throw error;\n }\n}\n\n/**\n * Converts absolute file path to SvelteKit $lib alias import\n * For SvelteKit projects, uses $lib alias for better module resolution\n */\nfunction getSvelteKitImportPath(\n projectRoot: string,\n objectFilePath: string | undefined,\n objectsDir: string,\n className?: string,\n): string {\n // Handle undefined filePath by generating a default path\n // This allows tests to work without providing explicit file paths\n const filePath =\n objectFilePath ||\n join(projectRoot, objectsDir, `${className || 'Object'}.ts`);\n\n // Convert objectsDir to absolute path if it's relative\n const absoluteObjectsDir = objectsDir.startsWith('/')\n ? objectsDir\n : join(projectRoot, objectsDir);\n\n // Get the relative path from objectsDir to the file\n const relativePath = relative(absoluteObjectsDir, filePath);\n\n // Convert to forward slashes and remove extension\n const normalizedPath = relativePath.replace(/\\\\/g, '/');\n const withoutExtension = normalizedPath.replace(/\\.(ts|js|tsx|jsx)$/, '');\n\n // If objectsDir is under src/lib, use $lib alias\n if (objectsDir.includes('src/lib')) {\n const libSubpath = objectsDir.split('src/lib')[1] || '';\n const fullPath = libSubpath\n ? `${libSubpath}/${withoutExtension}`\n : withoutExtension;\n return `$lib${fullPath}`.replace(/\\/+/g, '/'); // Clean up double slashes\n }\n\n // Otherwise use relative path (fallback for non-standard layouts)\n return withoutExtension.startsWith('.')\n ? withoutExtension\n : `./${withoutExtension}`;\n}\n\n/**\n * Check if an object's source file is local to the project (not in node_modules).\n * The scanner sets packageName for all objects (including local ones from the\n * project's own package.json), so we check the filePath to distinguish.\n */\nfunction isLocalObject(\n projectRoot: string,\n objectDef: SmartObjectDefinition,\n): boolean {\n if (!objectDef.filePath) return false;\n return (\n objectDef.filePath.startsWith(projectRoot) &&\n !objectDef.filePath.includes('/node_modules/')\n );\n}\n\n/**\n * Generates collection route template (GET list, POST create)\n */\nfunction generateTypedRouteErrorHelper(): string {\n return `\nfunction smrtRouteErrorResponse(cause: unknown) {\n const failure = normalizeTypedHttpError(cause);\n if (failure) return json({ error: failure }, { status: failure.status });\n return json({ error: 'Internal server error' }, { status: 500 });\n}\n`;\n}\n\nfunction generateCollectionRouteTemplate(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n includedActions: string[],\n options: SvelteKitOptions,\n routeDir: string,\n): string {\n const hasGet = includedActions.includes('list');\n const hasPost = includedActions.includes('create');\n const modelType = resolveObjectTypeReference(\n projectRoot,\n className,\n objectDef,\n options,\n routeDir,\n );\n const serializers = resolveStandardRouteSerializers(\n objectDef.decoratorConfig?.api,\n );\n const serializerImports = serializers.importStatements.join('\\n');\n // A custom list serializer can render related-table data the per-table\n // change-feed version cannot observe (#1765), so such routes keep the v1\n // body-hash ETag; the default toPublicJSON path uses the v2 version source.\n const listUsesSerializer = !!serializers.listItemSerializerName;\n const readPermissionFields = collectReadPermissionFields(\n objectDef,\n semanticManifest,\n );\n const listUsesPermissionScopedBody = readPermissionFields.length > 0;\n const listUsesBodyHash = listUsesSerializer || listUsesPermissionScopedBody;\n // The build-time web-collection shape digest (#1764) salts the v2 read ETag so\n // a shape-only deploy (no table write) busts every read validator. Deterministic\n // for a given manifest — same value the generated virt-web module exports and\n // the client persistence namespace keys on.\n const webManifestHash = computeWebManifestHash(semanticManifest);\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n\n const imports = `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { error${hasPost ? ', json' : ''} } from '@sveltejs/kit';\n${\n serializerImports ? `${serializerImports}\\n` : ''\n}import { getCollection } from '${configImport}';\n${hasPost ? \"import { normalizeTypedHttpError } from '@happyvertical/smrt-core';\\n\" : ''}\n${modelType.importStatement ? `${modelType.importStatement}\\n` : ''}import type { RequestHandler } from './$types';\n// Note: ${className} is auto-registered by the Vite plugin scanner\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsRouteTenantContext(objectDef) ? generateTenantContextHelper(usesPrincipalContext(objectDef), isTenantScoped(objectDef)) : ''}${hasPost ? generateWritablePolicyHelper(objectDef) : ''}${hasPost ? generateTypedRouteErrorHelper() : ''}${hasGet ? generateListBoundsHelper(objectDef) : ''}${hasGet ? generateConditionalGetRouteHelper(objectDef.decoratorConfig?.api, { tenantScoped: isTenantScoped(objectDef), permissionScoped: listUsesPermissionScopedBody, modelName: className, useBodyHash: listUsesBodyHash, manifestHash: webManifestHash }) : ''}`;\n\n // #1782: tenant-scoped reads fail closed to global (NULL-tenant) rows when no\n // tenant context is active (public/anonymous read). Non-tenant models keep the\n // plain list/count.\n // #2367: every generated page is ordered. `LIST_ORDER_BY` is emitted as a\n // module constant so the ordering is visible in the generated file rather\n // than implied by the database's row order.\n const listAndCount = isTenantScoped(objectDef)\n ? ` const readScope = tenantReadScope();\n const items = await collection.list({ limit, offset, orderBy: LIST_ORDER_BY, where: readScope });\n const count = await collection.count({ where: readScope });`\n : ` const items = await collection.list({ limit, offset, orderBy: LIST_ORDER_BY });\n const count = await collection.count();`;\n\n const getHandler = hasGet\n ? `\n// List all ${className.toLowerCase()}s\nexport const GET: RequestHandler = async ({ locals, url, request }) => {\n${routeGuardPreamble(objectDef, false)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const { limit, offset } = listBounds(url);\n\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n${\n listUsesSerializer\n ? `${listAndCount}\n // Custom serializer may render related-table data → v1 body-hash ETag (#1765).\n const serializedItems = await Promise.all(\n items.map(async (item) =>\n applyReadPermissionRedaction(\n await ${serializers.listItemSerializerName}(item),\n publicJsonOptions,\n ),\n ),\n );\n return conditionalJson(request, { items: serializedItems, count, limit, offset });`\n : listUsesPermissionScopedBody\n ? `${listAndCount}\n // Field read permissions make the body vary by caller permissions → v1 body-hash ETag (#1565).\n const items_public = items.map((item) => item.toPublicJSON(publicJsonOptions));\n return conditionalJson(request, { items: items_public, count, limit, offset });`\n : ` // ETag v2 (#1765): the table-version ETag is checked first; on a concrete\n // If-None-Match the list query below never runs (zero-query 304).\n return conditionalVersionedRead(request, collection.db, collection.tableName, async () => {\n${listAndCount}\n const items_public = items.map((item) => item.toPublicJSON(publicJsonOptions));\n return { items: items_public, count, limit, offset };\n });`\n}\n};\n`\n : '';\n\n const postHandler = hasPost\n ? `\n// Create new ${className.toLowerCase()}\nexport const POST: RequestHandler = async ({ locals, request }) => {\n${routeGuardPreamble(objectDef, true)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const body: unknown = await request.json();\n const data = applyWritablePolicy(body);\n\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n try {\n const item = await collection.create(data);\n${\n serializers.itemSerializerName\n ? `\n const serializedItem = await ${serializers.itemSerializerName}(item);\n\n return json(\n applyReadPermissionRedaction(serializedItem, publicJsonOptions),\n { status: 201 },\n );`\n : `\n return json(item.toPublicJSON(publicJsonOptions), { status: 201 });`\n}\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n};\n`\n : '';\n\n return imports + getHandler + postHandler;\n}\n\nfunction generateCollectionLoad(\n className: string,\n options: { typeName?: string } = {},\n): string {\n const genericSuffix = options.typeName ? `<${options.typeName}>` : '';\n\n return [\n ` const collection = await getCollection${genericSuffix}(`,\n ` '${className}',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateNotFoundError(className: string): string {\n const singleLineNotFoundError = ` if (!item) throw error(404, '${className} not found');`;\n\n if (singleLineNotFoundError.length <= 100) {\n return singleLineNotFoundError;\n }\n\n return [\n ' if (!item)',\n ' throw error(',\n ' 404,',\n ` '${className} not found',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateCollectionNotRegisteredError(className: string): string {\n return [\n ' if (!collection)',\n ' throw error(',\n ' 500,',\n ` '${className} collection is not registered',`,\n ' );',\n ].join('\\n');\n}\n\nfunction generateClassNotRegisteredError(className: string): string {\n return [\n ' if (!registered)',\n ' throw error(',\n ' 500,',\n ` '${className} is not registered',`,\n ' );',\n ].join('\\n');\n}\n\n/**\n * Generates item route template (GET, PUT, DELETE)\n */\nfunction generateItemRouteTemplate(\n projectRoot: string,\n className: string,\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n includedActions: string[],\n options: SvelteKitOptions,\n routeDir: string,\n): string {\n const hasGet = includedActions.includes('get');\n const hasPut = includedActions.includes('update');\n const hasDelete = includedActions.includes('delete');\n const simpleClassName = extractSimpleClassName(className);\n const modelType = resolveObjectTypeReference(\n projectRoot,\n className,\n objectDef,\n options,\n routeDir,\n );\n const serializers = resolveStandardRouteSerializers(\n objectDef.decoratorConfig?.api,\n );\n const serializerImports = serializers.importStatements.join('\\n');\n // A custom item serializer can render related-table data the per-table\n // change-feed version cannot observe (#1765), so such routes keep the v1\n // body-hash ETag; the default toPublicJSON path uses the v2 version source.\n const getUsesSerializer = !!serializers.itemSerializerName;\n const readPermissionFields = collectReadPermissionFields(\n objectDef,\n semanticManifest,\n );\n const getUsesPermissionScopedBody = readPermissionFields.length > 0;\n const getUsesBodyHash = getUsesSerializer || getUsesPermissionScopedBody;\n // The build-time web-collection shape digest (#1764) salts the v2 read ETag —\n // same value as the list route and the generated virt-web module (see above).\n const webManifestHash = computeWebManifestHash(semanticManifest);\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n\n const imports = `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { error${hasPut || hasDelete ? ', json' : ''} } from '@sveltejs/kit';\n${serializerImports ? `${serializerImports}\\n` : ''}import { getCollection } from '${configImport}';\n${hasPut || hasDelete ? \"import { normalizeTypedHttpError } from '@happyvertical/smrt-core';\\n\" : ''}\n${modelType.importStatement ? `${modelType.importStatement}\\n` : ''}import type { RequestHandler } from './$types';\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsRouteTenantContext(objectDef) ? generateTenantContextHelper(usesPrincipalContext(objectDef), isTenantScoped(objectDef)) : ''}${hasPut ? generateWritablePolicyHelper(objectDef) : ''}${hasPut || hasDelete ? generateTypedRouteErrorHelper() : ''}${hasGet ? generateConditionalGetRouteHelper(objectDef.decoratorConfig?.api, { tenantScoped: isTenantScoped(objectDef), permissionScoped: getUsesPermissionScopedBody, modelName: className, useBodyHash: getUsesBodyHash, manifestHash: webManifestHash }) : ''}`;\n\n // #1782: a tenant-scoped single read fails closed to global (NULL-tenant)\n // rows when no tenant context is active, so a public/anonymous GET /:id can't\n // fetch another tenant's row by id. Mutations (PUT/DELETE) require auth, so\n // they keep the plain id lookup and rely on the interceptor.\n const getForRead = isTenantScoped(objectDef)\n ? ` const readScope = tenantReadScope();\n const item = await collection.get(\n readScope ? { id: params.id, ...readScope } : params.id,\n );`\n : ` const item = await collection.get(params.id);`;\n\n const getHandler = hasGet\n ? `\n// Get single ${simpleClassName.toLowerCase()}\nexport const GET: RequestHandler = async ({ locals, params, request }) => {\n${routeGuardPreamble(objectDef, false)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n${\n getUsesSerializer\n ? `${getForRead}\n${generateNotFoundError(className)}\n // Custom serializer may render related-table data → v1 body-hash ETag (#1765).\n const serializedItem = await ${serializers.itemSerializerName}(item);\n return conditionalJson(\n request,\n applyReadPermissionRedaction(serializedItem, publicJsonOptions),\n );`\n : getUsesPermissionScopedBody\n ? `${getForRead}\n${generateNotFoundError(className)}\n // Field read permissions make the body vary by caller permissions → v1 body-hash ETag (#1565).\n return conditionalJson(request, item.toPublicJSON(publicJsonOptions));`\n : ` // ETag v2 (#1765): a concrete If-None-Match answers 304 without the row fetch\n // (a delete advances the version, so a since-deleted row can't false-match);\n // a wildcard \\`*\\` is deferred until the fetch confirms the row exists.\n return conditionalVersionedRead(request, collection.db, collection.tableName, async () => {\n${getForRead}\n${generateNotFoundError(className)}\n return item.toPublicJSON(publicJsonOptions);\n });`\n}\n};\n`\n : '';\n\n const putHandler = hasPut\n ? `\n// Update ${simpleClassName.toLowerCase()}\nexport const PUT: RequestHandler = async ({ locals, params, request }) => {\n${routeGuardPreamble(objectDef, true)}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n const item = await collection.get(params.id);\n${generateNotFoundError(className)}\n\n const body: unknown = await request.json();\n const data = applyWritablePolicy(body);\n Object.assign(item, data);\n try {\n await item.save();\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n${\n serializers.itemSerializerName\n ? `\n const serializedItem = await ${serializers.itemSerializerName}(item);\n\n return json(applyReadPermissionRedaction(serializedItem, publicJsonOptions));`\n : `\n return json(item.toPublicJSON(publicJsonOptions));`\n}\n};\n`\n : '';\n\n const deleteHandler = hasDelete\n ? `\n// Delete ${simpleClassName.toLowerCase()}\nexport const DELETE: RequestHandler = async ({ locals, params }) => {\n${routeGuardPreamble(objectDef, true)}\n${generateCollectionLoad(className, { typeName: modelType.typeName })}\n const item = await collection.get(params.id);\n${generateNotFoundError(className)}\n\n try {\n await item.delete();\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n return json({ success: true });\n};\n`\n : '';\n\n return imports + getHandler + putHandler + deleteHandler;\n}\n\n/**\n * Generates custom action route template\n */\nfunction generateActionRouteTemplate(\n projectRoot: string,\n routeDir: string,\n routeSpecs: GeneratedActionRouteSpec[],\n objectDef: SmartObjectDefinition,\n semanticManifest: SmartObjectManifest,\n options: SvelteKitOptions,\n): string {\n if (routeSpecs.length === 0) {\n throw new Error('Cannot generate a custom action route without handlers');\n }\n\n const [firstSpec] = routeSpecs;\n const { lookupClassName, routeConfig, hostType } = firstSpec;\n assertCompatibleCustomActionRouteSpecs(routeSpecs);\n const lookupModelType = resolveObjectTypeReference(\n projectRoot,\n lookupClassName,\n firstSpec.lookupObjectDef,\n options,\n routeDir,\n );\n const hostModelType = resolveObjectTypeReference(\n projectRoot,\n firstSpec.hostClassName,\n objectDef,\n options,\n routeDir,\n );\n const typeImports = mergeImportStatements([\n lookupModelType.importStatement,\n hostModelType.importStatement,\n ]);\n\n // Import only the decoders a handler in this file actually calls -- an\n // unconditional import would leave unused symbols in every generated action\n // route. A GET handler may need the number/boolean query-string decoders too,\n // since `URLSearchParams` hands it strings for both (#2686).\n const decoderImports = new Set<string>();\n for (const spec of routeSpecs) {\n if (hasSingleOptionsParameter(spec.actionDef)) continue;\n for (const parameter of spec.actionDef.parameters ?? []) {\n const decoder =\n spec.routeConfig?.method === 'GET'\n ? queryStringDecoderFor(parameter.type)\n : declaredTypeAcceptsDate(parameter.type)\n ? 'toCustomActionDate'\n : undefined;\n if (decoder) decoderImports.add(decoder);\n }\n }\n const coreImports = [\n 'normalizeCustomActionFailure',\n 'normalizeTypedHttpError',\n ...[...decoderImports].sort(),\n ].join(', ');\n const configImport = resolveSvelteKitConfigImport(\n projectRoot,\n routeDir,\n options,\n );\n const importBlock = [\n \"import { error, json } from '@sveltejs/kit';\",\n `import { ${coreImports} } from '@happyvertical/smrt-core';`,\n hostType === 'collection' || routeConfig.scope !== 'collection'\n ? `import { getCollection } from '${configImport}';`\n : [\n `import '${configImport}';`,\n \"import { ObjectRegistry } from '@happyvertical/smrt-core';\",\n ].join('\\n'),\n typeImports,\n \"import type { RequestHandler } from './$types';\",\n ]\n .filter(Boolean)\n .join('\\n');\n\n const tenantScoped =\n isTenantScoped(objectDef) ||\n routeSpecs.some(\n (spec) => !!spec.lookupObjectDef && isTenantScoped(spec.lookupObjectDef),\n );\n const principalContext =\n usesPrincipalContext(objectDef) ||\n routeSpecs.some(\n (spec) =>\n !!spec.lookupObjectDef && usesPrincipalContext(spec.lookupObjectDef),\n );\n const needsTenantContext = tenantScoped || principalContext;\n const handlers = routeSpecs\n .map((spec) =>\n generateActionRouteHandler(\n spec.lookupClassName,\n spec.actionName,\n spec.actionDef,\n spec.routeConfig,\n spec.hostType,\n tenantScoped,\n needsTenantContext,\n lookupModelType.typeName,\n hostModelType.typeName,\n ),\n )\n .join('\\n');\n\n return `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\n${importBlock}\n${generateAuthGuardHelper(objectDef, semanticManifest)}${needsTenantContext ? generateTenantContextHelper(principalContext, tenantScoped) : ''}\n${generateTypedRouteErrorHelper()}\n${handlers}`;\n}\n\nfunction generateActionRouteHandler(\n lookupClassName: string,\n actionName: string,\n actionDef: MethodDefinition,\n routeConfig: ResolvedApiActionRouteConfig,\n hostType: 'item' | 'collection',\n tenantScoped: boolean,\n needsTenantContext: boolean,\n lookupTypeName: string,\n hostTypeName: string,\n): string {\n const handlerName = routeConfig.method;\n // Mutating verbs require auth even when reads are public (#1540). Tenant-scoped\n // objects also establish tenant context so the action runs filtered.\n const guardLines = [\n ` requireRouteAuth(locals, ${routeConfig.method !== 'GET'});`,\n ];\n if (needsTenantContext) {\n guardLines.push(' establishTenantContext(locals);');\n }\n const authGuardLine = guardLines.join('\\n');\n const hasInput = actionDef.parameters.length > 0;\n const needsRequest = hasInput;\n const collectionHandlerArgs = buildRouteHandlerArgs(\n routeConfig.pathParamNames.length > 0,\n needsRequest,\n );\n const itemHandlerArgs = buildRouteHandlerArgs(true, needsRequest);\n\n if (hostType === 'collection') {\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n actionDef.isStatic,\n );\n const receiverExpression = actionDef.isStatic\n ? 'CollectionClass'\n : 'typedCollection';\n const staticTargetLoad = actionDef.isStatic\n ? ` const CollectionClass = typedCollection.constructor as typeof ${hostTypeName};\\n`\n : '';\n const scopedOptions = buildScopedOptionsForTenantRead(\n actionDef,\n routeConfig,\n tenantScoped,\n );\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n scopedOptions.optionsIdentifier,\n routeConfig.method,\n );\n\n return `// Custom collection method: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${collectionHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(lookupClassName, { typeName: lookupTypeName })}\n const typedCollection = collection as unknown as ${hostTypeName};\n${generateCollectionNotRegisteredError(lookupClassName)}\n${staticTargetLoad}\n\n${optionsLoad}${scopedOptions.source} let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n receiverExpression,\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n }\n\n if (routeConfig.scope === 'collection') {\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n true,\n );\n const scopedOptions = buildScopedOptionsForTenantRead(\n actionDef,\n routeConfig,\n tenantScoped,\n );\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n scopedOptions.optionsIdentifier,\n routeConfig.method,\n );\n return `// Custom collection action: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${collectionHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n const registered = ObjectRegistry.getClass('${lookupClassName}');\n${generateClassNotRegisteredError(lookupClassName)}\n\n${optionsLoad}${scopedOptions.source} const ClassRef = registered.constructor as typeof ${hostTypeName};\n let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n 'ClassRef',\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n }\n\n const optionsLoad = buildActionOptionsLoad(\n actionName,\n actionDef,\n routeConfig,\n hostTypeName,\n false,\n );\n const scopedItemLoad =\n tenantScoped && routeConfig.method === 'GET'\n ? ` const readScope = tenantReadScope();\n const item = await collection.get(\n readScope ? { id: params.id, ...readScope } : params.id,\n );`\n : ' const item = await collection.get(params.id);';\n const invocationArgs = buildActionInvocationArgs(\n actionDef,\n 'options',\n routeConfig.method,\n );\n return `// Custom action: ${actionName}\nexport const ${handlerName}: RequestHandler = async (${itemHandlerArgs}) => {\n${authGuardLine}\n const publicJsonOptions = getPublicJsonOptions(locals);\n${generateCollectionLoad(lookupClassName, { typeName: lookupTypeName })}\n${scopedItemLoad}\n${generateNotFoundError(lookupClassName)}\n\n${optionsLoad} let result: unknown;\n try {\n result = ${buildActionInvocationExpression(\n 'item',\n actionName,\n invocationArgs,\n )};\n } catch (cause) {\n return smrtRouteErrorResponse(cause);\n }\n\n const failure = normalizeCustomActionFailure(result);\n if (failure) {\n return json({ error: failure }, { status: failure.status });\n }\n\n return json({\n action: '${actionName}',\n result: toPublicResult(result, publicJsonOptions),\n });\n};\n`;\n}\n\nfunction generateKnowledgeRouteTemplate(\n knowledge: DomainKnowledgeConfig,\n artifact: Record<string, unknown> | null,\n): string {\n const api = knowledge.api ?? {};\n const includeDocs = api.includeDocs === true;\n const includePrompts = api.includePrompts === true;\n const requireAdmin = api.requireAdmin !== false;\n const artifactLiteral = artifact ? JSON.stringify(artifact) : 'null';\n\n return `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n\nimport { dev } from '$app/environment';\nimport { error, json } from '@sveltejs/kit';\nimport type { RequestHandler } from './$types';\n\nconst INCLUDE_DOCS_BY_DEFAULT = ${JSON.stringify(includeDocs)};\nconst INCLUDE_PROMPTS_BY_DEFAULT = ${JSON.stringify(includePrompts)};\nconst REQUIRE_ADMIN = ${JSON.stringify(requireAdmin)};\nconst KNOWLEDGE_ARTIFACT: Record<string, unknown> | null = ${artifactLiteral};\n\nif (!dev && !REQUIRE_ADMIN) {\n console.warn('[smrt] PUBLIC knowledge API route enabled; unauthenticated responses are sanitized.');\n}\n\nexport const GET: RequestHandler = async ({ locals, url, setHeaders }) => {\n setHeaders({ 'cache-control': 'private, no-store' });\n\n if (!dev && REQUIRE_ADMIN && !isKnowledgeAdmin(locals)) {\n throw error(403, 'SMRT knowledge requires dev mode or admin access');\n }\n\n const artifact = readKnowledgeArtifact();\n const includeDocs = queryBoolean(url, 'includeDocs', INCLUDE_DOCS_BY_DEFAULT);\n const includePrompts = queryBoolean(\n url,\n 'includePrompts',\n INCLUDE_PROMPTS_BY_DEFAULT,\n );\n\n return json(sanitizeKnowledgeArtifact(artifact, {\n includeDocs,\n includePrompts,\n publicAccess: !REQUIRE_ADMIN,\n }));\n};\n\nfunction readKnowledgeArtifact(): Record<string, unknown> {\n if (!KNOWLEDGE_ARTIFACT) throw error(404, 'SMRT knowledge artifact not found');\n return KNOWLEDGE_ARTIFACT;\n}\n\nfunction queryBoolean(url: URL, name: string, defaultValue: boolean): boolean {\n const value = url.searchParams.get(name);\n if (value === null) return defaultValue;\n return value === 'true';\n}\n\nfunction sanitizeKnowledgeArtifact(\n artifact: Record<string, unknown>,\n options: { includeDocs: boolean; includePrompts: boolean; publicAccess: boolean },\n): Record<string, unknown> {\n const sanitized = { ...artifact };\n\n if (!options.includeDocs) {\n delete sanitized.agentDoc;\n // Linked module docs (#2108) are the same authored prose as agentDoc, just\n // split across siblings — they must drop with it, not leak past the flag.\n delete sanitized.moduleDocs;\n }\n\n if (!options.includePrompts) {\n sanitized.prompts = [];\n }\n\n if (options.publicAccess) {\n delete sanitized.dependencies;\n delete sanitized.sourceHashes;\n delete sanitized.sourceManifestPath;\n delete sanitized.agentDocPath;\n }\n\n return sanitized;\n}\n\nfunction recordValue(value: unknown, key: string): unknown {\n if (!value || typeof value !== 'object') return undefined;\n return (value as Record<string, unknown>)[key];\n}\n\nfunction isKnowledgeAdmin(locals: unknown): boolean {\n if (!locals || typeof locals !== 'object') return false;\n const localRecord = locals as Record<string, unknown>;\n if (\n localRecord.smrtKnowledgeAdmin === true ||\n localRecord.smrtAdmin === true\n ) {\n return true;\n }\n\n const userRoles = rolesFrom(localRecord.user);\n const sessionRoles = rolesFrom(recordValue(localRecord.session, 'user'));\n return [...userRoles, ...sessionRoles].some((role) =>\n ['admin', 'owner', 'superadmin'].includes(role),\n );\n}\n\nfunction rolesFrom(value: unknown): string[] {\n if (!value || typeof value !== 'object') return [];\n const roleList = recordValue(value, 'roles');\n const roles = Array.isArray(roleList) ? roleList : [recordValue(value, 'role')];\n return roles\n .filter((role): role is string => typeof role === 'string')\n .map((role) => role.toLowerCase());\n}\n`;\n}\n\n/**\n * Updates .gitignore to exclude auto-generated routes\n */\nfunction updateGitignore(\n projectRoot: string,\n generatedRoutePaths: readonly string[],\n routeRoot: string,\n): void {\n const gitignorePath = join(projectRoot, '.gitignore');\n\n // Read existing .gitignore or create empty string\n let gitignoreContent = '';\n if (existsSync(gitignorePath)) {\n gitignoreContent = readFileSync(gitignorePath, 'utf-8');\n }\n\n const generatedPaths = [\n ...new Set(\n [...generatedRoutePaths, ...findGeneratedRouteFiles(routeRoot)].map(\n (path) => gitignorePatternForPath(relative(projectRoot, path)),\n ),\n ),\n ].sort((a, b) => a.localeCompare(b));\n const updatedContent = updateGeneratedRouteIgnoreBlock(\n gitignoreContent,\n generatedPaths,\n );\n\n if (updatedContent !== gitignoreContent) {\n writeFileSync(gitignorePath, updatedContent, 'utf-8');\n console.log('[smrt] Updated .gitignore with generated route paths');\n }\n}\n\nfunction findGeneratedRouteFiles(routeRoot: string): string[] {\n if (!existsSync(routeRoot)) return [];\n const files: string[] = [];\n for (const entry of readdirSync(routeRoot, { withFileTypes: true })) {\n const path = join(routeRoot, entry.name);\n if (entry.isDirectory()) {\n files.push(...findGeneratedRouteFiles(path));\n } else if (\n entry.isFile() &&\n entry.name === '+server.ts' &&\n readFileSync(path, 'utf-8').startsWith(AUTO_GENERATED_ROUTE_HEADER)\n ) {\n files.push(path);\n }\n }\n return files;\n}\n\nfunction gitignorePatternForPath(path: string): string {\n // Generated SvelteKit item routes include literal `[id]` segments. Escape\n // every Git pattern metacharacter so the managed block ignores files, not\n // glob expressions that happen to resemble their paths.\n return path.replaceAll('\\\\', '/').replaceAll(/([*?[\\]\\\\!#])/g, '\\\\$1');\n}\n\n/**\n * Whether a line has the shape versions before #2185 wrote beneath the legacy\n * header: a recursive `+server.ts` wildcard, optionally negated. The pattern is\n * matched by shape rather than against the currently configured `routesDir`,\n * because a project that moved `routesDir` after adopting the plugin (as\n * `@happyvertical/smrt-content` did, `src/routes/api` -> `src/routes/api/v1`)\n * still carries the pair its earlier `routesDir` produced.\n */\nfunction isLegacyGeneratedRoutePattern(line: string): boolean {\n // A comment is a boundary, never part of the run — otherwise a note that\n // happens to end in the same suffix would be swallowed with it.\n if (line.startsWith('#')) {\n return false;\n }\n return /^!?[^\\s].*\\/\\*\\*\\/\\+server\\.ts$/.test(line);\n}\n\n/**\n * Drop the generator-owned legacy header together with the contiguous run of\n * legacy-shaped patterns directly beneath it. Only that recognized run is\n * migrated: the first line that is not legacy-shaped ends it, so an application\n * rule — including an identical broad pattern the project owns elsewhere in the\n * file — survives untouched.\n */\nfunction stripLegacyGeneratedRouteIgnores(lines: string[]): void {\n const headerIndex = lines.indexOf(LEGACY_GITIGNORE_HEADER);\n if (headerIndex === -1) {\n return;\n }\n\n let end = headerIndex + 1;\n while (end < lines.length && isLegacyGeneratedRoutePattern(lines[end])) {\n end += 1;\n }\n\n // A header with nothing recognizable beneath it is left alone rather than\n // guessed at, matching the bounded-marker handling above.\n if (end > headerIndex + 1) {\n lines.splice(headerIndex, end - headerIndex);\n }\n}\n\nfunction updateGeneratedRouteIgnoreBlock(\n gitignoreContent: string,\n generatedPaths: readonly string[],\n): string {\n const lines = gitignoreContent.split('\\n');\n const managedBlock = [\n GITIGNORE_MANAGED_BLOCK_START,\n ...generatedPaths,\n GITIGNORE_MANAGED_BLOCK_END,\n ];\n\n if (\n lines.includes(GITIGNORE_MANAGED_BLOCK_START) ||\n lines.includes(GITIGNORE_MANAGED_BLOCK_END)\n ) {\n // Migration runs even once the bounded block exists: a project generated by\n // the first #2185 release kept its unmatched legacy pair, and the negation\n // in that pair silently re-includes anything the bounded block stops\n // listing. Strip it before locating the markers so the indices stay valid.\n stripLegacyGeneratedRouteIgnores(lines);\n\n const startIndex = lines.indexOf(GITIGNORE_MANAGED_BLOCK_START);\n const endIndex = lines.indexOf(GITIGNORE_MANAGED_BLOCK_END);\n if (startIndex === -1 || endIndex < startIndex) {\n // An incomplete marker pair may have been authored by a consumer. Do\n // not guess at its boundary or remove any user-managed ignore rules.\n return gitignoreContent;\n }\n\n lines.splice(\n startIndex,\n endIndex - startIndex + 1,\n ...(generatedPaths.length > 0 ? managedBlock : []),\n );\n return lines.join('\\n');\n }\n\n stripLegacyGeneratedRouteIgnores(lines);\n\n if (generatedPaths.length === 0) {\n return lines.join('\\n');\n }\n\n let updatedContent = lines.join('\\n');\n if (updatedContent.length > 0 && !updatedContent.endsWith('\\n')) {\n updatedContent += '\\n';\n }\n if (updatedContent.length > 0 && !updatedContent.endsWith('\\n\\n')) {\n updatedContent += '\\n';\n }\n\n return `${updatedContent}${managedBlock.join('\\n')}\\n`;\n}\n"],"mappings":"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"}