@donkeylabs/cli 2.2.0 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donkeylabs/cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "type": "module",
5
5
  "description": "CLI for @donkeylabs/server - project scaffolding and code generation",
6
6
  "main": "./src/index.ts",
@@ -45,6 +45,7 @@ export interface ProcessInfo {
45
45
  export interface ServerOutput {
46
46
  routes: RouteInfo[];
47
47
  processes: ProcessInfo[];
48
+ coreEvents?: Record<string, string>;
48
49
  }
49
50
 
50
51
  /**
@@ -124,7 +125,7 @@ export async function extractRoutesFromServer(entryPath: string): Promise<Server
124
125
  commands: p.commands,
125
126
  }));
126
127
 
127
- resolve({ routes, processes });
128
+ resolve({ routes, processes, coreEvents: result.coreEvents });
128
129
  } catch (e) {
129
130
  console.warn(pc.yellow("Failed to parse route data from server"));
130
131
  resolve({ routes: [], processes: [] });
@@ -954,7 +954,7 @@ export async function generateCommand(_args: string[]): Promise<void> {
954
954
  await generateRegistry(plugins, outPath);
955
955
  await generateContext(plugins, services, outPath);
956
956
  await generateRouteTypes(fileRoutes, outPath);
957
- await generateEventTypes(serverEvents, outPath);
957
+ await generateEventTypes(serverEvents, outPath, serverOutput.coreEvents);
958
958
  await generateProcessTypes(serverProcesses, outPath);
959
959
 
960
960
  const generated = ["registry", "context", "routes", "events", "processes"];
@@ -1373,9 +1373,17 @@ function parseZodObjectFields(objectContent: string): string {
1373
1373
 
1374
1374
  /**
1375
1375
  * Generate events.ts with namespace-nested types and EventMap.
1376
+ * Includes both core framework events and user-defined events.
1376
1377
  */
1377
- async function generateEventTypes(events: EventDefinitionInfo[], outPath: string): Promise<void> {
1378
- if (events.length === 0) {
1378
+ async function generateEventTypes(
1379
+ events: EventDefinitionInfo[],
1380
+ outPath: string,
1381
+ coreEvents?: Record<string, string>
1382
+ ): Promise<void> {
1383
+ const hasCoreEvents = coreEvents && Object.keys(coreEvents).length > 0;
1384
+ const hasUserEvents = events.length > 0;
1385
+
1386
+ if (!hasCoreEvents && !hasUserEvents) {
1379
1387
  // Still generate an empty file for consistency
1380
1388
  const content = `// Auto-generated by donkeylabs generate
1381
1389
  // Events - import as: import { type EventMap, type EventName } from ".@donkeylabs/server/events";
@@ -1398,10 +1406,32 @@ declare module "@donkeylabs/server" {
1398
1406
  return;
1399
1407
  }
1400
1408
 
1401
- // Group events by namespace (first part of event name)
1409
+ // Group ALL events by namespace (first part of event name)
1402
1410
  // e.g., "order.created" -> namespace "Order", event "Created"
1403
- const byNamespace = new Map<string, { eventName: string; pascalName: string; schemaSource: string; fullName: string }[]>();
1411
+ // e.g., "workflow.step.started" -> namespace "Workflow", event "StepStarted"
1412
+ const byNamespace = new Map<string, { eventName: string; pascalName: string; tsType: string; fullName: string; isCore: boolean }[]>();
1413
+
1414
+ // Add core events first (using pre-computed TS type strings)
1415
+ if (hasCoreEvents) {
1416
+ for (const [eventFullName, tsTypeString] of Object.entries(coreEvents!)) {
1417
+ const parts = eventFullName.split(".");
1418
+ const namespace = toPascalCase(parts[0] || "App");
1419
+ const eventName = parts.slice(1).map(p => toPascalCase(p)).join("") || toPascalCase(parts[0] || "Event");
1420
+
1421
+ if (!byNamespace.has(namespace)) {
1422
+ byNamespace.set(namespace, []);
1423
+ }
1424
+ byNamespace.get(namespace)!.push({
1425
+ eventName,
1426
+ pascalName: eventName,
1427
+ tsType: tsTypeString,
1428
+ fullName: eventFullName,
1429
+ isCore: true,
1430
+ });
1431
+ }
1432
+ }
1404
1433
 
1434
+ // Add user-defined events (from Zod schemas)
1405
1435
  for (const event of events) {
1406
1436
  const parts = event.name.split(".");
1407
1437
  const namespace = toPascalCase(parts[0] || "App");
@@ -1413,25 +1443,41 @@ declare module "@donkeylabs/server" {
1413
1443
  byNamespace.get(namespace)!.push({
1414
1444
  eventName,
1415
1445
  pascalName: eventName,
1416
- schemaSource: event.schemaSource,
1446
+ tsType: zodSchemaToTypeScript(event.schemaSource),
1417
1447
  fullName: event.name,
1448
+ isCore: false,
1418
1449
  });
1419
1450
  }
1420
1451
 
1421
1452
  // Generate namespace blocks
1422
1453
  const namespaceBlocks: string[] = [];
1454
+ const coreNamespaceBlocks: string[] = [];
1455
+ const userNamespaceBlocks: string[] = [];
1423
1456
  const eventMapEntries: string[] = [];
1424
1457
  const eventRegistryEntries: string[] = [];
1425
1458
  const eventNames: string[] = [];
1426
1459
 
1460
+ // Track which namespaces are core-only, user-only, or mixed
1427
1461
  for (const [namespace, nsEvents] of byNamespace) {
1462
+ const hasCoreInNs = nsEvents.some(e => e.isCore);
1463
+ const hasUserInNs = nsEvents.some(e => !e.isCore);
1464
+
1428
1465
  const eventTypeDecls = nsEvents.map(e => {
1429
- const tsType = zodSchemaToTypeScript(e.schemaSource);
1430
1466
  return ` /** Event data for "${e.fullName}" */
1431
- export type ${e.pascalName} = ${tsType};`;
1467
+ export type ${e.pascalName} = ${e.tsType};`;
1432
1468
  }).join("\n\n");
1433
1469
 
1434
- namespaceBlocks.push(`export namespace ${namespace} {\n${eventTypeDecls}\n}`);
1470
+ const block = `export namespace ${namespace} {\n${eventTypeDecls}\n}`;
1471
+
1472
+ if (hasCoreInNs && !hasUserInNs) {
1473
+ coreNamespaceBlocks.push(block);
1474
+ } else if (!hasCoreInNs && hasUserInNs) {
1475
+ userNamespaceBlocks.push(block);
1476
+ } else {
1477
+ // Mixed - put in core section
1478
+ coreNamespaceBlocks.push(block);
1479
+ }
1480
+ namespaceBlocks.push(block);
1435
1481
 
1436
1482
  // Add to EventMap and EventRegistry
1437
1483
  for (const e of nsEvents) {
@@ -1441,11 +1487,20 @@ declare module "@donkeylabs/server" {
1441
1487
  }
1442
1488
  }
1443
1489
 
1490
+ // Build the output with clear sections
1491
+ const sections: string[] = [];
1492
+
1493
+ if (coreNamespaceBlocks.length > 0) {
1494
+ sections.push(`// Core framework events\n${coreNamespaceBlocks.join("\n\n")}`);
1495
+ }
1496
+ if (userNamespaceBlocks.length > 0) {
1497
+ sections.push(`// User-defined events\n${userNamespaceBlocks.join("\n\n")}`);
1498
+ }
1499
+
1444
1500
  const content = `// Auto-generated by donkeylabs generate
1445
1501
  // Events - import as: import { type EventMap, type EventName, Order, User } from ".@donkeylabs/server/events";
1446
1502
 
1447
- // Event type namespaces - use as Order.Created, User.Signup, etc.
1448
- ${namespaceBlocks.join("\n\n")}
1503
+ ${sections.join("\n\n")}
1449
1504
 
1450
1505
  /** Map of all event names to their data types */
1451
1506
  export interface EventMap {