@happyvertical/smrt-core 0.57.46 → 0.57.47
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.
- package/AGENTS.md +11 -3
- package/agents/browser-entry.md +16 -0
- package/agents/build-knowledge.md +58 -14
- package/agents/change-feed.md +20 -0
- package/agents/generators.md +69 -3
- package/agents/schema-paths.md +82 -0
- package/dist/_virtual/_rolldown/runtime.js +22 -1
- package/dist/browser.d.ts +2 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/cascade.d.ts +46 -0
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +96 -7
- package/dist/cascade.js.map +1 -1
- package/dist/change-feed.d.ts.map +1 -1
- package/dist/change-feed.js +7 -4
- package/dist/change-feed.js.map +1 -1
- package/dist/class.d.ts.map +1 -1
- package/dist/class.js +3 -3
- package/dist/class.js.map +1 -1
- package/dist/consumer-plugin/index.d.ts +13 -0
- package/dist/consumer-plugin/index.d.ts.map +1 -1
- package/dist/consumer-plugin/index.js +69 -13
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/consumer-plugin.js +2 -2
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +3 -3
- package/dist/database.js.map +1 -1
- package/dist/dispatch/bus.d.ts.map +1 -1
- package/dist/dispatch/bus.js +1 -4
- package/dist/dispatch/bus.js.map +1 -1
- package/dist/dispatch/index.d.ts +1 -1
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/types.d.ts +22 -3
- package/dist/dispatch/types.d.ts.map +1 -1
- package/dist/generators/changes-route.d.ts.map +1 -1
- package/dist/generators/changes-route.js +2 -2
- package/dist/generators/changes-route.js.map +1 -1
- package/dist/generators/custom-action.d.ts +11 -0
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +23 -4
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lazy-config.d.ts +120 -3
- package/dist/lazy-config.d.ts.map +1 -1
- package/dist/lazy-config.js +81 -10
- package/dist/lazy-config.js.map +1 -1
- package/dist/manifest/generator.d.ts +8 -2
- package/dist/manifest/generator.d.ts.map +1 -1
- package/dist/manifest/generator.js +6 -5
- package/dist/manifest/generator.js.map +1 -1
- package/dist/manifest/index.d.ts +1 -0
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +2 -1
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/local-manifest-reader.d.ts +13 -2
- package/dist/manifest/local-manifest-reader.d.ts.map +1 -1
- package/dist/manifest/local-manifest-reader.js +38 -6
- package/dist/manifest/local-manifest-reader.js.map +1 -1
- package/dist/manifest/manifest-loader.d.ts +9 -8
- package/dist/manifest/manifest-loader.d.ts.map +1 -1
- package/dist/manifest/manifest-loader.js +67 -27
- package/dist/manifest/manifest-loader.js.map +1 -1
- package/dist/manifest/object-declarations.d.ts +116 -0
- package/dist/manifest/object-declarations.d.ts.map +1 -0
- package/dist/manifest/object-declarations.js +161 -0
- package/dist/manifest/object-declarations.js.map +1 -0
- package/dist/manifest/static-manifest.d.ts.map +1 -1
- package/dist/manifest/static-manifest.js +5 -3
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.d.ts.map +1 -1
- package/dist/manifest/store.js +18 -2
- package/dist/manifest/store.js.map +1 -1
- package/dist/manifest/test-artifacts.d.ts +57 -0
- package/dist/manifest/test-artifacts.d.ts.map +1 -0
- package/dist/manifest/test-artifacts.js +111 -0
- package/dist/manifest/test-artifacts.js.map +1 -0
- package/dist/manifest.js +2 -1
- package/dist/manifest.json +5 -3
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +11 -3
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -1
- package/dist/migrations/qualified-name-aliases.d.ts.map +1 -1
- package/dist/migrations/qualified-name-aliases.js +1 -1
- package/dist/migrations/qualified-name-aliases.js.map +1 -1
- package/dist/migrations.js +3 -1
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +2 -2
- package/dist/object.js.map +1 -1
- package/dist/postgres-permissions.d.ts.map +1 -1
- package/dist/postgres-permissions.js +4 -3
- package/dist/postgres-permissions.js.map +1 -1
- package/dist/postgres-timeouts.d.ts +30 -3
- package/dist/postgres-timeouts.d.ts.map +1 -1
- package/dist/postgres-timeouts.js +39 -2
- package/dist/postgres-timeouts.js.map +1 -1
- package/dist/prebuild/index.d.ts.map +1 -1
- package/dist/prebuild/index.js +14 -11
- package/dist/prebuild/index.js.map +1 -1
- package/dist/registry/class-registration.d.ts.map +1 -1
- package/dist/registry/class-registration.js +24 -2
- package/dist/registry/class-registration.js.map +1 -1
- package/dist/registry/collection-exposure.d.ts +27 -0
- package/dist/registry/collection-exposure.d.ts.map +1 -1
- package/dist/registry/collection-exposure.js +74 -1
- package/dist/registry/collection-exposure.js.map +1 -1
- package/dist/registry/collection-resolution.d.ts.map +1 -1
- package/dist/registry/collection-resolution.js +1 -0
- package/dist/registry/collection-resolution.js.map +1 -1
- package/dist/registry/framework-base-classes.d.ts.map +1 -1
- package/dist/registry/framework-base-classes.js +5 -0
- package/dist/registry/framework-base-classes.js.map +1 -1
- package/dist/registry/schema-builder.d.ts +8 -1
- package/dist/registry/schema-builder.d.ts.map +1 -1
- package/dist/registry/schema-builder.js +17 -4
- package/dist/registry/schema-builder.js.map +1 -1
- package/dist/registry/types.d.ts +12 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry.d.ts +2 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +30 -10
- package/dist/registry.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +10 -8
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/scanner/types.d.ts +29 -0
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/schema/generator.d.ts +32 -0
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +59 -0
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/live-parity.d.ts.map +1 -1
- package/dist/schema/live-parity.js +4 -2
- package/dist/schema/live-parity.js.map +1 -1
- package/dist/scripts/browser-unbundled-dev.mjs +90 -0
- package/dist/scripts/generate-test-manifest.js +9 -49
- package/dist/smrt-knowledge.json +16 -16
- package/dist/system/compatibility.d.ts.map +1 -1
- package/dist/system/compatibility.js +12 -4
- package/dist/system/compatibility.js.map +1 -1
- package/dist/system/schema.d.ts +70 -8
- package/dist/system/schema.d.ts.map +1 -1
- package/dist/system/schema.js +231 -24
- package/dist/system/schema.js.map +1 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +14 -2
- package/dist/testing/database.js.map +1 -1
- package/dist/tools/tool-generator.d.ts.map +1 -1
- package/dist/tools/tool-generator.js +2 -2
- package/dist/tools/tool-generator.js.map +1 -1
- package/dist/utils/import-workspace-module.d.ts.map +1 -1
- package/dist/utils/import-workspace-module.js +23 -0
- package/dist/utils/import-workspace-module.js.map +1 -1
- package/dist/utils/naming.js +5 -3
- package/dist/utils/naming.js.map +1 -1
- package/dist/vendor/pluralize/pluralize.js +421 -0
- package/dist/vendor/pluralize/pluralize.js.map +1 -0
- package/dist/vite-plugin/api-client-entries.d.ts +5 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +11 -6
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/consumer-import.d.ts +28 -0
- package/dist/vite-plugin/consumer-import.d.ts.map +1 -0
- package/dist/vite-plugin/consumer-import.js +42 -0
- package/dist/vite-plugin/consumer-import.js.map +1 -0
- package/dist/vite-plugin/dev-plane-route.d.ts +6 -1
- package/dist/vite-plugin/dev-plane-route.d.ts.map +1 -1
- package/dist/vite-plugin/dev-plane-route.js +8 -9
- package/dist/vite-plugin/dev-plane-route.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +12 -9
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/resources-route.d.ts.map +1 -1
- package/dist/vite-plugin/resources-route.js +3 -8
- package/dist/vite-plugin/resources-route.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +7 -11
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/sync-apply-route.d.ts +16 -0
- package/dist/vite-plugin/sync-apply-route.d.ts.map +1 -1
- package/dist/vite-plugin/sync-apply-route.js +48 -6
- package/dist/vite-plugin/sync-apply-route.js.map +1 -1
- package/package.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client-entries.js","names":[],"sources":["../../src/vite-plugin/api-client-entries.ts"],"sourcesContent":["/**\n * Manifest -> generated API-client entry selection.\n *\n * Runtime client values, Vite ambient declarations, and physical prebuild\n * declarations must agree on which manifest object owns a collection's\n * canonical endpoint. Collection classes describe access methods, not row\n * payloads, so a populated model always wins the shared collection key.\n */\n\nimport {\n CRUD_OPERATIONS,\n createManifestClassNamePredicate,\n resolveApiMethodExposure,\n} from '../generators/custom-action.js';\nimport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types.js';\nimport { resolveApiActionRouteConfig } from './sveltekit-generator.js';\nimport {\n findManifestObjectByName,\n isCollectionManifestClass,\n orderedManifestObjectEntries,\n resolveCollectionItemObject,\n} from './web-collections.js';\n\nexport type ApiClientCrudMethod =\n | 'list'\n | 'get'\n | 'create'\n | 'update'\n | 'delete'\n | 'search';\n\nexport interface ApiClientEntry {\n /** Original key in manifest.objects. */\n objectName: string;\n /** Object whose routes and custom methods this client entry exposes. */\n obj: SmartObjectDefinition;\n /** Canonical collection key or deterministic class-derived secondary key. */\n clientKey: string;\n /** Row-payload interface used by CRUD methods for this entry. */\n dataInterfaceName: string;\n /** Standard client operations whose server routes are actually emitted. */\n crudMethods: ApiClientCrudMethod[];\n /** Custom methods whose routes are actually emitted by the server. */\n customMethods: Array<{\n name: string;\n scope: 'item' | 'collection';\n pathParamNames: string[];\n parameters: Array<{\n name: string;\n type: string;\n optional?: boolean;\n default?: unknown;\n }>;\n }>;\n}\n\nexport function renderApiClientCrudType(\n dataInterfaceName: string,\n crudMethods: ApiClientCrudMethod[],\n overriddenMethods: string[] = [],\n): string | undefined {\n const overridden = new Set(overriddenMethods);\n const methods = crudMethods.filter((method) => !overridden.has(method));\n if (methods.length === 0) return undefined;\n if (\n methods.length === 6 &&\n methods.every(\n (method, index) => method === [...CRUD_OPERATIONS, 'search'][index],\n )\n ) {\n return `CrudOperations<${dataInterfaceName}>`;\n }\n return `Pick<CrudOperations<${dataInterfaceName}>, ${methods\n .map((method) => JSON.stringify(method))\n .join(' | ')}>`;\n}\n\nexport function renderApiClientCustomMethodParameters(\n method: ApiClientEntry['customMethods'][number],\n mapType: (type: string) => string,\n): string {\n const pathParamNames = new Set(method.pathParamNames);\n const params = method.parameters;\n const hasSingleOptionsParameter =\n params.length === 1 && params[0]?.name === 'options';\n const requiredPathProperties = method.pathParamNames\n .map((name) => `${name}: string`)\n .join('; ');\n let optionsType: string;\n\n if (hasSingleOptionsParameter) {\n const directOptionsType = mapType(params[0].type);\n optionsType = requiredPathProperties\n ? `${directOptionsType} & { ${requiredPathProperties} }`\n : directOptionsType;\n } else {\n const parameterNames = new Set(params.map((param) => param.name));\n const properties = params.map(\n (param) =>\n `${param.name}${pathParamNames.has(param.name) || !param.optional ? '' : '?'}: ${mapType(param.type)}`,\n );\n for (const pathParamName of method.pathParamNames) {\n if (!parameterNames.has(pathParamName)) {\n properties.push(`${pathParamName}: string`);\n }\n }\n optionsType =\n properties.length > 0\n ? `{ ${properties.join('; ')} }`\n : 'Record<string, never>';\n }\n\n const hasRequiredOptions = hasSingleOptionsParameter\n ? !params[0]?.optional\n : params.some(\n (param) => !pathParamNames.has(param.name) && !param.optional,\n );\n const optionsParameter = `${method.pathParamNames.length > 0 || hasRequiredOptions ? 'options' : 'options?'}: ${optionsType}`;\n return method.scope === 'collection'\n ? optionsParameter\n : `id: string, ${optionsParameter}`;\n}\n\ninterface ManifestCandidate {\n objectName: string;\n obj: SmartObjectDefinition;\n}\n\nfunction compareText(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction candidateIdentity(candidate: ManifestCandidate): string {\n return [\n candidate.obj.qualifiedName ?? '',\n candidate.obj.className,\n candidate.objectName,\n ].join('\\0');\n}\n\nfunction compareCandidateIdentity(\n left: ManifestCandidate,\n right: ManifestCandidate,\n): number {\n return compareText(candidateIdentity(left), candidateIdentity(right));\n}\n\nfunction lowerFirst(value: string): string {\n return value ? value[0].toLowerCase() + value.slice(1) : value;\n}\n\nfunction isAncestorOf(\n manifest: SmartObjectManifest,\n ancestor: SmartObjectDefinition,\n descendant: SmartObjectDefinition,\n): boolean {\n const seen = new Set<string>();\n let child = descendant;\n let parentName = child.extendsQualified || child.extends;\n\n while (parentName && !seen.has(parentName)) {\n seen.add(parentName);\n const parent = findManifestObjectByName(manifest, parentName, child);\n if (!parent) return false;\n if (parent === ancestor) return true;\n child = parent;\n parentName = parent.extendsQualified || parent.extends;\n }\n\n return false;\n}\n\nconst CRUD_OPERATION_SET = new Set<string>(CRUD_OPERATIONS);\n\nfunction resolveGeneratedClientCustomMethods(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): ApiClientEntry['customMethods'] {\n const apiConfig = obj.decoratorConfig?.api;\n if (apiConfig === false) return [];\n\n const isCollection = isCollectionManifestClass(manifest, obj);\n if (\n isCollection &&\n resolveCollectionItemObject(manifest, obj)?.decoratorConfig?.abstract ===\n true\n ) {\n return [];\n }\n const isModelClassName = createManifestClassNamePredicate(manifest);\n\n return Object.entries(obj.methods ?? {}).flatMap(([name, method]) => {\n // The client's whole contract is \"methods whose routes the server actually\n // emits\", so it reads the SAME resolver the emitters do rather than its own\n // include/exclude copy. Before #2686 that copy was equivalent; once the\n // wire-ability gate and `@method()` joined the decision, a local copy would\n // hand callers a typed `client.assets.createNewVersion(...)` pointing at a\n // route that is no longer written.\n if (\n !resolveApiMethodExposure({\n actionName: name,\n method,\n apiConfig,\n isCollectionClass: isCollection,\n ...(isModelClassName ? { isModelClassName } : {}),\n }).exposed\n ) {\n return [];\n }\n\n const routeConfig = resolveApiActionRouteConfig(\n name,\n method,\n apiConfig,\n {},\n isCollection ? 'collection' : method.isStatic ? 'collection' : 'item',\n );\n\n return [\n {\n name,\n scope: routeConfig.scope,\n pathParamNames: routeConfig.pathParamNames,\n parameters: method.parameters ?? [],\n },\n ];\n });\n}\n\nfunction resolveCrudObject(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): SmartObjectDefinition | undefined {\n if (!isCollectionManifestClass(manifest, obj)) return obj;\n\n const itemObject = resolveCollectionItemObject(manifest, obj);\n if (itemObject) return itemObject;\n\n // A non-conventional collection can still share an endpoint with a model.\n // Iterating the deterministic qualified-identity order (#2754) gives this\n // fallback the same total tie-break as every other manifest consumer.\n return orderedManifestObjectEntries(manifest)\n .filter(\n ([, candidate]) =>\n candidate.collection === obj.collection &&\n !isCollectionManifestClass(manifest, candidate),\n )\n .map(([, candidate]) => candidate)[0];\n}\n\nfunction resolveGeneratedClientCrudMethods(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): ApiClientCrudMethod[] {\n const crudObject = resolveCrudObject(obj, manifest);\n const apiConfig = crudObject?.decoratorConfig?.api;\n if (!crudObject || apiConfig === false) return [];\n\n if (apiConfig === true || apiConfig === undefined) {\n return [...CRUD_OPERATIONS, 'search'];\n }\n if (typeof apiConfig !== 'object' || apiConfig === null) {\n return [...CRUD_OPERATIONS, 'search'];\n }\n\n const included = Array.isArray(apiConfig.include)\n ? apiConfig.include\n : undefined;\n const excluded = Array.isArray(apiConfig.exclude) ? apiConfig.exclude : [];\n const standardMethods = (\n included\n ? CRUD_OPERATIONS.filter((action) => included.includes(action))\n : [...CRUD_OPERATIONS]\n ).filter((action) => !excluded.includes(action));\n\n // Preserve the historical search convenience only for an unbounded API\n // config. Explicit include lists are fail-closed; a real custom search\n // method is carried separately by resolveGeneratedClientCustomMethods().\n const includeSearch = !included && !excluded.includes('search');\n return includeSearch ? [...standardMethods, 'search'] : standardMethods;\n}\n\n/**\n * Resolve the CRUD surface that the generated route files actually expose for\n * one shared collection endpoint.\n *\n * Route generation processes manifest objects in the deterministic\n * qualified-identity order of {@link orderedManifestObjectEntries} (#2754):\n * collection and item handlers live in separate files, and the last model\n * that emits each file replaces the earlier file. Mirror that behavior here\n * by iterating the same order, so every client alias for a shared endpoint\n * has the same, real action set regardless of manifest scan order.\n */\nfunction resolveGeneratedEndpointCrudMethods(\n collection: string,\n manifest: SmartObjectManifest,\n): ApiClientCrudMethod[] {\n let collectionMethods: ApiClientCrudMethod[] = [];\n let itemMethods: ApiClientCrudMethod[] = [];\n\n for (const [, obj] of orderedManifestObjectEntries(manifest)) {\n if (\n obj.collection !== collection ||\n isCollectionManifestClass(manifest, obj)\n ) {\n continue;\n }\n\n const methods = resolveGeneratedClientCrudMethods(obj, manifest);\n const emittedCollectionMethods = methods.filter((method) =>\n ['list', 'create', 'search'].includes(method),\n );\n const emittedItemMethods = methods.filter((method) =>\n ['get', 'update', 'delete'].includes(method),\n );\n\n // generateRoutesForObject only writes a route file when that file has at\n // least one standard handler. A custom-only object leaves an earlier CRUD\n // file intact rather than replacing it with an empty file.\n if (\n emittedCollectionMethods.some(\n (method) => method === 'list' || method === 'create',\n )\n ) {\n collectionMethods = emittedCollectionMethods;\n }\n if (emittedItemMethods.length > 0) {\n itemMethods = emittedItemMethods;\n }\n }\n\n const emitted = new Set([...collectionMethods, ...itemMethods]);\n const orderedMethods: ApiClientCrudMethod[] = [...CRUD_OPERATIONS, 'search'];\n return orderedMethods.filter((method) => emitted.has(method));\n}\n\nfunction exposesApiClientSurface(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): boolean {\n if (obj.decoratorConfig?.api === false) return false;\n if (resolveGeneratedClientCrudMethods(obj, manifest).length > 0) return true;\n\n // A disabled item has no CRUD routes. Keep its companion collection only\n // when the collection itself contributes a custom route that the SvelteKit\n // generator will actually emit.\n return resolveGeneratedClientCustomMethods(obj, manifest).length > 0;\n}\n\nfunction resolveDataInterfaceName(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): string {\n if (!isCollectionManifestClass(manifest, obj)) {\n return `${obj.className}Data`;\n }\n\n const itemObject = resolveCollectionItemObject(manifest, obj);\n return `${itemObject?.className || obj.className}Data`;\n}\n\nfunction sharedCollectionModelDepth(\n manifest: SmartObjectManifest,\n obj: SmartObjectDefinition,\n): number {\n const seen = new Set<string>();\n let depth = 0;\n let child = obj;\n let parentName = child.extendsQualified || child.extends;\n\n while (parentName && !seen.has(parentName)) {\n seen.add(parentName);\n const parent = findManifestObjectByName(manifest, parentName, child);\n if (!parent || parent.collection !== obj.collection) break;\n depth += 1;\n child = parent;\n parentName = parent.extendsQualified || parent.extends;\n }\n\n return depth;\n}\n\n/**\n * Select the owner of one canonical collection endpoint with a transitive rank.\n *\n * Models beat collection classes because CRUD payloads are rows. Among models,\n * shallower same-collection ancestry wins, then a root with more descendants\n * wins (the STI base over an unrelated endpoint collision), then qualified\n * identity resolves any remaining ambiguity. Numeric/lexical tuple ranks stay\n * transitive, unlike pairwise ancestry overrides inside Array.sort().\n */\nfunction selectCanonicalOwner(\n manifest: SmartObjectManifest,\n group: ManifestCandidate[],\n): ManifestCandidate | undefined {\n const models = group.filter(\n (candidate) => !isCollectionManifestClass(manifest, candidate.obj),\n );\n\n if (models.length > 0) {\n return [...models]\n .map((candidate) => ({\n candidate,\n depth: sharedCollectionModelDepth(manifest, candidate.obj),\n descendantCount: models.filter(\n (other) =>\n other !== candidate &&\n isAncestorOf(manifest, candidate.obj, other.obj),\n ).length,\n }))\n .sort(\n (left, right) =>\n left.depth - right.depth ||\n right.descendantCount - left.descendantCount ||\n compareCandidateIdentity(left.candidate, right.candidate),\n )[0]?.candidate;\n }\n\n return [...group].sort((left, right) => {\n const leftHasItem = resolveCollectionItemObject(manifest, left.obj);\n const rightHasItem = resolveCollectionItemObject(manifest, right.obj);\n if (Boolean(leftHasItem) !== Boolean(rightHasItem)) {\n return leftHasItem ? -1 : 1;\n }\n return compareCandidateIdentity(left, right);\n })[0];\n}\n\n/**\n * Select every generated client entry with deterministic endpoint keys and row\n * payload types. Exactly one entry owns each canonical collection key; other\n * API objects remain available under stable class-derived secondary keys.\n */\nexport function selectApiClientEntries(\n manifest: SmartObjectManifest,\n): ApiClientEntry[] {\n const candidates = Object.entries(manifest.objects)\n .filter(([, obj]) => exposesApiClientSurface(obj, manifest))\n .map(([objectName, obj]): ManifestCandidate => ({ objectName, obj }));\n const candidatesByCollection = new Map<string, ManifestCandidate[]>();\n\n for (const candidate of candidates) {\n const group = candidatesByCollection.get(candidate.obj.collection) ?? [];\n group.push(candidate);\n candidatesByCollection.set(candidate.obj.collection, group);\n }\n\n const canonicalOwners = new Map<string, ManifestCandidate>();\n for (const [collection, group] of candidatesByCollection) {\n const canonicalOwner = selectCanonicalOwner(manifest, group);\n if (canonicalOwner) canonicalOwners.set(collection, canonicalOwner);\n }\n\n // Canonical owners are emitted first within each collection. Sorting all\n // remaining candidates by identity makes numeric suffixes stable too.\n const orderedCandidates = [...candidates].sort((left, right) => {\n const collectionOrder = compareText(\n left.obj.collection,\n right.obj.collection,\n );\n if (collectionOrder !== 0) return collectionOrder;\n\n const leftIsCanonical = canonicalOwners.get(left.obj.collection) === left;\n const rightIsCanonical =\n canonicalOwners.get(right.obj.collection) === right;\n if (leftIsCanonical !== rightIsCanonical) {\n return leftIsCanonical ? -1 : 1;\n }\n\n return compareCandidateIdentity(left, right);\n });\n\n // A secondary key must never shadow any canonical endpoint, including a\n // later collection whose canonical owner has not been emitted yet.\n const reservedCanonicalKeys = new Set(canonicalOwners.keys());\n const usedKeys = new Set<string>();\n\n return orderedCandidates.map(({ objectName, obj }) => {\n const isCanonicalOwner =\n canonicalOwners.get(obj.collection)?.objectName === objectName;\n let clientKey = isCanonicalOwner\n ? obj.collection\n : lowerFirst(obj.className);\n const baseClientKey = clientKey;\n let suffix = 2;\n\n while (\n usedKeys.has(clientKey) ||\n (!isCanonicalOwner && reservedCanonicalKeys.has(clientKey))\n ) {\n clientKey = `${baseClientKey}${suffix}`;\n suffix += 1;\n }\n\n usedKeys.add(clientKey);\n return {\n objectName,\n obj,\n clientKey,\n dataInterfaceName: resolveDataInterfaceName(obj, manifest),\n crudMethods: resolveGeneratedEndpointCrudMethods(\n obj.collection,\n manifest,\n ),\n customMethods: resolveGeneratedClientCustomMethods(obj, manifest),\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;AA2DA,SAAgB,wBACd,mBACA,aACA,oBAA8B,CAAC,GACX;CACpB,MAAM,aAAa,IAAI,IAAI,iBAAiB;CAC5C,MAAM,UAAU,YAAY,QAAQ,WAAW,CAAC,WAAW,IAAI,MAAM,CAAC;CACtE,IAAI,QAAQ,WAAW,GAAG,OAAO,KAAA;CACjC,IACE,QAAQ,WAAW,KACnB,QAAQ,OACL,QAAQ,UAAU,WAAW,CAAC,GAAG,iBAAiB,QAAQ,CAAC,CAAC,MAC/D,GAEA,OAAO,kBAAkB,kBAAkB;CAE7C,OAAO,uBAAuB,kBAAkB,KAAK,QAClD,KAAK,WAAW,KAAK,UAAU,MAAM,CAAC,CAAC,CACvC,KAAK,KAAK,EAAE;AACjB;AAEA,SAAgB,sCACd,QACA,SACQ;CACR,MAAM,iBAAiB,IAAI,IAAI,OAAO,cAAc;CACpD,MAAM,SAAS,OAAO;CACtB,MAAM,4BACJ,OAAO,WAAW,KAAK,OAAO,EAAE,EAAE,SAAS;CAC7C,MAAM,yBAAyB,OAAO,eACnC,KAAK,SAAS,GAAG,KAAK,SAAS,CAAC,CAChC,KAAK,IAAI;CACZ,IAAI;CAEJ,IAAI,2BAA2B;EAC7B,MAAM,oBAAoB,QAAQ,OAAO,EAAE,CAAC,IAAI;EAChD,cAAc,yBACV,GAAG,kBAAkB,OAAO,uBAAuB,MACnD;CACN,OAAO;EACL,MAAM,iBAAiB,IAAI,IAAI,OAAO,KAAK,UAAU,MAAM,IAAI,CAAC;EAChE,MAAM,aAAa,OAAO,KACvB,UACC,GAAG,MAAM,OAAO,eAAe,IAAI,MAAM,IAAI,KAAK,CAAC,MAAM,WAAW,KAAK,IAAI,IAAI,QAAQ,MAAM,IAAI,GACvG;EACA,KAAK,MAAM,iBAAiB,OAAO,gBACjC,IAAI,CAAC,eAAe,IAAI,aAAa,GACnC,WAAW,KAAK,GAAG,cAAc,SAAS;EAG9C,cACE,WAAW,SAAS,IAChB,KAAK,WAAW,KAAK,IAAI,EAAE,MAC3B;CACR;CAEA,MAAM,qBAAqB,4BACvB,CAAC,OAAO,EAAE,EAAE,WACZ,OAAO,MACJ,UAAU,CAAC,eAAe,IAAI,MAAM,IAAI,KAAK,CAAC,MAAM,QACvD;CACJ,MAAM,mBAAmB,GAAG,OAAO,eAAe,SAAS,KAAK,qBAAqB,YAAY,WAAW,IAAI;CAChH,OAAO,OAAO,UAAU,eACpB,mBACA,eAAe;AACrB;AAOA,SAAS,YAAY,MAAc,OAAuB;CACxD,IAAI,OAAO,OAAO,OAAO;CACzB,IAAI,OAAO,OAAO,OAAO;CACzB,OAAO;AACT;AAEA,SAAS,kBAAkB,WAAsC;CAC/D,OAAO;EACL,UAAU,IAAI,iBAAiB;EAC/B,UAAU,IAAI;EACd,UAAU;CACZ,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,yBACP,MACA,OACQ;CACR,OAAO,YAAY,kBAAkB,IAAI,GAAG,kBAAkB,KAAK,CAAC;AACtE;AAEA,SAAS,WAAW,OAAuB;CACzC,OAAO,QAAQ,MAAM,EAAE,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC,IAAI;AAC3D;AAEA,SAAS,aACP,UACA,UACA,YACS;CACT,MAAM,uBAAO,IAAI,IAAY;CAC7B,IAAI,QAAQ;CACZ,IAAI,aAAa,MAAM,oBAAoB,MAAM;CAEjD,OAAO,cAAc,CAAC,KAAK,IAAI,UAAU,GAAG;EAC1C,KAAK,IAAI,UAAU;EACnB,MAAM,SAAS,yBAAyB,UAAU,YAAY,KAAK;EACnE,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,WAAW,UAAU,OAAO;EAChC,QAAQ;EACR,aAAa,OAAO,oBAAoB,OAAO;CACjD;CAEA,OAAO;AACT;AAE2B,IAAI,IAAY,eAAe;AAE1D,SAAS,oCACP,KACA,UACiC;CACjC,MAAM,YAAY,IAAI,iBAAiB;CACvC,IAAI,cAAc,OAAO,OAAO,CAAC;CAEjC,MAAM,eAAe,0BAA0B,UAAU,GAAG;CAC5D,IACE,gBACA,4BAA4B,UAAU,GAAG,CAAC,EAAE,iBAAiB,aAC3D,MAEF,OAAO,CAAC;CAEV,MAAM,mBAAmB,iCAAiC,QAAQ;CAElE,OAAO,OAAO,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,YAAY;EAOnE,IACE,CAAC,yBAAyB;GACxB,YAAY;GACZ;GACA;GACA,mBAAmB;GACnB,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;EACjD,CAAC,CAAC,CAAC,SAEH,OAAO,CAAC;EAGV,MAAM,cAAc,4BAClB,MACA,QACA,WACA,CAAC,GACD,eAAe,eAAe,OAAO,WAAW,eAAe,MACjE;EAEA,OAAO,CACL;GACE;GACA,OAAO,YAAY;GACnB,gBAAgB,YAAY;GAC5B,YAAY,OAAO,cAAc,CAAC;EACpC,CACF;CACF,CAAC;AACH;AAEA,SAAS,kBACP,KACA,UACmC;CACnC,IAAI,CAAC,0BAA0B,UAAU,GAAG,GAAG,OAAO;CAEtD,MAAM,aAAa,4BAA4B,UAAU,GAAG;CAC5D,IAAI,YAAY,OAAO;CAKvB,OAAO,6BAA6B,QAAQ,CAAC,CAC1C,QACE,GAAG,eACF,UAAU,eAAe,IAAI,cAC7B,CAAC,0BAA0B,UAAU,SAAS,CAClD,CAAC,CACA,KAAK,GAAG,eAAe,SAAS,CAAC,CAAC;AACvC;AAEA,SAAS,kCACP,KACA,UACuB;CACvB,MAAM,aAAa,kBAAkB,KAAK,QAAQ;CAClD,MAAM,YAAY,YAAY,iBAAiB;CAC/C,IAAI,CAAC,cAAc,cAAc,OAAO,OAAO,CAAC;CAEhD,IAAI,cAAc,QAAQ,cAAc,KAAA,GACtC,OAAO,CAAC,GAAG,iBAAiB,QAAQ;CAEtC,IAAI,OAAO,cAAc,YAAY,cAAc,MACjD,OAAO,CAAC,GAAG,iBAAiB,QAAQ;CAGtC,MAAM,WAAW,MAAM,QAAQ,UAAU,OAAO,IAC5C,UAAU,UACV,KAAA;CACJ,MAAM,WAAW,MAAM,QAAQ,UAAU,OAAO,IAAI,UAAU,UAAU,CAAC;CACzE,MAAM,mBACJ,WACI,gBAAgB,QAAQ,WAAW,SAAS,SAAS,MAAM,CAAC,IAC5D,CAAC,GAAG,eAAe,EAAA,CACvB,QAAQ,WAAW,CAAC,SAAS,SAAS,MAAM,CAAC;CAM/C,OADsB,CAAC,YAAY,CAAC,SAAS,SAAS,QAAQ,IACvC,CAAC,GAAG,iBAAiB,QAAQ,IAAI;AAC1D;;;;;;;;;;;;AAaA,SAAS,oCACP,YACA,UACuB;CACvB,IAAI,oBAA2C,CAAC;CAChD,IAAI,cAAqC,CAAC;CAE1C,KAAK,MAAM,GAAG,QAAQ,6BAA6B,QAAQ,GAAG;EAC5D,IACE,IAAI,eAAe,cACnB,0BAA0B,UAAU,GAAG,GAEvC;EAGF,MAAM,UAAU,kCAAkC,KAAK,QAAQ;EAC/D,MAAM,2BAA2B,QAAQ,QAAQ,WAC/C;GAAC;GAAQ;GAAU;EAAQ,CAAC,CAAC,SAAS,MAAM,CAC9C;EACA,MAAM,qBAAqB,QAAQ,QAAQ,WACzC;GAAC;GAAO;GAAU;EAAQ,CAAC,CAAC,SAAS,MAAM,CAC7C;EAKA,IACE,yBAAyB,MACtB,WAAW,WAAW,UAAU,WAAW,QAC9C,GAEA,oBAAoB;EAEtB,IAAI,mBAAmB,SAAS,GAC9B,cAAc;CAElB;CAEA,MAAM,0BAAU,IAAI,IAAI,CAAC,GAAG,mBAAmB,GAAG,WAAW,CAAC;CAE9D,OAAO,CADwC,GAAG,iBAAiB,QAC5D,CAAA,CAAe,QAAQ,WAAW,QAAQ,IAAI,MAAM,CAAC;AAC9D;AAEA,SAAS,wBACP,KACA,UACS;CACT,IAAI,IAAI,iBAAiB,QAAQ,OAAO,OAAO;CAC/C,IAAI,kCAAkC,KAAK,QAAQ,CAAC,CAAC,SAAS,GAAG,OAAO;CAKxE,OAAO,oCAAoC,KAAK,QAAQ,CAAC,CAAC,SAAS;AACrE;AAEA,SAAS,yBACP,KACA,UACQ;CACR,IAAI,CAAC,0BAA0B,UAAU,GAAG,GAC1C,OAAO,GAAG,IAAI,UAAU;CAI1B,OAAO,GADY,4BAA4B,UAAU,GAC/C,CAAA,EAAY,aAAa,IAAI,UAAU;AACnD;AAEA,SAAS,2BACP,UACA,KACQ;CACR,MAAM,uBAAO,IAAI,IAAY;CAC7B,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,aAAa,MAAM,oBAAoB,MAAM;CAEjD,OAAO,cAAc,CAAC,KAAK,IAAI,UAAU,GAAG;EAC1C,KAAK,IAAI,UAAU;EACnB,MAAM,SAAS,yBAAyB,UAAU,YAAY,KAAK;EACnE,IAAI,CAAC,UAAU,OAAO,eAAe,IAAI,YAAY;EACrD,SAAS;EACT,QAAQ;EACR,aAAa,OAAO,oBAAoB,OAAO;CACjD;CAEA,OAAO;AACT;;;;;;;;;;AAWA,SAAS,qBACP,UACA,OAC+B;CAC/B,MAAM,SAAS,MAAM,QAClB,cAAc,CAAC,0BAA0B,UAAU,UAAU,GAAG,CACnE;CAEA,IAAI,OAAO,SAAS,GAClB,OAAO,CAAC,GAAG,MAAM,CAAC,CACf,KAAK,eAAe;EACnB;EACA,OAAO,2BAA2B,UAAU,UAAU,GAAG;EACzD,iBAAiB,OAAO,QACrB,UACC,UAAU,aACV,aAAa,UAAU,UAAU,KAAK,MAAM,GAAG,CACnD,CAAC,CAAC;CACJ,EAAE,CAAC,CACF,MACE,MAAM,UACL,KAAK,QAAQ,MAAM,SACnB,MAAM,kBAAkB,KAAK,mBAC7B,yBAAyB,KAAK,WAAW,MAAM,SAAS,CAC5D,CAAC,CAAC,EAAE,EAAE;CAGV,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,MAAM,UAAU;EACtC,MAAM,cAAc,4BAA4B,UAAU,KAAK,GAAG;EAClE,MAAM,eAAe,4BAA4B,UAAU,MAAM,GAAG;EACpE,IAAI,QAAQ,WAAW,MAAM,QAAQ,YAAY,GAC/C,OAAO,cAAc,KAAK;EAE5B,OAAO,yBAAyB,MAAM,KAAK;CAC7C,CAAC,CAAC,CAAC;AACL;;;;;;AAOA,SAAgB,uBACd,UACkB;CAClB,MAAM,aAAa,OAAO,QAAQ,SAAS,OAAO,CAAC,CAChD,QAAQ,GAAG,SAAS,wBAAwB,KAAK,QAAQ,CAAC,CAAC,CAC3D,KAAK,CAAC,YAAY,UAA6B;EAAE;EAAY;CAAI,EAAE;CACtE,MAAM,yCAAyB,IAAI,IAAiC;CAEpE,KAAK,MAAM,aAAa,YAAY;EAClC,MAAM,QAAQ,uBAAuB,IAAI,UAAU,IAAI,UAAU,KAAK,CAAC;EACvE,MAAM,KAAK,SAAS;EACpB,uBAAuB,IAAI,UAAU,IAAI,YAAY,KAAK;CAC5D;CAEA,MAAM,kCAAkB,IAAI,IAA+B;CAC3D,KAAK,MAAM,CAAC,YAAY,UAAU,wBAAwB;EACxD,MAAM,iBAAiB,qBAAqB,UAAU,KAAK;EAC3D,IAAI,gBAAgB,gBAAgB,IAAI,YAAY,cAAc;CACpE;CAIA,MAAM,oBAAoB,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,MAAM,UAAU;EAC9D,MAAM,kBAAkB,YACtB,KAAK,IAAI,YACT,MAAM,IAAI,UACZ;EACA,IAAI,oBAAoB,GAAG,OAAO;EAElC,MAAM,kBAAkB,gBAAgB,IAAI,KAAK,IAAI,UAAU,MAAM;EAGrE,IAAI,qBADF,gBAAgB,IAAI,MAAM,IAAI,UAAU,MAAM,QAE9C,OAAO,kBAAkB,KAAK;EAGhC,OAAO,yBAAyB,MAAM,KAAK;CAC7C,CAAC;CAID,MAAM,wBAAwB,IAAI,IAAI,gBAAgB,KAAK,CAAC;CAC5D,MAAM,2BAAW,IAAI,IAAY;CAEjC,OAAO,kBAAkB,KAAK,EAAE,YAAY,UAAU;EACpD,MAAM,mBACJ,gBAAgB,IAAI,IAAI,UAAU,CAAC,EAAE,eAAe;EACtD,IAAI,YAAY,mBACZ,IAAI,aACJ,WAAW,IAAI,SAAS;EAC5B,MAAM,gBAAgB;EACtB,IAAI,SAAS;EAEb,OACE,SAAS,IAAI,SAAS,KACrB,CAAC,oBAAoB,sBAAsB,IAAI,SAAS,GACzD;GACA,YAAY,GAAG,gBAAgB;GAC/B,UAAU;EACZ;EAEA,SAAS,IAAI,SAAS;EACtB,OAAO;GACL;GACA;GACA;GACA,mBAAmB,yBAAyB,KAAK,QAAQ;GACzD,aAAa,oCACX,IAAI,YACJ,QACF;GACA,eAAe,oCAAoC,KAAK,QAAQ;EAClE;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"api-client-entries.js","names":[],"sources":["../../src/vite-plugin/api-client-entries.ts"],"sourcesContent":["/**\n * Manifest -> generated API-client entry selection.\n *\n * Runtime client values, Vite ambient declarations, and physical prebuild\n * declarations must agree on which manifest object owns a collection's\n * canonical endpoint. Collection classes describe access methods, not row\n * payloads, so a populated model always wins the shared collection key.\n */\n\nimport {\n CRUD_OPERATIONS,\n createManifestClassNamePredicate,\n resolveApiMethodExposure,\n} from '../generators/custom-action.js';\nimport {\n createObjectDeclarationIndex,\n type ObjectDeclarationIndex,\n} from '../manifest/object-declarations.js';\nimport { isFrameworkBaseClass } from '../registry/framework-base-classes.js';\nimport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types.js';\nimport { resolveApiActionRouteConfig } from './sveltekit-generator.js';\nimport {\n findManifestObjectByName,\n isCollectionManifestClass,\n orderedManifestObjectEntries,\n resolveCollectionItemObject,\n} from './web-collections.js';\n\nexport type ApiClientCrudMethod =\n | 'list'\n | 'get'\n | 'create'\n | 'update'\n | 'delete'\n | 'search';\n\nexport interface ApiClientEntry {\n /** Original key in manifest.objects. */\n objectName: string;\n /** Object whose routes and custom methods this client entry exposes. */\n obj: SmartObjectDefinition;\n /** Canonical collection key or deterministic class-derived secondary key. */\n clientKey: string;\n /**\n * Row-payload interface used by CRUD methods for this entry: the declared\n * name from the shared declaration selection (package-qualified when\n * distinct classes share a simple name, #3115).\n */\n dataInterfaceName: string;\n /** Standard client operations whose server routes are actually emitted. */\n crudMethods: ApiClientCrudMethod[];\n /** Custom methods whose routes are actually emitted by the server. */\n customMethods: Array<{\n name: string;\n scope: 'item' | 'collection';\n pathParamNames: string[];\n parameters: Array<{\n name: string;\n type: string;\n optional?: boolean;\n default?: unknown;\n }>;\n }>;\n}\n\nexport function renderApiClientCrudType(\n dataInterfaceName: string,\n crudMethods: ApiClientCrudMethod[],\n overriddenMethods: string[] = [],\n): string | undefined {\n const overridden = new Set(overriddenMethods);\n const methods = crudMethods.filter((method) => !overridden.has(method));\n if (methods.length === 0) return undefined;\n if (\n methods.length === 6 &&\n methods.every(\n (method, index) => method === [...CRUD_OPERATIONS, 'search'][index],\n )\n ) {\n return `CrudOperations<${dataInterfaceName}>`;\n }\n return `Pick<CrudOperations<${dataInterfaceName}>, ${methods\n .map((method) => JSON.stringify(method))\n .join(' | ')}>`;\n}\n\nexport function renderApiClientCustomMethodParameters(\n method: ApiClientEntry['customMethods'][number],\n mapType: (type: string) => string,\n): string {\n const pathParamNames = new Set(method.pathParamNames);\n const params = method.parameters;\n const hasSingleOptionsParameter =\n params.length === 1 && params[0]?.name === 'options';\n const requiredPathProperties = method.pathParamNames\n .map((name) => `${name}: string`)\n .join('; ');\n let optionsType: string;\n\n if (hasSingleOptionsParameter) {\n const directOptionsType = mapType(params[0].type);\n optionsType = requiredPathProperties\n ? `${directOptionsType} & { ${requiredPathProperties} }`\n : directOptionsType;\n } else {\n const parameterNames = new Set(params.map((param) => param.name));\n const properties = params.map(\n (param) =>\n `${param.name}${pathParamNames.has(param.name) || !param.optional ? '' : '?'}: ${mapType(param.type)}`,\n );\n for (const pathParamName of method.pathParamNames) {\n if (!parameterNames.has(pathParamName)) {\n properties.push(`${pathParamName}: string`);\n }\n }\n optionsType =\n properties.length > 0\n ? `{ ${properties.join('; ')} }`\n : 'Record<string, never>';\n }\n\n const hasRequiredOptions = hasSingleOptionsParameter\n ? !params[0]?.optional\n : params.some(\n (param) => !pathParamNames.has(param.name) && !param.optional,\n );\n const optionsParameter = `${method.pathParamNames.length > 0 || hasRequiredOptions ? 'options' : 'options?'}: ${optionsType}`;\n return method.scope === 'collection'\n ? optionsParameter\n : `id: string, ${optionsParameter}`;\n}\n\ninterface ManifestCandidate {\n objectName: string;\n obj: SmartObjectDefinition;\n}\n\nfunction compareText(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction candidateIdentity(candidate: ManifestCandidate): string {\n return [\n candidate.obj.qualifiedName ?? '',\n candidate.obj.className,\n candidate.objectName,\n ].join('\\0');\n}\n\nfunction compareCandidateIdentity(\n left: ManifestCandidate,\n right: ManifestCandidate,\n): number {\n return compareText(candidateIdentity(left), candidateIdentity(right));\n}\n\nfunction lowerFirst(value: string): string {\n return value ? value[0].toLowerCase() + value.slice(1) : value;\n}\n\nfunction isAncestorOf(\n manifest: SmartObjectManifest,\n ancestor: SmartObjectDefinition,\n descendant: SmartObjectDefinition,\n): boolean {\n const seen = new Set<string>();\n let child = descendant;\n let parentName = child.extendsQualified || child.extends;\n\n while (parentName && !seen.has(parentName)) {\n seen.add(parentName);\n const parent = findManifestObjectByName(manifest, parentName, child);\n if (!parent) return false;\n if (parent === ancestor) return true;\n child = parent;\n parentName = parent.extendsQualified || parent.extends;\n }\n\n return false;\n}\n\nconst CRUD_OPERATION_SET = new Set<string>(CRUD_OPERATIONS);\n\nfunction resolveGeneratedClientCustomMethods(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): ApiClientEntry['customMethods'] {\n const apiConfig = obj.decoratorConfig?.api;\n if (apiConfig === false) return [];\n\n const isCollection = isCollectionManifestClass(manifest, obj);\n if (\n isCollection &&\n resolveCollectionItemObject(manifest, obj)?.decoratorConfig?.abstract ===\n true\n ) {\n return [];\n }\n const isModelClassName = createManifestClassNamePredicate(manifest);\n\n return Object.entries(obj.methods ?? {}).flatMap(([name, method]) => {\n // The client's whole contract is \"methods whose routes the server actually\n // emits\", so it reads the SAME resolver the emitters do rather than its own\n // include/exclude copy. Before #2686 that copy was equivalent; once the\n // wire-ability gate and `@method()` joined the decision, a local copy would\n // hand callers a typed `client.assets.createNewVersion(...)` pointing at a\n // route that is no longer written.\n if (\n !resolveApiMethodExposure({\n actionName: name,\n method,\n apiConfig,\n isCollectionClass: isCollection,\n ...(isModelClassName ? { isModelClassName } : {}),\n }).exposed\n ) {\n return [];\n }\n\n const routeConfig = resolveApiActionRouteConfig(\n name,\n method,\n apiConfig,\n {},\n isCollection ? 'collection' : method.isStatic ? 'collection' : 'item',\n );\n\n return [\n {\n name,\n scope: routeConfig.scope,\n pathParamNames: routeConfig.pathParamNames,\n parameters: method.parameters ?? [],\n },\n ];\n });\n}\n\nfunction resolveCrudObject(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): SmartObjectDefinition | undefined {\n if (!isCollectionManifestClass(manifest, obj)) return obj;\n\n const itemObject = resolveCollectionItemObject(manifest, obj);\n if (itemObject) return itemObject;\n\n // A non-conventional collection can still share an endpoint with a model.\n // Iterating the deterministic qualified-identity order (#2754) gives this\n // fallback the same total tie-break as every other manifest consumer.\n return orderedManifestObjectEntries(manifest)\n .filter(\n ([, candidate]) =>\n candidate.collection === obj.collection &&\n !isFrameworkBaseClass(candidate.className, candidate.packageName) &&\n !isCollectionManifestClass(manifest, candidate),\n )\n .map(([, candidate]) => candidate)[0];\n}\n\nfunction resolveGeneratedClientCrudMethods(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): ApiClientCrudMethod[] {\n const crudObject = resolveCrudObject(obj, manifest);\n const apiConfig = crudObject?.decoratorConfig?.api;\n if (!crudObject || apiConfig === false) return [];\n\n if (apiConfig === true || apiConfig === undefined) {\n return [...CRUD_OPERATIONS, 'search'];\n }\n if (typeof apiConfig !== 'object' || apiConfig === null) {\n return [...CRUD_OPERATIONS, 'search'];\n }\n\n const included = Array.isArray(apiConfig.include)\n ? apiConfig.include\n : undefined;\n const excluded = Array.isArray(apiConfig.exclude) ? apiConfig.exclude : [];\n const standardMethods = (\n included\n ? CRUD_OPERATIONS.filter((action) => included.includes(action))\n : [...CRUD_OPERATIONS]\n ).filter((action) => !excluded.includes(action));\n\n // Preserve the historical search convenience only for an unbounded API\n // config. Explicit include lists are fail-closed; a real custom search\n // method is carried separately by resolveGeneratedClientCustomMethods().\n const includeSearch = !included && !excluded.includes('search');\n return includeSearch ? [...standardMethods, 'search'] : standardMethods;\n}\n\n/**\n * Resolve the CRUD surface that the generated route files actually expose for\n * one shared collection endpoint.\n *\n * Route generation processes manifest objects in the deterministic\n * qualified-identity order of {@link orderedManifestObjectEntries} (#2754):\n * collection and item handlers live in separate files, and the last model\n * that emits each file replaces the earlier file. Mirror that behavior here\n * by iterating the same order, so every client alias for a shared endpoint\n * has the same, real action set regardless of manifest scan order.\n */\nfunction resolveGeneratedEndpointCrudMethods(\n collection: string,\n manifest: SmartObjectManifest,\n): ApiClientCrudMethod[] {\n let collectionMethods: ApiClientCrudMethod[] = [];\n let itemMethods: ApiClientCrudMethod[] = [];\n\n for (const [, obj] of orderedManifestObjectEntries(manifest)) {\n if (\n obj.collection !== collection ||\n isFrameworkBaseClass(obj.className, obj.packageName) ||\n isCollectionManifestClass(manifest, obj)\n ) {\n continue;\n }\n\n const methods = resolveGeneratedClientCrudMethods(obj, manifest);\n const emittedCollectionMethods = methods.filter((method) =>\n ['list', 'create', 'search'].includes(method),\n );\n const emittedItemMethods = methods.filter((method) =>\n ['get', 'update', 'delete'].includes(method),\n );\n\n // generateRoutesForObject only writes a route file when that file has at\n // least one standard handler. A custom-only object leaves an earlier CRUD\n // file intact rather than replacing it with an empty file.\n if (\n emittedCollectionMethods.some(\n (method) => method === 'list' || method === 'create',\n )\n ) {\n collectionMethods = emittedCollectionMethods;\n }\n if (emittedItemMethods.length > 0) {\n itemMethods = emittedItemMethods;\n }\n }\n\n const emitted = new Set([...collectionMethods, ...itemMethods]);\n const orderedMethods: ApiClientCrudMethod[] = [...CRUD_OPERATIONS, 'search'];\n return orderedMethods.filter((method) => emitted.has(method));\n}\n\nfunction exposesApiClientSurface(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n): boolean {\n // The framework's own base classes (SmrtObject, SmrtCollection, ...) are\n // scaffolding: the route generator never emits a route directory for them\n // (#2642), so the client must not advertise their CRUD or their methods,\n // static helpers included, as callable actions (#3295). A consumer that\n // aggregates `@happyvertical/smrt-core` receives them in its manifest.\n if (isFrameworkBaseClass(obj.className, obj.packageName)) return false;\n if (obj.decoratorConfig?.api === false) return false;\n if (resolveGeneratedClientCrudMethods(obj, manifest).length > 0) return true;\n\n // A disabled item has no CRUD routes. Keep its companion collection only\n // when the collection itself contributes a custom route that the SvelteKit\n // generator will actually emit.\n return resolveGeneratedClientCustomMethods(obj, manifest).length > 0;\n}\n\nfunction resolveDataInterfaceName(\n obj: SmartObjectDefinition,\n manifest: SmartObjectManifest,\n declarations: ObjectDeclarationIndex,\n): string {\n if (!isCollectionManifestClass(manifest, obj)) {\n return declarations.interfaceNameFor(obj);\n }\n\n const itemObject = resolveCollectionItemObject(manifest, obj);\n return declarations.interfaceNameFor(itemObject ?? obj);\n}\n\nfunction sharedCollectionModelDepth(\n manifest: SmartObjectManifest,\n obj: SmartObjectDefinition,\n): number {\n const seen = new Set<string>();\n let depth = 0;\n let child = obj;\n let parentName = child.extendsQualified || child.extends;\n\n while (parentName && !seen.has(parentName)) {\n seen.add(parentName);\n const parent = findManifestObjectByName(manifest, parentName, child);\n if (!parent || parent.collection !== obj.collection) break;\n depth += 1;\n child = parent;\n parentName = parent.extendsQualified || parent.extends;\n }\n\n return depth;\n}\n\n/**\n * Select the owner of one canonical collection endpoint with a transitive rank.\n *\n * Models beat collection classes because CRUD payloads are rows. Among models,\n * shallower same-collection ancestry wins, then a root with more descendants\n * wins (the STI base over an unrelated endpoint collision), then qualified\n * identity resolves any remaining ambiguity. Numeric/lexical tuple ranks stay\n * transitive, unlike pairwise ancestry overrides inside Array.sort().\n */\nfunction selectCanonicalOwner(\n manifest: SmartObjectManifest,\n group: ManifestCandidate[],\n): ManifestCandidate | undefined {\n const models = group.filter(\n (candidate) => !isCollectionManifestClass(manifest, candidate.obj),\n );\n\n if (models.length > 0) {\n return [...models]\n .map((candidate) => ({\n candidate,\n depth: sharedCollectionModelDepth(manifest, candidate.obj),\n descendantCount: models.filter(\n (other) =>\n other !== candidate &&\n isAncestorOf(manifest, candidate.obj, other.obj),\n ).length,\n }))\n .sort(\n (left, right) =>\n left.depth - right.depth ||\n right.descendantCount - left.descendantCount ||\n compareCandidateIdentity(left.candidate, right.candidate),\n )[0]?.candidate;\n }\n\n return [...group].sort((left, right) => {\n const leftHasItem = resolveCollectionItemObject(manifest, left.obj);\n const rightHasItem = resolveCollectionItemObject(manifest, right.obj);\n if (Boolean(leftHasItem) !== Boolean(rightHasItem)) {\n return leftHasItem ? -1 : 1;\n }\n return compareCandidateIdentity(left, right);\n })[0];\n}\n\n/**\n * Select every generated client entry with deterministic endpoint keys and row\n * payload types. Exactly one entry owns each canonical collection key; other\n * API objects remain available under stable class-derived secondary keys.\n */\nexport function selectApiClientEntries(\n manifest: SmartObjectManifest,\n): ApiClientEntry[] {\n const candidates = Object.entries(manifest.objects)\n .filter(([, obj]) => exposesApiClientSurface(obj, manifest))\n .map(([objectName, obj]): ManifestCandidate => ({ objectName, obj }));\n const candidatesByCollection = new Map<string, ManifestCandidate[]>();\n\n for (const candidate of candidates) {\n const group = candidatesByCollection.get(candidate.obj.collection) ?? [];\n group.push(candidate);\n candidatesByCollection.set(candidate.obj.collection, group);\n }\n\n const canonicalOwners = new Map<string, ManifestCandidate>();\n for (const [collection, group] of candidatesByCollection) {\n const canonicalOwner = selectCanonicalOwner(manifest, group);\n if (canonicalOwner) canonicalOwners.set(collection, canonicalOwner);\n }\n\n // Canonical owners are emitted first within each collection. Sorting all\n // remaining candidates by identity makes numeric suffixes stable too.\n const orderedCandidates = [...candidates].sort((left, right) => {\n const collectionOrder = compareText(\n left.obj.collection,\n right.obj.collection,\n );\n if (collectionOrder !== 0) return collectionOrder;\n\n const leftIsCanonical = canonicalOwners.get(left.obj.collection) === left;\n const rightIsCanonical =\n canonicalOwners.get(right.obj.collection) === right;\n if (leftIsCanonical !== rightIsCanonical) {\n return leftIsCanonical ? -1 : 1;\n }\n\n return compareCandidateIdentity(left, right);\n });\n\n // A secondary key must never shadow any canonical endpoint, including a\n // later collection whose canonical owner has not been emitted yet.\n const reservedCanonicalKeys = new Set(canonicalOwners.keys());\n const declarations = createObjectDeclarationIndex(manifest);\n const usedKeys = new Set<string>();\n\n return orderedCandidates.map(({ objectName, obj }) => {\n const isCanonicalOwner =\n canonicalOwners.get(obj.collection)?.objectName === objectName;\n let clientKey = isCanonicalOwner\n ? obj.collection\n : lowerFirst(obj.className);\n const baseClientKey = clientKey;\n let suffix = 2;\n\n while (\n usedKeys.has(clientKey) ||\n (!isCanonicalOwner && reservedCanonicalKeys.has(clientKey))\n ) {\n clientKey = `${baseClientKey}${suffix}`;\n suffix += 1;\n }\n\n usedKeys.add(clientKey);\n return {\n objectName,\n obj,\n clientKey,\n dataInterfaceName: resolveDataInterfaceName(obj, manifest, declarations),\n crudMethods: resolveGeneratedEndpointCrudMethods(\n obj.collection,\n manifest,\n ),\n customMethods: resolveGeneratedClientCustomMethods(obj, manifest),\n };\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer-relative ESM resolution for generated-route dependencies (#3913).
|
|
3
|
+
*
|
|
4
|
+
* Generated SvelteKit files are written into the consumer's own `src/`, and
|
|
5
|
+
* some of them import a package that core itself cannot depend on
|
|
6
|
+
* (`@happyvertical/smrt-users/sveltekit`, `@happyvertical/smrt-app-runtime/
|
|
7
|
+
* sveltekit`, `@happyvertical/smrt-dev-mcp/dev-plane`). The generator emits
|
|
8
|
+
* such a file only when that exact specifier would resolve in the consumer's
|
|
9
|
+
* build, so this check must answer the question Vite/SvelteKit will ask:
|
|
10
|
+
*
|
|
11
|
+
* - **ESM import conditions.** Published subpaths may expose only `types` and
|
|
12
|
+
* `import`. A CommonJS `createRequire(...).resolve` probe uses `require`
|
|
13
|
+
* conditions, throws `ERR_PACKAGE_PATH_NOT_EXPORTED` for such a subpath,
|
|
14
|
+
* and would falsely skip a correctly installed dependency.
|
|
15
|
+
* - **Anchored to the consumer.** Resolution starts from the consumer's
|
|
16
|
+
* `package.json` URL, so it walks the consumer's own `node_modules` and any
|
|
17
|
+
* hoisted ancestor `node_modules` — never core's install location.
|
|
18
|
+
* - **Existing file target.** ESM resolution can return a URL for a target
|
|
19
|
+
* that does not exist (or is a directory), so the target must be a file.
|
|
20
|
+
*
|
|
21
|
+
* Do not change a package's export map to accommodate a mismatched detector.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Whether `specifier` resolves from the consumer at `projectRoot` under ESM
|
|
25
|
+
* import conditions to an existing file.
|
|
26
|
+
*/
|
|
27
|
+
export declare function consumerResolvesImport(projectRoot: string, specifier: string): boolean;
|
|
28
|
+
//# sourceMappingURL=consumer-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumer-import.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/consumer-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAUT"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
+
import { resolve as resolve$1 } from "import-meta-resolve";
|
|
4
|
+
import { statSync } from "node:fs";
|
|
5
|
+
//#region src/vite-plugin/consumer-import.ts
|
|
6
|
+
/**
|
|
7
|
+
* Consumer-relative ESM resolution for generated-route dependencies (#3913).
|
|
8
|
+
*
|
|
9
|
+
* Generated SvelteKit files are written into the consumer's own `src/`, and
|
|
10
|
+
* some of them import a package that core itself cannot depend on
|
|
11
|
+
* (`@happyvertical/smrt-users/sveltekit`, `@happyvertical/smrt-app-runtime/
|
|
12
|
+
* sveltekit`, `@happyvertical/smrt-dev-mcp/dev-plane`). The generator emits
|
|
13
|
+
* such a file only when that exact specifier would resolve in the consumer's
|
|
14
|
+
* build, so this check must answer the question Vite/SvelteKit will ask:
|
|
15
|
+
*
|
|
16
|
+
* - **ESM import conditions.** Published subpaths may expose only `types` and
|
|
17
|
+
* `import`. A CommonJS `createRequire(...).resolve` probe uses `require`
|
|
18
|
+
* conditions, throws `ERR_PACKAGE_PATH_NOT_EXPORTED` for such a subpath,
|
|
19
|
+
* and would falsely skip a correctly installed dependency.
|
|
20
|
+
* - **Anchored to the consumer.** Resolution starts from the consumer's
|
|
21
|
+
* `package.json` URL, so it walks the consumer's own `node_modules` and any
|
|
22
|
+
* hoisted ancestor `node_modules` — never core's install location.
|
|
23
|
+
* - **Existing file target.** ESM resolution can return a URL for a target
|
|
24
|
+
* that does not exist (or is a directory), so the target must be a file.
|
|
25
|
+
*
|
|
26
|
+
* Do not change a package's export map to accommodate a mismatched detector.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Whether `specifier` resolves from the consumer at `projectRoot` under ESM
|
|
30
|
+
* import conditions to an existing file.
|
|
31
|
+
*/
|
|
32
|
+
function consumerResolvesImport(projectRoot, specifier) {
|
|
33
|
+
try {
|
|
34
|
+
return statSync(fileURLToPath(resolve$1(specifier, pathToFileURL(join(projectRoot, "package.json")).href))).isFile();
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { consumerResolvesImport };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=consumer-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumer-import.js","names":[],"sources":["../../src/vite-plugin/consumer-import.ts"],"sourcesContent":["/**\n * Consumer-relative ESM resolution for generated-route dependencies (#3913).\n *\n * Generated SvelteKit files are written into the consumer's own `src/`, and\n * some of them import a package that core itself cannot depend on\n * (`@happyvertical/smrt-users/sveltekit`, `@happyvertical/smrt-app-runtime/\n * sveltekit`, `@happyvertical/smrt-dev-mcp/dev-plane`). The generator emits\n * such a file only when that exact specifier would resolve in the consumer's\n * build, so this check must answer the question Vite/SvelteKit will ask:\n *\n * - **ESM import conditions.** Published subpaths may expose only `types` and\n * `import`. A CommonJS `createRequire(...).resolve` probe uses `require`\n * conditions, throws `ERR_PACKAGE_PATH_NOT_EXPORTED` for such a subpath,\n * and would falsely skip a correctly installed dependency.\n * - **Anchored to the consumer.** Resolution starts from the consumer's\n * `package.json` URL, so it walks the consumer's own `node_modules` and any\n * hoisted ancestor `node_modules` — never core's install location.\n * - **Existing file target.** ESM resolution can return a URL for a target\n * that does not exist (or is a directory), so the target must be a file.\n *\n * Do not change a package's export map to accommodate a mismatched detector.\n */\n\nimport { statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { resolve as resolveImport } from 'import-meta-resolve';\n\n/**\n * Whether `specifier` resolves from the consumer at `projectRoot` under ESM\n * import conditions to an existing file.\n */\nexport function consumerResolvesImport(\n projectRoot: string,\n specifier: string,\n): boolean {\n try {\n const target = resolveImport(\n specifier,\n pathToFileURL(join(projectRoot, 'package.json')).href,\n );\n return statSync(fileURLToPath(target)).isFile();\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,uBACd,aACA,WACS;CACT,IAAI;EAKF,OAAO,SAAS,cAJD,UACb,WACA,cAAc,KAAK,aAAa,cAAc,CAAC,CAAC,CAAC,IAErB,CAAM,CAAC,CAAC,CAAC,OAAO;CAChD,QAAQ;EACN,OAAO;CACT;AACF"}
|
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
* only emitted when that subpath resolves from the consumer.
|
|
11
11
|
*/
|
|
12
12
|
import type { SvelteKitOptions } from './sveltekit-generator.js';
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Whether `@happyvertical/smrt-dev-mcp/dev-plane` resolves from the consumer
|
|
15
|
+
* under ESM import conditions to an existing file. The published subpath is
|
|
16
|
+
* `types`/`import`-only, so a CommonJS `createRequire.resolve` probe would
|
|
17
|
+
* always skip an installed dev-plane (#3913).
|
|
18
|
+
*/
|
|
14
19
|
export declare function consumerHasSmrtDevMcp(projectRoot: string): boolean;
|
|
15
20
|
/** Whether this invocation will own the `_dev/[...tool]` output file. */
|
|
16
21
|
export declare function willGenerateDevPlaneRoute(projectRoot: string, options: SvelteKitOptions): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-plane-route.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/dev-plane-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"dev-plane-route.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/dev-plane-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAKlE;AAED,yEAAyE;AACzE,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAKT;AAED,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA2BT"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { AUTO_GENERATED_ROUTE_HEADER } from "./route-header.js";
|
|
2
2
|
import { generateCollectionAccessImports } from "./sveltekit-config-import.js";
|
|
3
|
+
import { consumerResolvesImport } from "./consumer-import.js";
|
|
3
4
|
import { join } from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { createRequire } from "node:module";
|
|
7
6
|
//#region src/vite-plugin/dev-plane-route.ts
|
|
8
7
|
/**
|
|
9
8
|
* Generated `_dev/[...tool]/+server.ts` route: the in-app runtime dev-plane
|
|
@@ -16,14 +15,14 @@ import { createRequire } from "node:module";
|
|
|
16
15
|
* generated file imports at consumer runtime. Like `_resources`, the route is
|
|
17
16
|
* only emitted when that subpath resolves from the consumer.
|
|
18
17
|
*/
|
|
19
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Whether `@happyvertical/smrt-dev-mcp/dev-plane` resolves from the consumer
|
|
20
|
+
* under ESM import conditions to an existing file. The published subpath is
|
|
21
|
+
* `types`/`import`-only, so a CommonJS `createRequire.resolve` probe would
|
|
22
|
+
* always skip an installed dev-plane (#3913).
|
|
23
|
+
*/
|
|
20
24
|
function consumerHasSmrtDevMcp(projectRoot) {
|
|
21
|
-
|
|
22
|
-
createRequire(pathToFileURL(join(projectRoot, "package.json")).href).resolve("@happyvertical/smrt-dev-mcp/dev-plane");
|
|
23
|
-
return true;
|
|
24
|
-
} catch {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
25
|
+
return consumerResolvesImport(projectRoot, "@happyvertical/smrt-dev-mcp/dev-plane");
|
|
27
26
|
}
|
|
28
27
|
/** Whether this invocation will own the `_dev/[...tool]` output file. */
|
|
29
28
|
function willGenerateDevPlaneRoute(projectRoot, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-plane-route.js","names":[],"sources":["../../src/vite-plugin/dev-plane-route.ts"],"sourcesContent":["/**\n * Generated `_dev/[...tool]/+server.ts` route: the in-app runtime dev-plane\n * (#2782). Opt-in via `svelteKit: { devPlaneRoute: { enabled: true } }`.\n *\n * The route is dev-only twice over: it 404s unless SvelteKit's `dev` flag is\n * set, and it refuses to start without `SMRT_DEV_MCP_TOKEN`. Everything else\n * — loopback checks, bearer auth, the positive read-only catalog, the MCP\n * endpoint — lives in `@happyvertical/smrt-dev-mcp/dev-plane`, which the\n * generated file imports at consumer runtime. Like `_resources`, the route is\n * only emitted when that subpath resolves from the consumer.\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport {
|
|
1
|
+
{"version":3,"file":"dev-plane-route.js","names":[],"sources":["../../src/vite-plugin/dev-plane-route.ts"],"sourcesContent":["/**\n * Generated `_dev/[...tool]/+server.ts` route: the in-app runtime dev-plane\n * (#2782). Opt-in via `svelteKit: { devPlaneRoute: { enabled: true } }`.\n *\n * The route is dev-only twice over: it 404s unless SvelteKit's `dev` flag is\n * set, and it refuses to start without `SMRT_DEV_MCP_TOKEN`. Everything else\n * — loopback checks, bearer auth, the positive read-only catalog, the MCP\n * endpoint — lives in `@happyvertical/smrt-dev-mcp/dev-plane`, which the\n * generated file imports at consumer runtime. Like `_resources`, the route is\n * only emitted when that subpath resolves from the consumer.\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { consumerResolvesImport } from './consumer-import.js';\nimport { AUTO_GENERATED_ROUTE_HEADER } from './route-header.js';\nimport { generateCollectionAccessImports } from './sveltekit-config-import.js';\nimport type { SvelteKitOptions } from './sveltekit-generator.js';\n\n/**\n * Whether `@happyvertical/smrt-dev-mcp/dev-plane` resolves from the consumer\n * under ESM import conditions to an existing file. The published subpath is\n * `types`/`import`-only, so a CommonJS `createRequire.resolve` probe would\n * always skip an installed dev-plane (#3913).\n */\nexport function consumerHasSmrtDevMcp(projectRoot: string): boolean {\n return consumerResolvesImport(\n projectRoot,\n '@happyvertical/smrt-dev-mcp/dev-plane',\n );\n}\n\n/** Whether this invocation will own the `_dev/[...tool]` output file. */\nexport function willGenerateDevPlaneRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): boolean {\n return (\n options.devPlaneRoute?.enabled === true &&\n consumerHasSmrtDevMcp(projectRoot)\n );\n}\n\nexport function generateDevPlaneRoute(\n projectRoot: string,\n options: SvelteKitOptions,\n): boolean {\n if (options.devPlaneRoute?.enabled !== true) {\n return false;\n }\n if (!willGenerateDevPlaneRoute(projectRoot, options)) {\n console.log(\n '[smrt] Skipping _dev route - @happyvertical/smrt-dev-mcp/dev-plane is ' +\n 'not resolvable; install @happyvertical/smrt-dev-mcp as a devDependency',\n );\n return false;\n }\n const routeDir = join(projectRoot, options.routesDir, '_dev', '[...tool]');\n if (!existsSync(routeDir)) {\n mkdirSync(routeDir, { recursive: true });\n }\n const filePath = join(routeDir, '+server.ts');\n writeFileSync(\n filePath,\n generateDevPlaneRouteTemplate(\n generateCollectionAccessImports(projectRoot, routeDir, options, [\n 'getSmrtConfig',\n ]),\n ),\n 'utf-8',\n );\n console.log(`[smrt] Generated: ${filePath}`);\n return true;\n}\n\nfunction generateDevPlaneRouteTemplate(\n collectionAccessImports: string,\n): string {\n return `${AUTO_GENERATED_ROUTE_HEADER}\n// DO NOT EDIT - changes will be overwritten\n//\n// In-app runtime dev-plane (#2782). Dev mode only. Serves the read-only\n// runtime tools over JSON (GET|POST /_dev/<tool>, GET /_dev for the catalog)\n// and MCP (POST /_dev/mcp) against this app's live registry and database.\n// Requires SMRT_DEV_MCP_TOKEN; every request must present it as a bearer\n// token from loopback. Never mounted in production builds.\nimport { dev } from '$app/environment';\nimport { error } from '@sveltejs/kit';\nimport type { RequestHandler } from './$types';\nimport { createDevPlane, type DevPlane } from '@happyvertical/smrt-dev-mcp/dev-plane';\n${collectionAccessImports}\n\nlet plane: DevPlane | null = null;\n\nfunction getPlane(): DevPlane | null {\n if (!dev) return null;\n const token = process.env.SMRT_DEV_MCP_TOKEN?.trim();\n if (!token) return null;\n if (!plane) {\n // The default config's db is what the app itself opens; passing its\n // url/type makes the SDK connection cache hand the plane the same handle.\n const db = getSmrtConfig('__smrt_dev_plane__').db as\n | { url?: string; type?: string }\n | undefined;\n plane = createDevPlane({ token, projectRoot: process.cwd(), db });\n }\n return plane;\n}\n\nconst handle: RequestHandler = async ({ request, url }) => {\n if (!dev) throw error(404, 'Not found');\n const active = getPlane();\n if (!active) {\n throw error(503, 'SMRT_DEV_MCP_TOKEN is not set; the dev-plane is disabled');\n }\n const base = url.pathname.slice(0, url.pathname.indexOf('/_dev') + '/_dev'.length);\n return active.handleRequest(request, base);\n};\n\nexport const GET = handle;\nexport const POST = handle;\n`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,sBAAsB,aAA8B;CAClE,OAAO,uBACL,aACA,uCACF;AACF;;AAGA,SAAgB,0BACd,aACA,SACS;CACT,OACE,QAAQ,eAAe,YAAY,QACnC,sBAAsB,WAAW;AAErC;AAEA,SAAgB,sBACd,aACA,SACS;CACT,IAAI,QAAQ,eAAe,YAAY,MACrC,OAAO;CAET,IAAI,CAAC,0BAA0B,aAAa,OAAO,GAAG;EACpD,QAAQ,IACN,8IAEF;EACA,OAAO;CACT;CACA,MAAM,WAAW,KAAK,aAAa,QAAQ,WAAW,QAAQ,WAAW;CACzE,IAAI,CAAC,WAAW,QAAQ,GACtB,UAAU,UAAU,EAAE,WAAW,KAAK,CAAC;CAEzC,MAAM,WAAW,KAAK,UAAU,YAAY;CAC5C,cACE,UACA,8BACE,gCAAgC,aAAa,UAAU,SAAS,CAC9D,eACF,CAAC,CACH,GACA,OACF;CACA,QAAQ,IAAI,qBAAqB,UAAU;CAC3C,OAAO;AACT;AAEA,SAAS,8BACP,yBACQ;CACR,OAAO,GAAG,4BAA4B;;;;;;;;;;;;EAYtC,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgC1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAKzE,OAAO,KAAK,EACV,2BAA2B,EAC3B,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAKzE,OAAO,KAAK,EACV,2BAA2B,EAC3B,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,2BAA2B,CAAC;AAcnC,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAWpC,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAsB9B,OAAO,EACL,kCAAkC,EAClC,KAAK,sCAAsC,EAC3C,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,8BAA8B,EAC9B,2BAA2B,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAalE,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACnD,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,6BAA6B,CAAC;IACnD,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qBAAqB;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wEAAwE;IACxE,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC;;OAEG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,8CAA8C;IAC9C,SAAS,CAAC,EAAE;QACV,yDAAyD;QACzD,OAAO,EAAE,OAAO,CAAC;QACjB,wEAAwE;QACxE,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,qEAAqE;QACrE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,mEAAmE;QACnE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,mDAAmD;QACnD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB;;;;WAIG;QACH,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB;;;WAGG;QACH,YAAY,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;QACrC;;;;WAIG;QACH,WAAW,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAC;YAAC,cAAc,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7D;;;;;;WAMG;QACH,cAAc,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KACxC,CAAC;IACF,mEAAmE;IACnE,SAAS,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAC1C;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,kBAAkB,CAAC,EAAE,6BAA6B,CAAC;QACnD,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,sBAAsB,CACpB,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAClC;;;;OAIG;IACH,4BAA4B,IAAI,OAAO,CACrC,2BAA2B,GAAG,SAAS,CACxC,CAAC;CACH;AAYD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACvC,2BAA2B,GAAG,SAAS,CAgBzC;AAyBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qCAAqC,CAAC,KAAK,EAAE;IAC3D,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,0BAA0B,EAAE,aAAa,CAAC,4BAA4B,CAAC,CAAC;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,GAAG,2BAA2B,CAAC,aAAa,CAAC,CAY7C;AAsED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAG1D;AAKD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,mBAAmB,GAC5B,mBAAmB,CAIrB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAAC,CAuC7C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,mBAAmB,GAC5B,MAAM,CAaR;AAqID,wBAAgB,UAAU,CACxB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,CAAC,aAAa,CAAC,GAAG;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,CAwpCxD;AAwQD;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,MAAM,EACnB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC,IAAI,CAAC,CAmaf"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { DETERMINISTIC_GENERATED_AT } from "../scanner/types.js";
|
|
2
|
+
import { isTestArtifactManifest } from "../manifest/test-artifacts.js";
|
|
2
3
|
import { CRUD_OPERATIONS } from "../generators/custom-action.js";
|
|
3
4
|
import { findCliApiCoherenceViolations, generateSvelteKitRoutes, methodNameToKebab, resolveApiActionRouteConfig, resolveApiActionSet, validateCliIncludeAgainstApi } from "./sveltekit-generator.js";
|
|
4
|
-
import { buildWebMcpToolDefinitions,
|
|
5
|
+
import { buildWebMcpToolDefinitions, generateWebModule, selectWebCollectionEntries } from "./web-collections.js";
|
|
5
6
|
import { publishAtomicArtifact } from "../consumer-plugin/artifact-publication.js";
|
|
6
7
|
import { mergeKnowledgeConfig, resolveFileKnowledgeConfig } from "../knowledge-config.js";
|
|
7
8
|
import { buildDomainKnowledgeManifest } from "../knowledge.js";
|
|
9
|
+
import { createObjectDeclarationIndex, selectObjectDeclarations, warnObjectDeclarationCollisions } from "../manifest/object-declarations.js";
|
|
8
10
|
import { importWorkspaceModule } from "../utils/import-workspace-module.js";
|
|
9
11
|
import { discoverSmrtPackages } from "../manifest/discover-smrt-packages.js";
|
|
10
12
|
import { smrtAssetUrlCompatibility } from "./asset-url-compatibility.js";
|
|
@@ -282,6 +284,7 @@ function mergeExternalManifestEntries(manifest, manifestPath) {
|
|
|
282
284
|
return manifest;
|
|
283
285
|
}
|
|
284
286
|
if (!existing?.objects || typeof existing.objects !== "object") return manifest;
|
|
287
|
+
if (isTestArtifactManifest(existing)) return manifest;
|
|
285
288
|
const localPackageNames = /* @__PURE__ */ new Set();
|
|
286
289
|
if (manifest.packageName) localPackageNames.add(manifest.packageName);
|
|
287
290
|
if (typeof existing.packageName === "string" && existing.packageName) localPackageNames.add(existing.packageName);
|
|
@@ -984,9 +987,7 @@ export function createMCPServer(options = {}) {
|
|
|
984
987
|
*/
|
|
985
988
|
function generateClientModeTypes(manifest) {
|
|
986
989
|
const typeDefinitions = [];
|
|
987
|
-
|
|
988
|
-
for (const objectMeta of sortedClientModeObjects) {
|
|
989
|
-
const interfaceName = objectMeta.className;
|
|
990
|
+
for (const { interfaceName, obj: objectMeta } of selectObjectDeclarations(manifest)) {
|
|
990
991
|
const fields = objectMeta.fields || {};
|
|
991
992
|
const propertyLines = [];
|
|
992
993
|
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
@@ -1017,7 +1018,7 @@ function generateClientModeTypes(manifest) {
|
|
|
1017
1018
|
propertyLines.push(` ${fieldName}${optional}: ${type};`);
|
|
1018
1019
|
}
|
|
1019
1020
|
propertyLines.unshift(" id?: string;", " created_at?: string;", " updated_at?: string;");
|
|
1020
|
-
const interfaceDef = `export interface ${interfaceName}
|
|
1021
|
+
const interfaceDef = `export interface ${interfaceName} {\n${propertyLines.join("\n")}\n}`;
|
|
1021
1022
|
typeDefinitions.push(interfaceDef);
|
|
1022
1023
|
}
|
|
1023
1024
|
return typeDefinitions.join("\n\n");
|
|
@@ -1094,8 +1095,10 @@ async function generateTypeDeclarationFile(manifest, projectRoot, typeDeclaratio
|
|
|
1094
1095
|
const declarationsDir = join(projectRoot, typeDeclarationsPath);
|
|
1095
1096
|
const declarationsFile = join(declarationsDir, "virtual-modules.d.ts");
|
|
1096
1097
|
if (!existsSync(declarationsDir)) mkdirSync(declarationsDir, { recursive: true });
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1098
|
+
const declarations = createObjectDeclarationIndex(manifest);
|
|
1099
|
+
warnObjectDeclarationCollisions(declarations, console.warn);
|
|
1100
|
+
const objectInterfaces = declarations.declarations.map(({ interfaceName, obj }) => {
|
|
1101
|
+
return ` export interface ${interfaceName} {
|
|
1099
1102
|
id?: string;
|
|
1100
1103
|
${Object.entries(obj.fields).map(([fieldName, field]) => {
|
|
1101
1104
|
return ` ${fieldName}${field.required === false ? "?" : ""}: ${mapTypeScriptType(field.type)};`;
|
|
@@ -1106,7 +1109,7 @@ ${Object.entries(obj.fields).map(([fieldName, field]) => {
|
|
|
1106
1109
|
}).join("\n\n");
|
|
1107
1110
|
const apiClientInterface = selectApiClientEntries(manifest).map(({ obj, clientKey, dataInterfaceName, crudMethods, customMethods: exposedMethods }) => {
|
|
1108
1111
|
const { methods = {} } = obj;
|
|
1109
|
-
const interfaceName = dataInterfaceName
|
|
1112
|
+
const interfaceName = `import('@happyvertical/smrt-virt-types').${dataInterfaceName}`;
|
|
1110
1113
|
const exposedActionNames = new Set(exposedMethods.map((method) => method.name));
|
|
1111
1114
|
const customMethods = Object.entries(methods).filter(([name, method]) => !GENERATED_CLIENT_CRUD_METHODS.has(name) && method.isPublic && exposedActionNames.has(name));
|
|
1112
1115
|
const customMethodSignatures = customMethods.map(([methodName]) => {
|
|
@@ -1121,7 +1124,7 @@ ${Object.entries(obj.fields).map(([fieldName, field]) => {
|
|
|
1121
1124
|
}
|
|
1122
1125
|
return ` ${JSON.stringify(clientKey)}: ${crudOperationsType ?? "Record<string, never>"};`;
|
|
1123
1126
|
}).join("\n");
|
|
1124
|
-
const webCollectionInterface = selectWebCollectionEntries(manifest).map(({ collection, obj }) => ` ${JSON.stringify(collection)}: SmrtWebCollectionDefinition<import('@happyvertical/smrt-virt-types').${obj
|
|
1127
|
+
const webCollectionInterface = selectWebCollectionEntries(manifest).map(({ collection, obj }) => ` ${JSON.stringify(collection)}: SmrtWebCollectionDefinition<import('@happyvertical/smrt-virt-types').${declarations.interfaceNameFor(obj)}>;`).join("\n");
|
|
1125
1128
|
Object.entries(manifest.objects).flatMap(([_name, obj]) => Object.entries(obj.methods).map(([methodName, method]) => ({
|
|
1126
1129
|
name: `${methodName}_${obj.collection}`,
|
|
1127
1130
|
description: `${method.name} operation on ${obj.collection}`,
|