@specverse/engines 6.5.4 → 6.6.3

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.
@@ -0,0 +1,84 @@
1
+ name: MongoDBNativeDriver
2
+ version: "1.0.0"
3
+ category: service
4
+ description: "Business logic services using the native MongoDB driver for collection access (no ORM layer)"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [services, business-logic, mongodb, native-driver, controllers]
10
+
11
+ compatibility:
12
+ specverse: ">=5.0.0"
13
+ node: ">=18.0.0"
14
+
15
+ # With the MongoDB native driver, collection access IS the data layer — there
16
+ # is no ORM layer to swap in independently. So this single factory provides
17
+ # both the "orm.client" capability AND the service-layer capabilities.
18
+ capabilities:
19
+ provides:
20
+ - "orm.schema" # Emits the MongoDB client connector (the client IS the schema layer)
21
+ - "orm.client"
22
+ - "orm.mongodb.native"
23
+ - "service.controller"
24
+ - "service.business"
25
+ - "service.crud"
26
+ requires:
27
+ - "storage.database.document"
28
+
29
+ technology:
30
+ runtime: "node"
31
+ language: "typescript"
32
+ orm: "mongodb-native"
33
+ version: "^6.0.0"
34
+
35
+ dependencies:
36
+ runtime:
37
+ - name: "mongodb"
38
+ version: "^6.3.0"
39
+
40
+ dev:
41
+ - name: "@types/node"
42
+ version: "^20.8.0"
43
+ - name: "typescript"
44
+ version: "^5.2.0"
45
+
46
+ codeTemplates:
47
+ # `schema` is the orm.schema-capability slot the realize engine drives for
48
+ # ORM-side artifacts. With Prisma this emits `schema.prisma`; with the
49
+ # MongoDB native driver there is no separate db-schema artifact, so this
50
+ # slot emits the singleton client connector instead — same intent
51
+ # ("how does the app reach the data layer"), different physical output.
52
+ schema:
53
+ engine: typescript
54
+ generator: "libs/instance-factories/services/templates/mongodb-native/client-generator.ts"
55
+ outputPattern: "{backendDir}/src/db/mongoClient.ts"
56
+
57
+ controllers:
58
+ engine: typescript
59
+ generator: "libs/instance-factories/services/templates/mongodb-native/controller-generator.ts"
60
+ outputPattern: "{backendDir}/src/controllers/{model}Controller.ts"
61
+
62
+ services:
63
+ engine: typescript
64
+ generator: "libs/instance-factories/services/templates/mongodb-native/service-generator.ts"
65
+ outputPattern: "{backendDir}/src/services/{service}.ts"
66
+
67
+ configuration:
68
+ outputStructure: "monorepo"
69
+ backendDir: "backend"
70
+ collectionNaming: "lowercase-pluralized" # User → users, OrderItem → orderitems
71
+ validation: true
72
+ eventPublishing: true
73
+ errorHandling: "throw"
74
+
75
+ requirements:
76
+ dependencies:
77
+ npm:
78
+ dependencies:
79
+ "mongodb": "^6.3.0"
80
+ environment:
81
+ - name: "MONGODB_URI"
82
+ description: "MongoDB connection string (e.g. mongodb://localhost:27017/myapp)"
83
+ required: true
84
+ configuration: {}
@@ -0,0 +1,43 @@
1
+ function generateMongoClient(_context) {
2
+ return `/**
3
+ * MongoDB native driver \u2014 singleton client + helpers.
4
+ *
5
+ * Picks up MONGODB_URI / MONGODB_DB from the environment. The client is
6
+ * lazily initialised on first use and reused across requests; \`disconnect\`
7
+ * is exposed for graceful-shutdown wiring.
8
+ */
9
+ import { MongoClient, type Db, type Collection, type Document } from 'mongodb';
10
+
11
+ const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';
12
+ const dbName = process.env.MONGODB_DB || 'specverse';
13
+
14
+ let client: MongoClient | null = null;
15
+ let database: Db | null = null;
16
+
17
+ export async function getDb(): Promise<Db> {
18
+ if (database) return database;
19
+ client = new MongoClient(uri);
20
+ await client.connect();
21
+ database = client.db(dbName);
22
+ return database;
23
+ }
24
+
25
+ export async function getCollection<T extends Document = Document>(
26
+ name: string,
27
+ ): Promise<Collection<T>> {
28
+ const db = await getDb();
29
+ return db.collection<T>(name);
30
+ }
31
+
32
+ export async function disconnect(): Promise<void> {
33
+ if (client) {
34
+ await client.close();
35
+ client = null;
36
+ database = null;
37
+ }
38
+ }
39
+ `;
40
+ }
41
+ export {
42
+ generateMongoClient as default
43
+ };
@@ -0,0 +1,259 @@
1
+ import { buildTransitionMap, isAutoField } from "@specverse/types/spec-rules";
2
+ function generateMongoNativeController(context) {
3
+ const { controller, model } = context;
4
+ if (!controller) throw new Error("Controller is required in template context");
5
+ if (!model) throw new Error("Model is required for controller generation");
6
+ const controllerName = controller.name;
7
+ const modelName = model.name;
8
+ const modelVar = lowerFirst(modelName);
9
+ const collection = collectionName(model);
10
+ const curedOps = controller.cured || {};
11
+ const customActions = generateCustomActions(controller, modelName);
12
+ const validate = generateValidateMethod(model, modelName);
13
+ const create = curedOps.create ? generateCreateMethod(model, modelName, modelVar, collection) : "";
14
+ const retrieve = curedOps.retrieve ? generateRetrieveMethod(modelName, modelVar, collection) : "";
15
+ const update = curedOps.update ? generateUpdateMethod(modelName, modelVar, collection) : "";
16
+ const evolve = curedOps.evolve ? generateEvolveMethod(model, modelName, modelVar, collection) : "";
17
+ const del = curedOps.delete ? generateDeleteMethod(modelName, modelVar, collection) : "";
18
+ const hasEventPublishing = curedOps.create || curedOps.update || curedOps.evolve || curedOps.delete;
19
+ return `/**
20
+ * ${controllerName}
21
+ * Model-specific business logic for ${modelName} (MongoDB native driver)
22
+ * ${controller.description || ""}
23
+ */
24
+ import { ObjectId, type Filter, type Document } from 'mongodb';
25
+ import { getCollection } from '../db/mongoClient.js';
26
+ ${hasEventPublishing ? `import { eventBus } from '../events/eventBus.js';` : ""}
27
+ ${customActions.needsAiBehaviors ? `import * as aiBehaviors from '../behaviors/${modelName}Controller.ai.js';` : ""}
28
+
29
+ const COLLECTION_NAME = '${collection}';
30
+
31
+ /** Parse an id string to the value the collection expects: ObjectId for
32
+ * 24-hex-character ids, otherwise pass-through (UUIDs, slugs, ints-as-string). */
33
+ function parseId(id: string): ObjectId | string {
34
+ if (typeof id === 'string' && /^[a-fA-F0-9]{24}$/.test(id)) return new ObjectId(id);
35
+ return id;
36
+ }
37
+
38
+ /** _id-aware filter builder. */
39
+ function byId(id: string): Filter<Document> {
40
+ return { _id: parseId(id) as any };
41
+ }
42
+
43
+ export class ${controllerName} {
44
+ ${validate}
45
+ ${create}
46
+ ${retrieve}
47
+ ${update}
48
+ ${evolve}
49
+ ${del}
50
+ ${customActions.code}
51
+ }
52
+
53
+ export const ${modelVar}Controller = new ${controllerName}();
54
+ export default ${modelVar}Controller;
55
+ `;
56
+ }
57
+ function lowerFirst(s) {
58
+ return s.charAt(0).toLowerCase() + s.slice(1);
59
+ }
60
+ function collectionName(model) {
61
+ if (model?.storage?.collection) return String(model.storage.collection);
62
+ return model.name.toLowerCase() + "s";
63
+ }
64
+ function generateValidateMethod(model, modelName) {
65
+ return `
66
+ /**
67
+ * Validate ${modelName} data \u2014 runs before create / update / evolve.
68
+ */
69
+ public validate(
70
+ _data: any,
71
+ _context: { operation: 'create' | 'update' | 'evolve' }
72
+ ): { valid: boolean; errors: string[] } {
73
+ const errors: string[] = [];
74
+ ${generateValidationLogic(model)}
75
+ return { valid: errors.length === 0, errors };
76
+ }
77
+ `;
78
+ }
79
+ function generateValidationLogic(model) {
80
+ if (!model.attributes) return " // No validation rules defined";
81
+ const attrList = Array.isArray(model.attributes) ? model.attributes.map((a) => [a.name, a]) : Object.entries(model.attributes);
82
+ const out = [];
83
+ attrList.forEach(([name, attr]) => {
84
+ if (attr.required && !isAutoField(name, attr)) {
85
+ out.push(` if (_context.operation === 'create' && !_data.${name}) errors.push('${name} is required');`);
86
+ }
87
+ if (attr.type === "String" || attr.type === "string") {
88
+ if (attr.min) out.push(` if (_data.${name} && _data.${name}.length < ${attr.min}) errors.push('${name} must be at least ${attr.min} characters');`);
89
+ if (attr.max) out.push(` if (_data.${name} && _data.${name}.length > ${attr.max}) errors.push('${name} must be at most ${attr.max} characters');`);
90
+ }
91
+ if (attr.values && Array.isArray(attr.values)) {
92
+ const values = attr.values.map((v) => `'${v}'`).join(", ");
93
+ out.push(` if (_data.${name} && ![${values}].includes(_data.${name})) errors.push('${name} must be one of: ${attr.values.join(", ")}');`);
94
+ }
95
+ if (attr.format === "email") {
96
+ out.push(` if (_data.${name} && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(_data.${name})) errors.push('${name} must be a valid email address');`);
97
+ }
98
+ });
99
+ return out.join("\n") || " // No validation rules defined";
100
+ }
101
+ function generateCreateMethod(model, modelName, modelVar, collection) {
102
+ return `
103
+ /**
104
+ * Create a new ${modelName}.
105
+ */
106
+ public async create(data: any): Promise<any> {
107
+ const validation = this.validate(data, { operation: 'create' });
108
+ if (!validation.valid) throw new Error(\`Validation failed: \${validation.errors.join(', ')}\`);
109
+
110
+ const collection = await getCollection('${collection}');
111
+ const result = await collection.insertOne({ ...data });
112
+ const ${modelVar} = { _id: result.insertedId, ...data };
113
+
114
+ await eventBus.publish('${modelName}Created', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
115
+ return ${modelVar};
116
+ }
117
+ `;
118
+ }
119
+ function generateRetrieveMethod(modelName, modelVar, collection) {
120
+ return `
121
+ /**
122
+ * Retrieve ${modelName} by id. Returns null when not found.
123
+ */
124
+ public async retrieve(id: string): Promise<any | null> {
125
+ const collection = await getCollection('${collection}');
126
+ return await collection.findOne(byId(id));
127
+ }
128
+
129
+ /**
130
+ * Retrieve a page of ${modelName}s.
131
+ */
132
+ public async retrieveAll(options: { skip?: number; take?: number } = {}): Promise<any[]> {
133
+ const collection = await getCollection('${collection}');
134
+ const cursor = collection.find({});
135
+ if (options.skip) cursor.skip(options.skip);
136
+ if (options.take) cursor.limit(options.take);
137
+ return await cursor.toArray();
138
+ }
139
+ `;
140
+ }
141
+ function generateUpdateMethod(modelName, modelVar, collection) {
142
+ return `
143
+ /**
144
+ * Update ${modelName}.
145
+ */
146
+ public async update(id: string, data: any): Promise<any> {
147
+ const validation = this.validate(data, { operation: 'update' });
148
+ if (!validation.valid) throw new Error(\`Validation failed: \${validation.errors.join(', ')}\`);
149
+
150
+ // Strip nested objects + id \u2014 only scalar fields are written.
151
+ const updateData: any = {};
152
+ for (const [key, value] of Object.entries(data)) {
153
+ if (key === 'id' || key === '_id') continue;
154
+ if (Array.isArray(value)) continue;
155
+ if (value !== null && typeof value === 'object' && !(value instanceof Date)) continue;
156
+ updateData[key] = value;
157
+ }
158
+
159
+ const collection = await getCollection('${collection}');
160
+ await collection.updateOne(byId(id), { $set: updateData });
161
+ const ${modelVar} = await collection.findOne(byId(id));
162
+ if (!${modelVar}) throw new Error('${modelName} not found after update');
163
+
164
+ await eventBus.publish('${modelName}Updated', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
165
+ return ${modelVar};
166
+ }
167
+ `;
168
+ }
169
+ function generateEvolveMethod(model, modelName, modelVar, collection) {
170
+ const lifecycles = Array.isArray(model.lifecycles) ? model.lifecycles : model.lifecycles ? Object.entries(model.lifecycles).map(([name, lc]) => ({ name, ...lc })) : [];
171
+ const lifecycle = lifecycles[0];
172
+ const lifecycleName = lifecycle?.name || "status";
173
+ const validTransitions = lifecycle ? buildTransitionMap(lifecycle) : {};
174
+ const states = lifecycle?.states && lifecycle.states.length > 0 ? lifecycle.states.map((s) => typeof s === "string" ? s : s.name) : Array.from(/* @__PURE__ */ new Set([
175
+ ...Object.keys(validTransitions),
176
+ ...Object.values(validTransitions).flat()
177
+ ]));
178
+ return `
179
+ /**
180
+ * Evolve ${modelName} through lifecycle "${lifecycleName}"
181
+ * States: ${states.join(" \u2192 ") || "(none declared)"}
182
+ */
183
+ public async evolve(id: string, data: any): Promise<any> {
184
+ const collection = await getCollection('${collection}');
185
+ const current = await collection.findOne(byId(id));
186
+ if (!current) throw new Error('${modelName} not found');
187
+
188
+ const targetLifecycle = data?.lifecycleName || '${lifecycleName}';
189
+ const targetState = data?.toState ?? data?.state ?? data?.[targetLifecycle];
190
+ if (!targetState) throw new Error('evolve requires toState (or ${lifecycleName}) in the request body');
191
+
192
+ ${states.length > 0 ? `
193
+ const currentState = (current as any)[targetLifecycle];
194
+ const validTransitions: Record<string, string[]> = ${JSON.stringify(validTransitions)};
195
+ const allowed = validTransitions[currentState] || [];
196
+ if (!allowed.includes(targetState)) {
197
+ throw new Error(\`Invalid transition: \${currentState} \u2192 \${targetState}. Allowed: \${allowed.join(', ') || 'none'}\`);
198
+ }
199
+ ` : ""}
200
+
201
+ await collection.updateOne(byId(id), { $set: { [targetLifecycle]: targetState } });
202
+ const ${modelVar} = await collection.findOne(byId(id));
203
+ if (!${modelVar}) throw new Error('${modelName} not found after evolve');
204
+
205
+ await eventBus.publish('${modelName}Evolved', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
206
+ return ${modelVar};
207
+ }
208
+ `;
209
+ }
210
+ function generateDeleteMethod(modelName, modelVar, collection) {
211
+ return `
212
+ /**
213
+ * Delete ${modelName}.
214
+ */
215
+ public async delete(id: string): Promise<void> {
216
+ const collection = await getCollection('${collection}');
217
+ const ${modelVar} = await collection.findOne(byId(id));
218
+ await collection.deleteOne(byId(id));
219
+ if (${modelVar}) {
220
+ await eventBus.publish('${modelName}Deleted', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
221
+ }
222
+ }
223
+ `;
224
+ }
225
+ function generateCustomActions(controller, modelName) {
226
+ if (!controller.actions || Object.keys(controller.actions).length === 0) {
227
+ return { code: "", needsAiBehaviors: false };
228
+ }
229
+ const out = [];
230
+ for (const [actionName, action] of Object.entries(controller.actions)) {
231
+ const params = generateActionParams(action);
232
+ const stepsHeader = action.steps && action.steps.length > 0 ? action.steps.map((s) => ` * - ${typeof s === "string" ? s : s.action || JSON.stringify(s)}`).join("\n") : " * (no spec steps declared)";
233
+ out.push(`
234
+ /**
235
+ * ${actionName}
236
+ * ${action.description || ""}
237
+ *
238
+ * Spec steps:
239
+ ${stepsHeader}
240
+ */
241
+ public async ${actionName}(${params}): Promise<any> {
242
+ return await aiBehaviors.${actionName}({ controller: this, ...args });
243
+ }
244
+ `);
245
+ }
246
+ return { code: out.join("\n"), needsAiBehaviors: true };
247
+ }
248
+ function generateActionParams(action) {
249
+ if (Array.isArray(action.parameters) && action.parameters.length > 0) {
250
+ return "args: any";
251
+ }
252
+ if (action.parameters && typeof action.parameters === "object" && Object.keys(action.parameters).length > 0) {
253
+ return "args: any";
254
+ }
255
+ return "args: any = {}";
256
+ }
257
+ export {
258
+ generateMongoNativeController as default
259
+ };
@@ -0,0 +1,64 @@
1
+ function generateMongoNativeService(context) {
2
+ const { service } = context;
3
+ if (!service) throw new Error("Service is required in template context");
4
+ const serviceName = service.name;
5
+ const operationsCode = generateOperations(service);
6
+ const usesDb = /\bgetDb\b|\bgetCollection\b/.test(operationsCode);
7
+ const hasEvents = service.publishes && service.publishes.length > 0 || service.subscribes && service.subscribes.length > 0;
8
+ return `/**
9
+ * ${serviceName}
10
+ * Abstract business logic service (MongoDB native driver)
11
+ * ${service.description || ""}
12
+ */
13
+ ${usesDb ? `import { getDb, getCollection } from '../db/mongoClient.js';` : ""}
14
+ ${hasEvents ? `import { eventBus } from '../events/eventBus.js';` : ""}
15
+
16
+ export class ${serviceName} {
17
+ ${operationsCode}
18
+ }
19
+
20
+ const ${lowerFirst(serviceName)} = new ${serviceName}();
21
+ export const ${lowerFirst(serviceName)}Instance = ${lowerFirst(serviceName)};
22
+ export default ${lowerFirst(serviceName)};
23
+ `;
24
+ }
25
+ function lowerFirst(s) {
26
+ return s.charAt(0).toLowerCase() + s.slice(1);
27
+ }
28
+ function generateOperations(service) {
29
+ const ops = service.operations;
30
+ if (!ops || Array.isArray(ops) && ops.length === 0 || !Array.isArray(ops) && Object.keys(ops).length === 0) {
31
+ return `
32
+ /**
33
+ * Default service entrypoint \u2014 replace with real operations once declared
34
+ * on the service's spec.
35
+ */
36
+ public async execute(_params: any = {}): Promise<any> {
37
+ throw new Error('${service.name}.execute is not implemented');
38
+ }
39
+ `;
40
+ }
41
+ const entries = Array.isArray(ops) ? ops.map((op) => [op.name, op]) : Object.entries(ops);
42
+ return entries.map(([name, op]) => generateOperation(name, op, service.name)).join("\n");
43
+ }
44
+ function generateOperation(operationName, operation, serviceName) {
45
+ const stepsHeader = operation.steps && operation.steps.length > 0 ? operation.steps.map((s) => ` * - ${typeof s === "string" ? s : s.action || JSON.stringify(s)}`).join("\n") : " * (no spec steps declared)";
46
+ return `
47
+ /**
48
+ * ${operationName}
49
+ * ${operation.description || ""}
50
+ *
51
+ * Spec steps:
52
+ ${stepsHeader}
53
+ */
54
+ public async ${operationName}(_args: any = {}): Promise<any> {
55
+ // TODO (#43 follow-up): translate spec steps into native MongoDB driver
56
+ // calls. For now this is a stub so realize completes and the service
57
+ // surface is callable for parity tests.
58
+ throw new Error('${serviceName}.${operationName} is not implemented');
59
+ }
60
+ `;
61
+ }
62
+ export {
63
+ generateMongoNativeService as default
64
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../../src/realize/library/library.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../../src/realize/library/library.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAkD,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAEvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iCAAiC;IACjC,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,OAAO,CAAuB;;IAMtC;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB9F;;OAEG;IACG,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC9D;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAqBrE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE;IAK5C;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO;IAIjD;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,EAAE;IA8E5C;;OAEG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,EAAE;IAIvD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,GAAG,eAAe,EAAE;IAIxE;;OAEG;IACH,QAAQ,IAAI,MAAM,EAAE;IAIpB;;OAEG;IACH,IAAI,IAAI,MAAM;IAQd;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,QAAQ,CACN,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;KAClC,GACA,mBAAmB;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAqBjD;;;OAGG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAuCxD;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,QAAQ,IAAI;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtC;CAyBF;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAuDhG"}
@@ -48,6 +48,17 @@ export class InstanceFactoryLibrary {
48
48
  // Sort by priority (highest first)
49
49
  const sortedSources = [...sources].sort((a, b) => (b.priority || 0) - (a.priority || 0));
50
50
  const result = await loadFromMultipleSources(sortedSources.map(s => ({ path: s.path })), { validate: true, ignoreInvalid: true });
51
+ // Surface validation errors as warnings so a malformed factory doesn't
52
+ // disappear without a trace. ignoreInvalid: true means we keep loading
53
+ // the other factories — but the user still needs to see WHY one was
54
+ // dropped (otherwise the symptom is a confusing "Unknown factory X" at
55
+ // the manifest stage with no hint that the yaml was rejected upstream).
56
+ if (result.errors && result.errors.length > 0) {
57
+ for (const err of result.errors) {
58
+ const lines = (err.errors || []).map(e => ` - ${e}`).join('\n');
59
+ console.warn(`⚠️ Skipped instance factory ${err.filePath}\n${lines}`);
60
+ }
61
+ }
51
62
  // Add to library
52
63
  for (const loadResult of result.types) {
53
64
  const name = loadResult.type.name;
@@ -1 +1 @@
1
- {"version":3,"file":"library.js","sourceRoot":"","sources":["../../../src/realize/library/library.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"library.js","sourceRoot":"","sources":["../../../src/realize/library/library.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ name: MongoDBNativeDriver
2
+ version: "1.0.0"
3
+ category: service
4
+ description: "Business logic services using the native MongoDB driver for collection access (no ORM layer)"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [services, business-logic, mongodb, native-driver, controllers]
10
+
11
+ compatibility:
12
+ specverse: ">=5.0.0"
13
+ node: ">=18.0.0"
14
+
15
+ # With the MongoDB native driver, collection access IS the data layer — there
16
+ # is no ORM layer to swap in independently. So this single factory provides
17
+ # both the "orm.client" capability AND the service-layer capabilities.
18
+ capabilities:
19
+ provides:
20
+ - "orm.schema" # Emits the MongoDB client connector (the client IS the schema layer)
21
+ - "orm.client"
22
+ - "orm.mongodb.native"
23
+ - "service.controller"
24
+ - "service.business"
25
+ - "service.crud"
26
+ requires:
27
+ - "storage.database.document"
28
+
29
+ technology:
30
+ runtime: "node"
31
+ language: "typescript"
32
+ orm: "mongodb-native"
33
+ version: "^6.0.0"
34
+
35
+ dependencies:
36
+ runtime:
37
+ - name: "mongodb"
38
+ version: "^6.3.0"
39
+
40
+ dev:
41
+ - name: "@types/node"
42
+ version: "^20.8.0"
43
+ - name: "typescript"
44
+ version: "^5.2.0"
45
+
46
+ codeTemplates:
47
+ # `schema` is the orm.schema-capability slot the realize engine drives for
48
+ # ORM-side artifacts. With Prisma this emits `schema.prisma`; with the
49
+ # MongoDB native driver there is no separate db-schema artifact, so this
50
+ # slot emits the singleton client connector instead — same intent
51
+ # ("how does the app reach the data layer"), different physical output.
52
+ schema:
53
+ engine: typescript
54
+ generator: "libs/instance-factories/services/templates/mongodb-native/client-generator.ts"
55
+ outputPattern: "{backendDir}/src/db/mongoClient.ts"
56
+
57
+ controllers:
58
+ engine: typescript
59
+ generator: "libs/instance-factories/services/templates/mongodb-native/controller-generator.ts"
60
+ outputPattern: "{backendDir}/src/controllers/{model}Controller.ts"
61
+
62
+ services:
63
+ engine: typescript
64
+ generator: "libs/instance-factories/services/templates/mongodb-native/service-generator.ts"
65
+ outputPattern: "{backendDir}/src/services/{service}.ts"
66
+
67
+ configuration:
68
+ outputStructure: "monorepo"
69
+ backendDir: "backend"
70
+ collectionNaming: "lowercase-pluralized" # User → users, OrderItem → orderitems
71
+ validation: true
72
+ eventPublishing: true
73
+ errorHandling: "throw"
74
+
75
+ requirements:
76
+ dependencies:
77
+ npm:
78
+ dependencies:
79
+ "mongodb": "^6.3.0"
80
+ environment:
81
+ - name: "MONGODB_URI"
82
+ description: "MongoDB connection string (e.g. mongodb://localhost:27017/myapp)"
83
+ required: true
84
+ configuration: {}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Regression tests for the MongoDB native driver controller generator (TODO #43).
3
+ *
4
+ * Pins the generator's output for the headline shapes:
5
+ * - CURVED ops emit native-driver collection access (insertOne, findOne,
6
+ * updateOne, deleteOne, find().toArray())
7
+ * - Lifecycle transitions decode flow shorthand and emit a transition map
8
+ * (the buildTransitionMap path was the bug that hid `pending -> done`
9
+ * from evolve before #43)
10
+ * - Controller surfaces compile cleanly under strict-ish tsc (smoke is
11
+ * the realize harness; this file pins shape, not full compilation)
12
+ */
13
+ import { describe, it, expect } from 'vitest';
14
+ import generateMongoNativeController from '../controller-generator.js';
15
+
16
+ const baseModel = {
17
+ name: 'Todo',
18
+ attributes: {
19
+ id: { name: 'id', type: 'UUID', required: true, auto: 'uuid4' },
20
+ title: { name: 'title', type: 'String', required: true },
21
+ completed: { name: 'completed', type: 'Boolean', default: false },
22
+ },
23
+ };
24
+
25
+ const baseController = {
26
+ name: 'TodoController',
27
+ description: 'Controller for Todo',
28
+ cured: { create: true, retrieve: true, update: true, evolve: true, delete: true },
29
+ };
30
+
31
+ describe('MongoDB native — controller-generator', () => {
32
+ it('emits all CURVED ops via collection access', () => {
33
+ const out = generateMongoNativeController({
34
+ controller: baseController,
35
+ model: baseModel,
36
+ } as any);
37
+ expect(out).toContain(`COLLECTION_NAME = 'todos'`);
38
+ expect(out).toContain('insertOne');
39
+ expect(out).toContain('findOne');
40
+ expect(out).toContain('updateOne');
41
+ expect(out).toContain('deleteOne');
42
+ expect(out).toContain('cursor.toArray');
43
+ expect(out).not.toContain('PrismaClient');
44
+ expect(out).not.toContain('prisma.');
45
+ });
46
+
47
+ it('parses ObjectId-shaped ids and falls through for UUID/string ids', () => {
48
+ const out = generateMongoNativeController({
49
+ controller: baseController,
50
+ model: baseModel,
51
+ } as any);
52
+ expect(out).toContain(`/^[a-fA-F0-9]{24}$/.test(id)`);
53
+ expect(out).toContain('new ObjectId(id)');
54
+ });
55
+
56
+ it('emits lifecycle transition map even when spec used `flow:` shorthand only', () => {
57
+ // Regression: pre-fix, lifecycle.states was undefined when the spec
58
+ // declared only `flow: "pending -> done"` (states are derived at parse-
59
+ // time, but the inferred YAML keeps the flow string). The evolve gate
60
+ // skipped the transition check because `states.length > 0` was false.
61
+ const out = generateMongoNativeController({
62
+ controller: baseController,
63
+ model: {
64
+ ...baseModel,
65
+ lifecycles: { status: { name: 'status', flow: 'pending -> done' } },
66
+ },
67
+ } as any);
68
+ expect(out).toContain('public async evolve(');
69
+ expect(out).toContain('"pending":["done"]');
70
+ expect(out).toContain('Invalid transition');
71
+ });
72
+
73
+ it('emits a working multi-state transition map for explicit states', () => {
74
+ const out = generateMongoNativeController({
75
+ controller: baseController,
76
+ model: {
77
+ ...baseModel,
78
+ lifecycles: {
79
+ status: {
80
+ name: 'status',
81
+ states: ['draft', 'open', 'closed'],
82
+ transitions: { open: 'draft -> open', close: 'open -> closed' },
83
+ },
84
+ },
85
+ },
86
+ } as any);
87
+ expect(out).toContain('"draft":["open"]');
88
+ expect(out).toContain('"open":["closed"]');
89
+ });
90
+
91
+ it('uses model.storage.collection override when present', () => {
92
+ const out = generateMongoNativeController({
93
+ controller: baseController,
94
+ model: { ...baseModel, storage: { collection: 'custom_todos' } },
95
+ } as any);
96
+ expect(out).toContain(`COLLECTION_NAME = 'custom_todos'`);
97
+ expect(out).toContain(`getCollection('custom_todos')`);
98
+ });
99
+
100
+ it('omits CURVED ops not declared on the controller', () => {
101
+ const out = generateMongoNativeController({
102
+ controller: { ...baseController, cured: { retrieve: true } },
103
+ model: baseModel,
104
+ } as any);
105
+ expect(out).toContain('public async retrieve(');
106
+ expect(out).not.toContain('public async create(');
107
+ expect(out).not.toContain('public async update(');
108
+ expect(out).not.toContain('public async delete(');
109
+ expect(out).not.toContain('public async evolve(');
110
+ });
111
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * MongoDB Native Driver — client singleton
3
+ *
4
+ * Emits a small connection module shared by all controllers and services.
5
+ * Collection naming convention: lowercase + 's' suffix (User → users,
6
+ * Category → categorys), matching the lowercase-pluralized scheme declared
7
+ * in the factory yaml. Models with custom collection names can override
8
+ * via spec — the controller-generator looks at `model.storage?.collection`.
9
+ */
10
+ import type { TemplateContext } from '@specverse/types';
11
+
12
+ export default function generateMongoClient(_context: TemplateContext): string {
13
+ return `/**
14
+ * MongoDB native driver — singleton client + helpers.
15
+ *
16
+ * Picks up MONGODB_URI / MONGODB_DB from the environment. The client is
17
+ * lazily initialised on first use and reused across requests; \`disconnect\`
18
+ * is exposed for graceful-shutdown wiring.
19
+ */
20
+ import { MongoClient, type Db, type Collection, type Document } from 'mongodb';
21
+
22
+ const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';
23
+ const dbName = process.env.MONGODB_DB || 'specverse';
24
+
25
+ let client: MongoClient | null = null;
26
+ let database: Db | null = null;
27
+
28
+ export async function getDb(): Promise<Db> {
29
+ if (database) return database;
30
+ client = new MongoClient(uri);
31
+ await client.connect();
32
+ database = client.db(dbName);
33
+ return database;
34
+ }
35
+
36
+ export async function getCollection<T extends Document = Document>(
37
+ name: string,
38
+ ): Promise<Collection<T>> {
39
+ const db = await getDb();
40
+ return db.collection<T>(name);
41
+ }
42
+
43
+ export async function disconnect(): Promise<void> {
44
+ if (client) {
45
+ await client.close();
46
+ client = null;
47
+ database = null;
48
+ }
49
+ }
50
+ `;
51
+ }
@@ -0,0 +1,316 @@
1
+ /**
2
+ * MongoDB Native Driver — Controller Generator
3
+ *
4
+ * Generates per-model controllers exposing CURVED operations via the native
5
+ * MongoDB driver (collection-level insertOne / findOne / updateOne / deleteOne).
6
+ *
7
+ * Scope (MVP — TODO #43):
8
+ * - Validate / Create / Retrieve / Update / Delete fully wired
9
+ * - Evolve emits a lifecycle-aware update when the model declares states;
10
+ * transitions are validated against the declared flow before update
11
+ * - Custom actions emit AI-behavior stubs (callable, but the body is left
12
+ * as a TODO with the spec steps inline) — same pattern Prisma uses
13
+ *
14
+ * Out of scope here (deferred follow-up TODOs):
15
+ * - $transaction wrapping for multi-document writes (MongoDB sessions)
16
+ * - Aggregation-pipeline-driven retrieve variants (joins via $lookup)
17
+ * - Inline behavior-step → driver-call generation parity with the
18
+ * prisma step-conventions library
19
+ *
20
+ * Collection naming: lowercase + 's' (User → users) unless the model
21
+ * declares `storage.collection`. ID field is ObjectId-aware: a 24-hex
22
+ * string is parsed via `new ObjectId(id)`; anything else is kept as-is so
23
+ * specs that use string ids (UUIDs, slugs) keep working unchanged.
24
+ */
25
+ import type { TemplateContext } from '@specverse/types';
26
+ import { buildTransitionMap, isAutoField } from '@specverse/types/spec-rules';
27
+
28
+ export default function generateMongoNativeController(context: TemplateContext): string {
29
+ const { controller, model } = context;
30
+ if (!controller) throw new Error('Controller is required in template context');
31
+ if (!model) throw new Error('Model is required for controller generation');
32
+
33
+ const controllerName = controller.name;
34
+ const modelName = model.name;
35
+ const modelVar = lowerFirst(modelName);
36
+ const collection = collectionName(model);
37
+ const curedOps = controller.cured || {};
38
+
39
+ const customActions = generateCustomActions(controller, modelName);
40
+
41
+ const validate = generateValidateMethod(model, modelName);
42
+ const create = curedOps.create ? generateCreateMethod(model, modelName, modelVar, collection) : '';
43
+ const retrieve = curedOps.retrieve ? generateRetrieveMethod(modelName, modelVar, collection) : '';
44
+ const update = curedOps.update ? generateUpdateMethod(modelName, modelVar, collection) : '';
45
+ const evolve = curedOps.evolve ? generateEvolveMethod(model, modelName, modelVar, collection) : '';
46
+ const del = curedOps.delete ? generateDeleteMethod(modelName, modelVar, collection) : '';
47
+
48
+ const hasEventPublishing =
49
+ curedOps.create || curedOps.update || curedOps.evolve || curedOps.delete;
50
+
51
+ return `/**
52
+ * ${controllerName}
53
+ * Model-specific business logic for ${modelName} (MongoDB native driver)
54
+ * ${controller.description || ''}
55
+ */
56
+ import { ObjectId, type Filter, type Document } from 'mongodb';
57
+ import { getCollection } from '../db/mongoClient.js';
58
+ ${hasEventPublishing ? `import { eventBus } from '../events/eventBus.js';` : ''}
59
+ ${customActions.needsAiBehaviors ? `import * as aiBehaviors from '../behaviors/${modelName}Controller.ai.js';` : ''}
60
+
61
+ const COLLECTION_NAME = '${collection}';
62
+
63
+ /** Parse an id string to the value the collection expects: ObjectId for
64
+ * 24-hex-character ids, otherwise pass-through (UUIDs, slugs, ints-as-string). */
65
+ function parseId(id: string): ObjectId | string {
66
+ if (typeof id === 'string' && /^[a-fA-F0-9]{24}$/.test(id)) return new ObjectId(id);
67
+ return id;
68
+ }
69
+
70
+ /** _id-aware filter builder. */
71
+ function byId(id: string): Filter<Document> {
72
+ return { _id: parseId(id) as any };
73
+ }
74
+
75
+ export class ${controllerName} {
76
+ ${validate}
77
+ ${create}
78
+ ${retrieve}
79
+ ${update}
80
+ ${evolve}
81
+ ${del}
82
+ ${customActions.code}
83
+ }
84
+
85
+ export const ${modelVar}Controller = new ${controllerName}();
86
+ export default ${modelVar}Controller;
87
+ `;
88
+ }
89
+
90
+ function lowerFirst(s: string): string {
91
+ return s.charAt(0).toLowerCase() + s.slice(1);
92
+ }
93
+
94
+ function collectionName(model: any): string {
95
+ if (model?.storage?.collection) return String(model.storage.collection);
96
+ // Lowercase-pluralized: User → users, OrderItem → orderitems
97
+ return model.name.toLowerCase() + 's';
98
+ }
99
+
100
+ function generateValidateMethod(model: any, modelName: string): string {
101
+ return `
102
+ /**
103
+ * Validate ${modelName} data — runs before create / update / evolve.
104
+ */
105
+ public validate(
106
+ _data: any,
107
+ _context: { operation: 'create' | 'update' | 'evolve' }
108
+ ): { valid: boolean; errors: string[] } {
109
+ const errors: string[] = [];
110
+ ${generateValidationLogic(model)}
111
+ return { valid: errors.length === 0, errors };
112
+ }
113
+ `;
114
+ }
115
+
116
+ function generateValidationLogic(model: any): string {
117
+ if (!model.attributes) return ' // No validation rules defined';
118
+ const attrList = Array.isArray(model.attributes)
119
+ ? model.attributes.map((a: any) => [a.name, a])
120
+ : Object.entries(model.attributes);
121
+ const out: string[] = [];
122
+ attrList.forEach(([name, attr]: [string, any]) => {
123
+ if (attr.required && !isAutoField(name, attr)) {
124
+ out.push(` if (_context.operation === 'create' && !_data.${name}) errors.push('${name} is required');`);
125
+ }
126
+ if (attr.type === 'String' || attr.type === 'string') {
127
+ if (attr.min) out.push(` if (_data.${name} && _data.${name}.length < ${attr.min}) errors.push('${name} must be at least ${attr.min} characters');`);
128
+ if (attr.max) out.push(` if (_data.${name} && _data.${name}.length > ${attr.max}) errors.push('${name} must be at most ${attr.max} characters');`);
129
+ }
130
+ if (attr.values && Array.isArray(attr.values)) {
131
+ const values = attr.values.map((v: string) => `'${v}'`).join(', ');
132
+ out.push(` if (_data.${name} && ![${values}].includes(_data.${name})) errors.push('${name} must be one of: ${attr.values.join(', ')}');`);
133
+ }
134
+ if (attr.format === 'email') {
135
+ out.push(` if (_data.${name} && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(_data.${name})) errors.push('${name} must be a valid email address');`);
136
+ }
137
+ });
138
+ return out.join('\n') || ' // No validation rules defined';
139
+ }
140
+
141
+ function generateCreateMethod(model: any, modelName: string, modelVar: string, collection: string): string {
142
+ return `
143
+ /**
144
+ * Create a new ${modelName}.
145
+ */
146
+ public async create(data: any): Promise<any> {
147
+ const validation = this.validate(data, { operation: 'create' });
148
+ if (!validation.valid) throw new Error(\`Validation failed: \${validation.errors.join(', ')}\`);
149
+
150
+ const collection = await getCollection('${collection}');
151
+ const result = await collection.insertOne({ ...data });
152
+ const ${modelVar} = { _id: result.insertedId, ...data };
153
+
154
+ await eventBus.publish('${modelName}Created', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
155
+ return ${modelVar};
156
+ }
157
+ `;
158
+ }
159
+
160
+ function generateRetrieveMethod(modelName: string, modelVar: string, collection: string): string {
161
+ return `
162
+ /**
163
+ * Retrieve ${modelName} by id. Returns null when not found.
164
+ */
165
+ public async retrieve(id: string): Promise<any | null> {
166
+ const collection = await getCollection('${collection}');
167
+ return await collection.findOne(byId(id));
168
+ }
169
+
170
+ /**
171
+ * Retrieve a page of ${modelName}s.
172
+ */
173
+ public async retrieveAll(options: { skip?: number; take?: number } = {}): Promise<any[]> {
174
+ const collection = await getCollection('${collection}');
175
+ const cursor = collection.find({});
176
+ if (options.skip) cursor.skip(options.skip);
177
+ if (options.take) cursor.limit(options.take);
178
+ return await cursor.toArray();
179
+ }
180
+ `;
181
+ }
182
+
183
+ function generateUpdateMethod(modelName: string, modelVar: string, collection: string): string {
184
+ return `
185
+ /**
186
+ * Update ${modelName}.
187
+ */
188
+ public async update(id: string, data: any): Promise<any> {
189
+ const validation = this.validate(data, { operation: 'update' });
190
+ if (!validation.valid) throw new Error(\`Validation failed: \${validation.errors.join(', ')}\`);
191
+
192
+ // Strip nested objects + id — only scalar fields are written.
193
+ const updateData: any = {};
194
+ for (const [key, value] of Object.entries(data)) {
195
+ if (key === 'id' || key === '_id') continue;
196
+ if (Array.isArray(value)) continue;
197
+ if (value !== null && typeof value === 'object' && !(value instanceof Date)) continue;
198
+ updateData[key] = value;
199
+ }
200
+
201
+ const collection = await getCollection('${collection}');
202
+ await collection.updateOne(byId(id), { $set: updateData });
203
+ const ${modelVar} = await collection.findOne(byId(id));
204
+ if (!${modelVar}) throw new Error('${modelName} not found after update');
205
+
206
+ await eventBus.publish('${modelName}Updated', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
207
+ return ${modelVar};
208
+ }
209
+ `;
210
+ }
211
+
212
+ function generateEvolveMethod(model: any, modelName: string, modelVar: string, collection: string): string {
213
+ const lifecycles = Array.isArray(model.lifecycles)
214
+ ? model.lifecycles
215
+ : (model.lifecycles ? Object.entries(model.lifecycles).map(([name, lc]: [string, any]) => ({ name, ...lc })) : []);
216
+ const lifecycle = lifecycles[0];
217
+ const lifecycleName = lifecycle?.name || 'status';
218
+ const validTransitions = lifecycle ? buildTransitionMap(lifecycle) : {};
219
+ // Derive states from the transition map when the spec used `flow:` shorthand
220
+ // (states is undefined on the wire, but buildTransitionMap expands the flow).
221
+ const states = lifecycle?.states && lifecycle.states.length > 0
222
+ ? lifecycle.states.map((s: any) => typeof s === 'string' ? s : s.name)
223
+ : Array.from(new Set([
224
+ ...Object.keys(validTransitions),
225
+ ...Object.values(validTransitions).flat(),
226
+ ]));
227
+
228
+ return `
229
+ /**
230
+ * Evolve ${modelName} through lifecycle "${lifecycleName}"
231
+ * States: ${states.join(' → ') || '(none declared)'}
232
+ */
233
+ public async evolve(id: string, data: any): Promise<any> {
234
+ const collection = await getCollection('${collection}');
235
+ const current = await collection.findOne(byId(id));
236
+ if (!current) throw new Error('${modelName} not found');
237
+
238
+ const targetLifecycle = data?.lifecycleName || '${lifecycleName}';
239
+ const targetState = data?.toState ?? data?.state ?? data?.[targetLifecycle];
240
+ if (!targetState) throw new Error('evolve requires toState (or ${lifecycleName}) in the request body');
241
+
242
+ ${states.length > 0 ? `
243
+ const currentState = (current as any)[targetLifecycle];
244
+ const validTransitions: Record<string, string[]> = ${JSON.stringify(validTransitions)};
245
+ const allowed = validTransitions[currentState] || [];
246
+ if (!allowed.includes(targetState)) {
247
+ throw new Error(\`Invalid transition: \${currentState} → \${targetState}. Allowed: \${allowed.join(', ') || 'none'}\`);
248
+ }
249
+ ` : ''}
250
+
251
+ await collection.updateOne(byId(id), { $set: { [targetLifecycle]: targetState } });
252
+ const ${modelVar} = await collection.findOne(byId(id));
253
+ if (!${modelVar}) throw new Error('${modelName} not found after evolve');
254
+
255
+ await eventBus.publish('${modelName}Evolved', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
256
+ return ${modelVar};
257
+ }
258
+ `;
259
+ }
260
+
261
+ function generateDeleteMethod(modelName: string, modelVar: string, collection: string): string {
262
+ return `
263
+ /**
264
+ * Delete ${modelName}.
265
+ */
266
+ public async delete(id: string): Promise<void> {
267
+ const collection = await getCollection('${collection}');
268
+ const ${modelVar} = await collection.findOne(byId(id));
269
+ await collection.deleteOne(byId(id));
270
+ if (${modelVar}) {
271
+ await eventBus.publish('${modelName}Deleted', { ...${modelVar}, timestamp: new Date().toISOString() } as any);
272
+ }
273
+ }
274
+ `;
275
+ }
276
+
277
+ interface CustomActionsResult {
278
+ code: string;
279
+ needsAiBehaviors: boolean;
280
+ }
281
+
282
+ function generateCustomActions(controller: any, modelName: string): CustomActionsResult {
283
+ if (!controller.actions || Object.keys(controller.actions).length === 0) {
284
+ return { code: '', needsAiBehaviors: false };
285
+ }
286
+ const out: string[] = [];
287
+ for (const [actionName, action] of Object.entries<any>(controller.actions)) {
288
+ const params = generateActionParams(action);
289
+ const stepsHeader = (action.steps && action.steps.length > 0)
290
+ ? action.steps.map((s: any) => ` * - ${typeof s === 'string' ? s : (s.action || JSON.stringify(s))}`).join('\n')
291
+ : ' * (no spec steps declared)';
292
+ out.push(`
293
+ /**
294
+ * ${actionName}
295
+ * ${action.description || ''}
296
+ *
297
+ * Spec steps:
298
+ ${stepsHeader}
299
+ */
300
+ public async ${actionName}(${params}): Promise<any> {
301
+ return await aiBehaviors.${actionName}({ controller: this, ...args });
302
+ }
303
+ `);
304
+ }
305
+ return { code: out.join('\n'), needsAiBehaviors: true };
306
+ }
307
+
308
+ function generateActionParams(action: any): string {
309
+ if (Array.isArray(action.parameters) && action.parameters.length > 0) {
310
+ return 'args: any';
311
+ }
312
+ if (action.parameters && typeof action.parameters === 'object' && Object.keys(action.parameters).length > 0) {
313
+ return 'args: any';
314
+ }
315
+ return 'args: any = {}';
316
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * MongoDB Native Driver — Service Generator
3
+ *
4
+ * Generates abstract business-logic services that use `getCollection` /
5
+ * `getDb` directly. The service body is intentionally skeletal: each
6
+ * declared operation gets a typed method, but the body is a TODO stub
7
+ * containing the spec steps as comments. Real-implementation generation
8
+ * is a separate concern (#43 follow-up: behavior-step → driver-call
9
+ * conventions parity with the prisma step library).
10
+ */
11
+ import type { TemplateContext } from '@specverse/types';
12
+
13
+ export default function generateMongoNativeService(context: TemplateContext): string {
14
+ const { service } = context;
15
+ if (!service) throw new Error('Service is required in template context');
16
+
17
+ const serviceName = service.name;
18
+ const operationsCode = generateOperations(service);
19
+ const usesDb = /\bgetDb\b|\bgetCollection\b/.test(operationsCode);
20
+ const hasEvents = (service.publishes && service.publishes.length > 0) ||
21
+ (service.subscribes && service.subscribes.length > 0);
22
+
23
+ return `/**
24
+ * ${serviceName}
25
+ * Abstract business logic service (MongoDB native driver)
26
+ * ${service.description || ''}
27
+ */
28
+ ${usesDb ? `import { getDb, getCollection } from '../db/mongoClient.js';` : ''}
29
+ ${hasEvents ? `import { eventBus } from '../events/eventBus.js';` : ''}
30
+
31
+ export class ${serviceName} {
32
+ ${operationsCode}
33
+ }
34
+
35
+ const ${lowerFirst(serviceName)} = new ${serviceName}();
36
+ export const ${lowerFirst(serviceName)}Instance = ${lowerFirst(serviceName)};
37
+ export default ${lowerFirst(serviceName)};
38
+ `;
39
+ }
40
+
41
+ function lowerFirst(s: string): string {
42
+ return s.charAt(0).toLowerCase() + s.slice(1);
43
+ }
44
+
45
+ function generateOperations(service: any): string {
46
+ const ops = service.operations;
47
+ if (!ops || (Array.isArray(ops) && ops.length === 0) || (!Array.isArray(ops) && Object.keys(ops).length === 0)) {
48
+ return `
49
+ /**
50
+ * Default service entrypoint — replace with real operations once declared
51
+ * on the service's spec.
52
+ */
53
+ public async execute(_params: any = {}): Promise<any> {
54
+ throw new Error('${service.name}.execute is not implemented');
55
+ }
56
+ `;
57
+ }
58
+ const entries: [string, any][] = Array.isArray(ops)
59
+ ? ops.map((op: any) => [op.name, op])
60
+ : Object.entries(ops);
61
+ return entries.map(([name, op]) => generateOperation(name, op, service.name)).join('\n');
62
+ }
63
+
64
+ function generateOperation(operationName: string, operation: any, serviceName: string): string {
65
+ const stepsHeader = (operation.steps && operation.steps.length > 0)
66
+ ? operation.steps.map((s: any) => ` * - ${typeof s === 'string' ? s : (s.action || JSON.stringify(s))}`).join('\n')
67
+ : ' * (no spec steps declared)';
68
+ return `
69
+ /**
70
+ * ${operationName}
71
+ * ${operation.description || ''}
72
+ *
73
+ * Spec steps:
74
+ ${stepsHeader}
75
+ */
76
+ public async ${operationName}(_args: any = {}): Promise<any> {
77
+ // TODO (#43 follow-up): translate spec steps into native MongoDB driver
78
+ // calls. For now this is a stub so realize completes and the service
79
+ // surface is callable for parity tests.
80
+ throw new Error('${serviceName}.${operationName} is not implemented');
81
+ }
82
+ `;
83
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "6.5.4",
3
+ "version": "6.6.3",
4
4
  "description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry, bundles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -62,7 +62,7 @@
62
62
  "@ai-sdk/openai-compatible": "^2.0.41",
63
63
  "@ai-sdk/provider": "^3.0.8",
64
64
  "@specverse/assets": "^1.6.0",
65
- "@specverse/engines": "^6.4.0",
65
+ "@specverse/engines": "^6.6.1",
66
66
  "@specverse/entities": "^5.1.0",
67
67
  "@specverse/runtime": "^5.0.1",
68
68
  "@specverse/types": "^5.1.0",