@happyvertical/smrt-core 0.45.2 → 0.46.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.
- package/AGENTS.md +1 -0
- package/agents/generators.md +0 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/embedded-write-queue.d.ts.map +1 -1
- package/dist/embedded-write-queue.js +20 -1
- package/dist/embedded-write-queue.js.map +1 -1
- package/dist/generators/custom-action.d.ts +71 -39
- package/dist/generators/custom-action.d.ts.map +1 -1
- package/dist/generators/custom-action.js +71 -39
- package/dist/generators/custom-action.js.map +1 -1
- package/dist/generators/index.d.ts +0 -2
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +2 -3
- package/dist/generators/mcp.d.ts.map +1 -1
- package/dist/generators/mcp.js +1 -1
- package/dist/generators/mcp.js.map +1 -1
- package/dist/generators/tenant-gate.d.ts +33 -9
- package/dist/generators/tenant-gate.d.ts.map +1 -1
- package/dist/generators/tenant-gate.js +2 -1
- package/dist/generators/tenant-gate.js.map +1 -1
- package/dist/generators.js +2 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/knowledge.js +28 -16
- package/dist/knowledge.js.map +1 -1
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/migrations/framework-base-tables.d.ts +148 -0
- package/dist/migrations/framework-base-tables.d.ts.map +1 -0
- package/dist/migrations/framework-base-tables.js +419 -0
- package/dist/migrations/framework-base-tables.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +2 -1
- package/dist/migrations.js +2 -1
- package/dist/postgres-permissions.d.ts +40 -0
- package/dist/postgres-permissions.d.ts.map +1 -0
- package/dist/postgres-permissions.js +353 -0
- package/dist/postgres-permissions.js.map +1 -0
- package/dist/registry/framework-base-classes.d.ts.map +1 -1
- package/dist/registry/framework-base-classes.js +4 -1
- package/dist/registry/framework-base-classes.js.map +1 -1
- package/dist/scripts/create-wrappers.js +0 -5
- package/dist/smrt-knowledge.json +7 -8
- package/dist/testing/database.d.ts +6 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +9 -1
- package/dist/testing/database.js.map +1 -1
- package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
- package/dist/vite-plugin/api-client-entries.js +16 -14
- package/dist/vite-plugin/api-client-entries.js.map +1 -1
- package/dist/vite-plugin/index.d.ts.map +1 -1
- package/dist/vite-plugin/index.js +2 -166
- package/dist/vite-plugin/index.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts +3 -2
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +20 -24
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/templates/default-ui.ts +22 -1
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +4 -9
- package/dist/generators/cli.d.ts +0 -155
- package/dist/generators/cli.d.ts.map +0 -1
- package/dist/generators/cli.js +0 -473
- package/dist/generators/cli.js.map +0 -1
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
import { CRUD_OPERATIONS } from "../generators/custom-action.js";
|
|
1
2
|
import { resolveApiActionRouteConfig } from "./sveltekit-generator.js";
|
|
2
3
|
import { findManifestObjectByName, isCollectionManifestClass, resolveCollectionItemObject } from "./web-collections.js";
|
|
3
4
|
//#region src/vite-plugin/api-client-entries.ts
|
|
5
|
+
/**
|
|
6
|
+
* Manifest -> generated API-client entry selection.
|
|
7
|
+
*
|
|
8
|
+
* Runtime client values, Vite ambient declarations, and physical prebuild
|
|
9
|
+
* declarations must agree on which manifest object owns a collection's
|
|
10
|
+
* canonical endpoint. Collection classes describe access methods, not row
|
|
11
|
+
* payloads, so a populated model always wins the shared collection key.
|
|
12
|
+
*/
|
|
4
13
|
function renderApiClientCrudType(dataInterfaceName, crudMethods, overriddenMethods = []) {
|
|
5
14
|
const overridden = new Set(overriddenMethods);
|
|
6
15
|
const methods = crudMethods.filter((method) => !overridden.has(method));
|
|
7
16
|
if (methods.length === 0) return void 0;
|
|
8
|
-
if (methods.length === 6 && methods.every((method, index) => method === [...
|
|
17
|
+
if (methods.length === 6 && methods.every((method, index) => method === [...CRUD_OPERATIONS, "search"][index])) return `CrudOperations<${dataInterfaceName}>`;
|
|
9
18
|
return `Pick<CrudOperations<${dataInterfaceName}>, ${methods.map((method) => JSON.stringify(method)).join(" | ")}>`;
|
|
10
19
|
}
|
|
11
20
|
function renderApiClientCustomMethodParameters(method, mapType) {
|
|
@@ -59,14 +68,7 @@ function isAncestorOf(manifest, ancestor, descendant) {
|
|
|
59
68
|
}
|
|
60
69
|
return false;
|
|
61
70
|
}
|
|
62
|
-
var
|
|
63
|
-
"list",
|
|
64
|
-
"get",
|
|
65
|
-
"create",
|
|
66
|
-
"update",
|
|
67
|
-
"delete"
|
|
68
|
-
];
|
|
69
|
-
var STANDARD_API_ACTION_SET = new Set(STANDARD_API_ACTIONS);
|
|
71
|
+
var CRUD_OPERATION_SET = new Set(CRUD_OPERATIONS);
|
|
70
72
|
function resolveGeneratedClientCustomMethods(obj, manifest) {
|
|
71
73
|
const apiConfig = obj.decoratorConfig?.api;
|
|
72
74
|
if (apiConfig === false) return [];
|
|
@@ -75,7 +77,7 @@ function resolveGeneratedClientCustomMethods(obj, manifest) {
|
|
|
75
77
|
const excluded = Array.isArray(config?.exclude) ? config.exclude : void 0;
|
|
76
78
|
const isCollection = isCollectionManifestClass(manifest, obj);
|
|
77
79
|
return Object.entries(obj.methods ?? {}).flatMap(([name, method]) => {
|
|
78
|
-
if (
|
|
80
|
+
if (CRUD_OPERATION_SET.has(name) || !method.isPublic) return [];
|
|
79
81
|
if (included && !included.includes(name)) return [];
|
|
80
82
|
if (excluded?.includes(name)) return [];
|
|
81
83
|
const routeConfig = resolveApiActionRouteConfig(name, method, apiConfig, {}, isCollection ? "collection" : method.isStatic ? "collection" : "item");
|
|
@@ -97,11 +99,11 @@ function resolveGeneratedClientCrudMethods(obj, manifest) {
|
|
|
97
99
|
const crudObject = resolveCrudObject(obj, manifest);
|
|
98
100
|
const apiConfig = crudObject?.decoratorConfig?.api;
|
|
99
101
|
if (!crudObject || apiConfig === false) return [];
|
|
100
|
-
if (apiConfig === true || apiConfig === void 0) return [...
|
|
101
|
-
if (typeof apiConfig !== "object" || apiConfig === null) return [...
|
|
102
|
+
if (apiConfig === true || apiConfig === void 0) return [...CRUD_OPERATIONS, "search"];
|
|
103
|
+
if (typeof apiConfig !== "object" || apiConfig === null) return [...CRUD_OPERATIONS, "search"];
|
|
102
104
|
const included = Array.isArray(apiConfig.include) ? apiConfig.include : void 0;
|
|
103
105
|
const excluded = Array.isArray(apiConfig.exclude) ? apiConfig.exclude : [];
|
|
104
|
-
const standardMethods = (included ?
|
|
106
|
+
const standardMethods = (included ? CRUD_OPERATIONS.filter((action) => included.includes(action)) : [...CRUD_OPERATIONS]).filter((action) => !excluded.includes(action));
|
|
105
107
|
return !included && !excluded.includes("search") ? [...standardMethods, "search"] : standardMethods;
|
|
106
108
|
}
|
|
107
109
|
/**
|
|
@@ -133,7 +135,7 @@ function resolveGeneratedEndpointCrudMethods(collection, manifest) {
|
|
|
133
135
|
if (emittedItemMethods.length > 0) itemMethods = emittedItemMethods;
|
|
134
136
|
}
|
|
135
137
|
const emitted = /* @__PURE__ */ new Set([...collectionMethods, ...itemMethods]);
|
|
136
|
-
return [...
|
|
138
|
+
return [...CRUD_OPERATIONS, "search"].filter((method) => emitted.has(method));
|
|
137
139
|
}
|
|
138
140
|
function exposesApiClientSurface(obj, manifest) {
|
|
139
141
|
if (obj.decoratorConfig?.api === false) return false;
|
|
@@ -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 type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types.js';\nimport { resolveApiActionRouteConfig } from './sveltekit-generator.js';\nimport {\n findManifestObjectByName,\n isCollectionManifestClass,\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 === [...STANDARD_API_ACTIONS, '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 STANDARD_API_ACTIONS = [\n 'list',\n 'get',\n 'create',\n 'update',\n 'delete',\n] as const;\nconst STANDARD_API_ACTION_SET = new Set<string>(STANDARD_API_ACTIONS);\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 config =\n typeof apiConfig === 'object' && apiConfig !== null ? apiConfig : undefined;\n const included = Array.isArray(config?.include) ? config.include : undefined;\n const excluded = Array.isArray(config?.exclude) ? config.exclude : undefined;\n const isCollection = isCollectionManifestClass(manifest, obj);\n\n return Object.entries(obj.methods ?? {}).flatMap(([name, method]) => {\n if (STANDARD_API_ACTION_SET.has(name) || !method.isPublic) return [];\n if (included && !included.includes(name)) return [];\n if (excluded?.includes(name)) return [];\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 return Object.values(manifest.objects)\n .filter(\n (candidate) =>\n candidate.collection === obj.collection &&\n !isCollectionManifestClass(manifest, candidate),\n )\n .sort((left, right) =>\n compareText(\n left.qualifiedName ?? left.className,\n right.qualifiedName ?? right.className,\n ),\n )[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 [...STANDARD_API_ACTIONS, 'search'];\n }\n if (typeof apiConfig !== 'object' || apiConfig === null) {\n return [...STANDARD_API_ACTIONS, '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 ? STANDARD_API_ACTIONS.filter((action) => included.includes(action))\n : [...STANDARD_API_ACTIONS]\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 insertion order. Collection\n * and item handlers live in separate files, and the last model that emits each\n * file replaces the earlier file. Mirror that behavior here so every client\n * alias for a shared endpoint has the same, real action set.\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 Object.values(manifest.objects)) {\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[] = [\n ...STANDARD_API_ACTIONS,\n 'search',\n ];\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":"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"}
|
|
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 { CRUD_OPERATIONS } 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 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 config =\n typeof apiConfig === 'object' && apiConfig !== null ? apiConfig : undefined;\n const included = Array.isArray(config?.include) ? config.include : undefined;\n const excluded = Array.isArray(config?.exclude) ? config.exclude : undefined;\n const isCollection = isCollectionManifestClass(manifest, obj);\n\n return Object.entries(obj.methods ?? {}).flatMap(([name, method]) => {\n if (CRUD_OPERATION_SET.has(name) || !method.isPublic) return [];\n if (included && !included.includes(name)) return [];\n if (excluded?.includes(name)) return [];\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 return Object.values(manifest.objects)\n .filter(\n (candidate) =>\n candidate.collection === obj.collection &&\n !isCollectionManifestClass(manifest, candidate),\n )\n .sort((left, right) =>\n compareText(\n left.qualifiedName ?? left.className,\n right.qualifiedName ?? right.className,\n ),\n )[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 insertion order. Collection\n * and item handlers live in separate files, and the last model that emits each\n * file replaces the earlier file. Mirror that behavior here so every client\n * alias for a shared endpoint has the same, real action set.\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 Object.values(manifest.objects)) {\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":";;;;;;;;;;;;AAsDA,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;AAEA,IAAM,qBAAqB,IAAI,IAAY,eAAe;AAE1D,SAAS,oCACP,KACA,UACiC;CACjC,MAAM,YAAY,IAAI,iBAAiB;CACvC,IAAI,cAAc,OAAO,OAAO,CAAC;CAEjC,MAAM,SACJ,OAAO,cAAc,YAAY,cAAc,OAAO,YAAY,KAAA;CACpE,MAAM,WAAW,MAAM,QAAQ,QAAQ,OAAO,IAAI,OAAO,UAAU,KAAA;CACnE,MAAM,WAAW,MAAM,QAAQ,QAAQ,OAAO,IAAI,OAAO,UAAU,KAAA;CACnE,MAAM,eAAe,0BAA0B,UAAU,GAAG;CAE5D,OAAO,OAAO,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,YAAY;EACnE,IAAI,mBAAmB,IAAI,IAAI,KAAK,CAAC,OAAO,UAAU,OAAO,CAAC;EAC9D,IAAI,YAAY,CAAC,SAAS,SAAS,IAAI,GAAG,OAAO,CAAC;EAClD,IAAI,UAAU,SAAS,IAAI,GAAG,OAAO,CAAC;EAEtC,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;CAGvB,OAAO,OAAO,OAAO,SAAS,OAAO,CAAC,CACnC,QACE,cACC,UAAU,eAAe,IAAI,cAC7B,CAAC,0BAA0B,UAAU,SAAS,CAClD,CAAC,CACA,MAAM,MAAM,UACX,YACE,KAAK,iBAAiB,KAAK,WAC3B,MAAM,iBAAiB,MAAM,SAC/B,CACF,CAAC,CAAC;AACN;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;;;;;;;;;;AAWA,SAAS,oCACP,YACA,UACuB;CACvB,IAAI,oBAA2C,CAAC;CAChD,IAAI,cAAqC,CAAC;CAE1C,KAAK,MAAM,OAAO,OAAO,OAAO,SAAS,OAAO,GAAG;EACjD,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EACV,2BAA2B,EAC3B,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,MAAM,EAAiC,MAAM,MAAM,CAAC;AAClE,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vite-plugin/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DETERMINISTIC_GENERATED_AT } from "../scanner/types.js";
|
|
2
|
-
import { resolveCustomActionNames } from "../generators/custom-action.js";
|
|
3
2
|
import { findCliApiCoherenceViolations, generateSvelteKitRoutes, methodNameToKebab, resolveApiActionRouteConfig, resolveApiActionSet, validateCliIncludeAgainstApi } from "./sveltekit-generator.js";
|
|
4
3
|
import { buildWebCollectionDefinition, buildWebMcpToolDefinitions, buildWebToolDescriptors, computeWebManifestHash, selectWebCollectionEntries } from "./web-collections.js";
|
|
5
4
|
import { buildDomainKnowledgeManifest } from "../knowledge.js";
|
|
@@ -24,7 +23,6 @@ var VIRTUAL_MODULES = {
|
|
|
24
23
|
"@happyvertical/smrt-virt-types": "smrt:types",
|
|
25
24
|
"@happyvertical/smrt-virt-manifest": "smrt:manifest",
|
|
26
25
|
"@happyvertical/smrt-virt-ui": "smrt:ui",
|
|
27
|
-
"@happyvertical/smrt-virt-cli": "smrt:cli",
|
|
28
26
|
"@happyvertical/smrt-virt-web": "smrt:web"
|
|
29
27
|
};
|
|
30
28
|
/**
|
|
@@ -153,7 +151,7 @@ function smrtPlugin(options = {}) {
|
|
|
153
151
|
if (violations.length === 0) return;
|
|
154
152
|
for (const { className, unreachable } of violations) {
|
|
155
153
|
const cliConfig = m.objects[className]?.decoratorConfig?.cli;
|
|
156
|
-
const isEnforced = typeof cliConfig === "object" && Array.isArray(cliConfig.include) && cliConfig.include.length > 0;
|
|
154
|
+
const isEnforced = typeof cliConfig === "object" && cliConfig !== null && Array.isArray(cliConfig.include) && cliConfig.include.length > 0;
|
|
157
155
|
for (const action of unreachable) console.warn(`[smrt] ${className}.${action} is exposed as a CLI command but is not exposed via the api.` + (isEnforced ? " Build will fail until this is resolved.\n" : " (Not yet build-blocking for this cli:true/{} class -- see #2638.)\n") + ` Either:\n - Add '${action}' to api.include, or\n - Remove '${action}' from cli.include / add it to cli.exclude.\n The CLI invokes methods over HTTP; methods without API routes are unreachable.\n If this CLI is intentionally invoked in-process (no HTTP), set\n \`cli: { skipApiCheck: true }\` on the @smrt() decorator to acknowledge.`);
|
|
158
156
|
}
|
|
159
157
|
}
|
|
@@ -516,7 +514,6 @@ function smrtPlugin(options = {}) {
|
|
|
516
514
|
case "smrt:manifest": return generateManifestModule(manifest);
|
|
517
515
|
case "smrt:ui": return await loadDefaultUI();
|
|
518
516
|
case "smrt:index-html": return await loadDefaultHTML();
|
|
519
|
-
case "smrt:cli": return await generateCLIModule(manifest);
|
|
520
517
|
case "smrt:web": return generateWebModule(manifest, { kebabRoutes: svelteKit.kebabRoutes ?? false });
|
|
521
518
|
default: return null;
|
|
522
519
|
}
|
|
@@ -1218,44 +1215,7 @@ ${webCollectionInterface}
|
|
|
1218
1215
|
export const manifestHash: string;
|
|
1219
1216
|
export default collectionDefinitions;
|
|
1220
1217
|
}
|
|
1221
|
-
|
|
1222
|
-
// CLI module - Auto-generated command-line interface
|
|
1223
|
-
declare module '@happyvertical/smrt-virt-cli' {
|
|
1224
|
-
export interface CLIConfig {
|
|
1225
|
-
name?: string;
|
|
1226
|
-
version?: string;
|
|
1227
|
-
description?: string;
|
|
1228
|
-
prompt?: boolean;
|
|
1229
|
-
colors?: boolean;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
export interface CLIContext {
|
|
1233
|
-
db?: any;
|
|
1234
|
-
ai?: any;
|
|
1235
|
-
user?: {
|
|
1236
|
-
id: string;
|
|
1237
|
-
roles?: string[];
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
export interface CLICommandMap {
|
|
1242
|
-
[objectName: string]: {
|
|
1243
|
-
collection: string;
|
|
1244
|
-
commands: string[];
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
export const cliCommands: CLICommandMap;
|
|
1249
|
-
|
|
1250
|
-
export function setupCLI(config?: CLIConfig, context?: CLIContext): {
|
|
1251
|
-
run: (argv: string[]) => Promise<void>;
|
|
1252
|
-
generator: any;
|
|
1253
|
-
};
|
|
1254
|
-
|
|
1255
|
-
export function getCLIHandler(config?: CLIConfig, context?: CLIContext): (argv: string[]) => Promise<void>;
|
|
1256
|
-
|
|
1257
|
-
export default setupCLI;
|
|
1258
|
-
}`);
|
|
1218
|
+
`);
|
|
1259
1219
|
console.log(`[smrt] Generated TypeScript declarations: ${declarationsFile}`);
|
|
1260
1220
|
} catch (error) {
|
|
1261
1221
|
console.error("[smrt] Error generating TypeScript declarations:", error);
|
|
@@ -1335,130 +1295,6 @@ async function loadDefaultHTML() {
|
|
|
1335
1295
|
async function loadDefaultUI() {
|
|
1336
1296
|
return getDefaultUIModule();
|
|
1337
1297
|
}
|
|
1338
|
-
/**
|
|
1339
|
-
* Generate virtual CLI module
|
|
1340
|
-
*/
|
|
1341
|
-
async function generateCLIModule(manifest) {
|
|
1342
|
-
try {
|
|
1343
|
-
const commands = [];
|
|
1344
|
-
const objectImports = [];
|
|
1345
|
-
for (const [className, objectDef] of Object.entries(manifest.objects)) {
|
|
1346
|
-
const cliConfig = objectDef.decoratorConfig?.cli;
|
|
1347
|
-
if (cliConfig === false) continue;
|
|
1348
|
-
const excluded = (typeof cliConfig === "object" ? cliConfig.exclude : []) || [];
|
|
1349
|
-
const included = typeof cliConfig === "object" ? cliConfig.include : null;
|
|
1350
|
-
const shouldInclude = (command) => {
|
|
1351
|
-
if (included && !included.includes(command)) return false;
|
|
1352
|
-
if (excluded.includes(command)) return false;
|
|
1353
|
-
return true;
|
|
1354
|
-
};
|
|
1355
|
-
const collectionName = objectDef.collection;
|
|
1356
|
-
const simpleClassName = objectDef.className || className;
|
|
1357
|
-
const commandName = simpleClassName.toLowerCase();
|
|
1358
|
-
objectImports.push(`// Import ${simpleClassName} for CLI operations`);
|
|
1359
|
-
const availableCommands = [];
|
|
1360
|
-
if (shouldInclude("list")) availableCommands.push(`'${commandName}:list'`);
|
|
1361
|
-
if (shouldInclude("get")) availableCommands.push(`'${commandName}:get'`);
|
|
1362
|
-
if (shouldInclude("create")) availableCommands.push(`'${commandName}:create'`);
|
|
1363
|
-
if (shouldInclude("update")) availableCommands.push(`'${commandName}:update'`);
|
|
1364
|
-
if (shouldInclude("delete")) availableCommands.push(`'${commandName}:delete'`);
|
|
1365
|
-
for (const methodName of resolveCustomActionNames(Object.entries(objectDef.methods), {
|
|
1366
|
-
include: included ?? void 0,
|
|
1367
|
-
exclude: excluded
|
|
1368
|
-
}, [
|
|
1369
|
-
"list",
|
|
1370
|
-
"get",
|
|
1371
|
-
"create",
|
|
1372
|
-
"update",
|
|
1373
|
-
"delete"
|
|
1374
|
-
])) {
|
|
1375
|
-
if (methodName.startsWith("_")) continue;
|
|
1376
|
-
if (shouldInclude(methodName)) availableCommands.push(`'${commandName}:${methodName}'`);
|
|
1377
|
-
}
|
|
1378
|
-
if (availableCommands.length > 0) commands.push(`
|
|
1379
|
-
// ${simpleClassName} commands
|
|
1380
|
-
${JSON.stringify(simpleClassName)}: {
|
|
1381
|
-
collection: ${JSON.stringify(collectionName)},
|
|
1382
|
-
commands: [${availableCommands.join(", ")}]
|
|
1383
|
-
}`);
|
|
1384
|
-
}
|
|
1385
|
-
return `
|
|
1386
|
-
// Auto-generated CLI module from SMRT objects
|
|
1387
|
-
// This file is generated automatically - do not edit
|
|
1388
|
-
|
|
1389
|
-
import { CLIGenerator } from '@happyvertical/smrt-core/generators/cli';
|
|
1390
|
-
|
|
1391
|
-
/**
|
|
1392
|
-
* @typedef {import('@happyvertical/smrt-core/generators/cli').CLIConfig} CLIConfig
|
|
1393
|
-
* @typedef {import('@happyvertical/smrt-core/generators/cli').CLIContext} CLIContext
|
|
1394
|
-
*/
|
|
1395
|
-
|
|
1396
|
-
${objectImports.join("\n")}
|
|
1397
|
-
|
|
1398
|
-
/**
|
|
1399
|
-
* Available CLI commands by object
|
|
1400
|
-
*/
|
|
1401
|
-
export const cliCommands = {${commands.join(",\n")}
|
|
1402
|
-
};
|
|
1403
|
-
|
|
1404
|
-
/**
|
|
1405
|
-
* Setup CLI with auto-generated commands
|
|
1406
|
-
*
|
|
1407
|
-
* @param {CLIConfig} [config={}] - CLI configuration
|
|
1408
|
-
* @param {CLIContext} [context={}] - CLI context
|
|
1409
|
-
* @returns {{run: function(string[]): Promise<void>, generator: *}}
|
|
1410
|
-
*
|
|
1411
|
-
* @example
|
|
1412
|
-
* import { setupCLI } from '@happyvertical/smrt-virt-cli';
|
|
1413
|
-
*
|
|
1414
|
-
* const cli = setupCLI({
|
|
1415
|
-
* name: 'my-app',
|
|
1416
|
-
* version: '1.0.0'
|
|
1417
|
-
* });
|
|
1418
|
-
*
|
|
1419
|
-
* cli.run(process.argv);
|
|
1420
|
-
*/
|
|
1421
|
-
export function setupCLI(config = {}, context = {}) {
|
|
1422
|
-
const generator = new CLIGenerator(config, context);
|
|
1423
|
-
return {
|
|
1424
|
-
run: async (argv) => {
|
|
1425
|
-
const handler = generator.generateHandler();
|
|
1426
|
-
await handler(argv.slice(2)); // Remove 'node' and script name
|
|
1427
|
-
},
|
|
1428
|
-
generator
|
|
1429
|
-
};
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
/**
|
|
1433
|
-
* Get CLI handler directly
|
|
1434
|
-
*
|
|
1435
|
-
* @param {CLIConfig} [config={}] - CLI configuration
|
|
1436
|
-
* @param {CLIContext} [context={}] - CLI context
|
|
1437
|
-
* @returns {function(string[]): Promise<void>}
|
|
1438
|
-
*/
|
|
1439
|
-
export function getCLIHandler(config = {}, context = {}) {
|
|
1440
|
-
const generator = new CLIGenerator(config, context);
|
|
1441
|
-
return generator.generateHandler();
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
export default setupCLI;
|
|
1445
|
-
`;
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
console.warn("[smrt] Error generating CLI module:", error);
|
|
1448
|
-
return `
|
|
1449
|
-
// Error generating CLI module
|
|
1450
|
-
export const cliCommands = {};
|
|
1451
|
-
export function setupCLI() {
|
|
1452
|
-
console.warn("CLI generation failed");
|
|
1453
|
-
return { run: async () => {} };
|
|
1454
|
-
}
|
|
1455
|
-
export function getCLIHandler() {
|
|
1456
|
-
return async () => console.warn("CLI generation failed");
|
|
1457
|
-
}
|
|
1458
|
-
export default setupCLI;
|
|
1459
|
-
`;
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
1298
|
//#endregion
|
|
1463
1299
|
export { buildWebMcpToolDefinitions, findCliApiCoherenceViolations, generateInlineRegisterModule, generateSvelteKitRoutes, generateTypeDeclarationFile, isRegisterShimModuleId, loadVerifiedSmrtGenerationSnapshot, methodNameToKebab, resolveApiActionRouteConfig, resolveApiActionSet, serializeSmrtGenerationSnapshot, sha256SmrtGenerationSnapshot, smrtPlugin, toKnowledgeAgentSurface, validateCliIncludeAgainstApi };
|
|
1464
1300
|
|