@common-stack/server-core 7.2.1-alpha.49 → 7.2.1-alpha.50

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/lib/index.d.ts CHANGED
@@ -3,4 +3,3 @@ export * from './interfaces';
3
3
  export * from './constants';
4
4
  export * from './logger';
5
5
  export * from './utils';
6
- export * from './moleculer-generation';
package/lib/index.js CHANGED
@@ -1 +1 @@
1
- export{Feature,featureCatalog}from'./connector/connector.js';export{GraphqlRootType}from'./interfaces/rules.js';export{TYPES}from'./constants/types.js';export{CACHE_CONTROL_DIRECTIVE}from'./constants/directives.js';export{logger}from'./logger/logger.js';export{getCurrentPreferences,transformPrefsToArray}from'./utils/preferences.js';export{generateQueryCacheKey}from'./utils/generate-query-cache-key.js';export{extractTenantId}from'./utils/extract-tenant-id.js';export{getDirectiveArgsFromSchema}from'./utils/get-directive-args-from-schema.js';export{buildActionPath,getActionName,getAllMethodNames,isExcludedMethod,toPascalCase}from'./moleculer-generation/serviceGenerationUtils.js';export{Moleculer}from'./moleculer-generation/moleculerEventHandler.js';export{createTypedAction,debugServiceParams,generateAutoInferredServiceActions,generateServiceActions,generateServiceActionsAndEvents,generateTypeSafeServiceActions,printServiceParams,verifyAllParamsDefined}from'./moleculer-generation/typedMoleculerService.js';export{ProxyService,generateProxyMethods}from'./moleculer-generation/typedProxyService.js';export{zodSchemasToMoleculer,zodToMoleculerParams}from'./moleculer-generation/zodToMoleculer.js';//# sourceMappingURL=index.js.map
1
+ export{Feature,featureCatalog}from'./connector/connector.js';export{GraphqlRootType}from'./interfaces/rules.js';export{TYPES}from'./constants/types.js';export{CACHE_CONTROL_DIRECTIVE}from'./constants/directives.js';export{logger}from'./logger/logger.js';export{getCurrentPreferences,transformPrefsToArray}from'./utils/preferences.js';export{generateQueryCacheKey}from'./utils/generate-query-cache-key.js';export{extractTenantId}from'./utils/extract-tenant-id.js';export{getDirectiveArgsFromSchema}from'./utils/get-directive-args-from-schema.js';//# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common-stack/server-core",
3
- "version": "7.2.1-alpha.49",
3
+ "version": "7.2.1-alpha.50",
4
4
  "description": "common core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -34,7 +34,7 @@
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "gitHead": "5d15f698177752229be196e4457e99c9dd4d26a5",
37
+ "gitHead": "86248ff51544d199dfe9b57471665d8c26d2817e",
38
38
  "typescript": {
39
39
  "definition": "lib/index.d.ts"
40
40
  }
@@ -1,628 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Generate Zod schemas for ALL service interfaces (CommonJS version)
4
- *
5
- * This script can be run from:
6
- * 1. Local project: node scripts/generateAllServiceSchemas.cjs
7
- * 2. As npm script: Add to package.json scripts and run via npm/yarn
8
- * 3. From node_modules: npx @common-stack/server-core generateAllServiceSchemas
9
- *
10
- * Configuration is loaded from cdecode-config.json in the project root.
11
- * All paths in the config are relative to the project root.
12
- *
13
- * @example package.json script
14
- * "scripts": {
15
- * "generateSchemas": "node node_modules/@common-stack/server-core/lib/moleculer-generation/generateAllServiceSchemas.cjs"
16
- * }
17
- */
18
-
19
- const fs = require('fs');
20
- const path = require('path');
21
- const ts = require('typescript');
22
-
23
- // Determine the project root - use current working directory (where the command is run)
24
- // This works whether the script is in local scripts/ or node_modules/
25
- const projectRoot = process.cwd();
26
-
27
- // Load configuration from cdecode-config.json in the project root
28
- const configPath = path.join(projectRoot, 'cdecode-config.json');
29
- let serviceConfig = {};
30
-
31
- if (fs.existsSync(configPath)) {
32
- try {
33
- const fullConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
34
- serviceConfig = fullConfig.serviceSchemas || {};
35
- console.log('✅ Loaded configuration from cdecode-config.json');
36
- } catch (error) {
37
- console.warn('⚠️ Could not parse cdecode-config.json, using defaults');
38
- }
39
- } else {
40
- console.warn('⚠️ cdecode-config.json not found in project root, using defaults');
41
- }
42
-
43
- // Apply configuration with defaults (all paths relative to project root)
44
- const SERVICES_DIR = path.join(projectRoot, serviceConfig.servicesDir || 'packages/common/src/services');
45
- const OUTPUT_FILE = path.join(
46
- projectRoot,
47
- serviceConfig.outputFile || 'packages/common/src/generated/service-schemas.ts',
48
- );
49
-
50
- // Validate that SERVICES_DIR exists
51
- if (!fs.existsSync(SERVICES_DIR)) {
52
- console.error(`❌ Error: Services directory not found: ${SERVICES_DIR}`);
53
- console.error(` Current working directory: ${projectRoot}`);
54
- console.error(` Expected path (from config): ${serviceConfig.servicesDir || 'packages/common/src/services'}`);
55
- console.error('\n Make sure:');
56
- console.error(' 1. You are running this script from the project root');
57
- console.error(' 2. The servicesDir path in cdecode-config.json is correct');
58
- process.exit(1);
59
- }
60
-
61
- const SKIP_SERVICES = serviceConfig.skipServices || [
62
- 'AuthBackendClient',
63
- 'PubSub',
64
- 'RedisCacheManager',
65
- 'InngestClient',
66
- 'JSONContributionRegistry',
67
- 'PageStore',
68
- 'PublisherEventService',
69
- ];
70
- const KNOWN_ENUMS = serviceConfig.knownEnums || [];
71
- const CONST_ENUM_SCHEMAS = serviceConfig.constEnumSchemas || ['ConfigurationTarget', 'ConfigurationScope'];
72
-
73
- /**
74
- * Calculate relative path from outputFile to graphqlSchemasPath
75
- */
76
- function calculateRelativeImportPath() {
77
- if (!serviceConfig.outputFile || !serviceConfig.graphqlSchemasPath) {
78
- return './generated-zod-schemas';
79
- }
80
-
81
- const outputDir = path.dirname(path.join(projectRoot, serviceConfig.outputFile));
82
- const graphqlSchemaPath = path.join(projectRoot, serviceConfig.graphqlSchemasPath);
83
-
84
- // Calculate relative path
85
- const relativePath = path.relative(outputDir, graphqlSchemaPath);
86
-
87
- // Remove .ts extension and ensure it starts with ./
88
- const withoutExt = relativePath.replace(/\.ts$/, '');
89
- return withoutExt.startsWith('.') ? withoutExt : `./${withoutExt}`;
90
- }
91
-
92
- const GRAPHQL_SCHEMAS_IMPORT_PATH = calculateRelativeImportPath();
93
-
94
- /**
95
- * Dynamically discover all available GraphQL Zod schemas from graphql-zod-schemas.ts
96
- * This scans for exported schema functions and extracts their type names
97
- */
98
- function discoverGraphQLZodTypes() {
99
- const graphqlSchemaFile = serviceConfig.graphqlSchemasPath
100
- ? path.join(projectRoot, serviceConfig.graphqlSchemasPath)
101
- : path.join(projectRoot, 'packages/common/src/generated/generated-zod-schemas.ts');
102
-
103
- // Check if file exists
104
- if (!fs.existsSync(graphqlSchemaFile)) {
105
- console.warn('⚠️ graphql-zod-schemas.ts not found, using empty set for GraphQL types');
106
- return new Set();
107
- }
108
-
109
- const content = fs.readFileSync(graphqlSchemaFile, 'utf8');
110
- const graphqlTypes = new Set();
111
-
112
- // Match all exported schema function names
113
- // Pattern: export function SomeTypeInputSchema() or export function SomeTypeSchema()
114
- const schemaFunctionPattern = /export function ([A-Z][a-zA-Z0-9]+)Schema\(\)/g;
115
- let match;
116
-
117
- while ((match = schemaFunctionPattern.exec(content)) !== null) {
118
- const schemaName = match[1];
119
-
120
- // Convert schema function name back to interface name
121
- // Examples:
122
- // - UserTokenInputSchema -> IUserTokenInput
123
- // - UserAuth0UpdateFieldsSchema -> IUserAuth0UpdateFields
124
- // - ConfigurationNodeInputSchema -> IConfigurationNodeInput
125
-
126
- // Skip enum schemas (they don't have 'Input' suffix typically and are in CONST_ENUM_SCHEMAS)
127
- if (CONST_ENUM_SCHEMAS.includes(schemaName)) {
128
- continue;
129
- }
130
-
131
- // Add 'I' prefix to convert to interface name
132
- const interfaceName = 'I' + schemaName;
133
- graphqlTypes.add(interfaceName);
134
- }
135
-
136
- return graphqlTypes;
137
- }
138
-
139
- // Dynamically discover available GraphQL Zod types
140
- const GRAPHQL_ZOD_TYPES = discoverGraphQLZodTypes();
141
-
142
- function findServiceInterfaces() {
143
- const files = fs.readdirSync(SERVICES_DIR).filter((f) => f.endsWith('.ts') && f !== 'index.ts');
144
- const services = [];
145
-
146
- files.forEach((file) => {
147
- const content = fs.readFileSync(path.join(SERVICES_DIR, file), 'utf8');
148
- const interfaceMatch = content.match(/export interface (I[A-Z][a-zA-Z0-9]*Service)/);
149
-
150
- if (interfaceMatch) {
151
- const serviceName = interfaceMatch[1];
152
- if (!SKIP_SERVICES.includes(serviceName.replace(/^I/, ''))) {
153
- services.push({
154
- name: serviceName,
155
- file: file,
156
- path: path.join(SERVICES_DIR, file),
157
- });
158
- }
159
- }
160
- });
161
-
162
- return services;
163
- }
164
-
165
- /**
166
- * Parse a TypeScript source file and extract method signatures from an interface
167
- * Now includes support for resolving inherited interface methods
168
- */
169
- function parseServiceInterface(filePath, interfaceName) {
170
- const sourceCode = fs.readFileSync(filePath, 'utf8');
171
- const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true);
172
-
173
- const methods = [];
174
- const usedEnums = new Set();
175
- const parsedInterfaces = new Set(); // Track parsed interfaces to avoid infinite recursion
176
-
177
- /**
178
- * Extract methods from an interface node
179
- */
180
- function extractMethodsFromInterface(node, currentSourceFile) {
181
- node.members.forEach((member) => {
182
- if (ts.isMethodSignature(member) && member.name) {
183
- const methodName = member.name.getText(currentSourceFile);
184
- const parameters = [];
185
-
186
- if (member.parameters) {
187
- member.parameters.forEach((param) => {
188
- const paramName = param.name.getText(currentSourceFile);
189
- const paramType = param.type ? param.type.getText(currentSourceFile) : 'any';
190
- const isOptional = !!param.questionToken;
191
-
192
- // Skip destructured parameters - treat the whole param as passthrough object
193
- if (ts.isObjectBindingPattern(param.name)) {
194
- // This is a destructured parameter like { user, accessToken }
195
- // Use the type instead
196
- parameters.push({
197
- name: '_destructured',
198
- type: paramType,
199
- isOptional,
200
- isDestructured: true,
201
- });
202
- return;
203
- }
204
-
205
- // Check if type is a known enum or const enum
206
- KNOWN_ENUMS.forEach((enumName) => {
207
- if (paramType.includes(enumName)) {
208
- usedEnums.add(enumName);
209
- }
210
- });
211
- CONST_ENUM_SCHEMAS.forEach((enumName) => {
212
- if (paramType.includes(enumName)) {
213
- usedEnums.add(enumName);
214
- }
215
- });
216
-
217
- parameters.push({
218
- name: paramName,
219
- type: paramType,
220
- isOptional,
221
- });
222
- });
223
- }
224
-
225
- // Only add if method doesn't already exist (child interface overrides parent)
226
- if (!methods.find((m) => m.name === methodName)) {
227
- methods.push({
228
- name: methodName,
229
- parameters,
230
- });
231
- }
232
- }
233
- });
234
- }
235
-
236
- /**
237
- * Resolve and parse extended interfaces
238
- */
239
- function resolveExtendedInterfaces(node, currentSourceFile) {
240
- if (node.heritageClauses) {
241
- node.heritageClauses.forEach((heritage) => {
242
- heritage.types.forEach((type) => {
243
- const baseInterfaceName = type.expression.getText(currentSourceFile);
244
-
245
- // Skip if already parsed (prevent infinite recursion)
246
- if (parsedInterfaces.has(baseInterfaceName)) {
247
- return;
248
- }
249
- parsedInterfaces.add(baseInterfaceName);
250
-
251
- // Try to find the base interface in common locations
252
- // projectRoot is process.cwd() - where the command is run from (project root)
253
- const possiblePaths = [
254
- // Most common: IBaseService in project's packages/common/src/repositories/
255
- path.join(projectRoot, 'packages/common/src/repositories/IBaseService.ts'),
256
- // Alternative: in store-mongo package
257
- path.join(projectRoot, 'packages/common-store-mongo/src/interfaces/base-service.ts'),
258
- // Same directory as current service file
259
- path.join(path.dirname(filePath), baseInterfaceName + '.ts'),
260
- // Direct filename match in repositories folder
261
- path.join(projectRoot, 'packages/common/src/repositories', baseInterfaceName + '.ts'),
262
- ];
263
-
264
- for (const possiblePath of possiblePaths) {
265
- if (fs.existsSync(possiblePath)) {
266
- try {
267
- const baseSourceCode = fs.readFileSync(possiblePath, 'utf8');
268
- const baseSourceFile = ts.createSourceFile(
269
- possiblePath,
270
- baseSourceCode,
271
- ts.ScriptTarget.Latest,
272
- true,
273
- );
274
-
275
- // Find the base interface and extract its methods
276
- function visitBase(baseNode) {
277
- if (
278
- ts.isInterfaceDeclaration(baseNode) &&
279
- baseNode.name.text === baseInterfaceName
280
- ) {
281
- // First, resolve any interfaces this base interface extends
282
- resolveExtendedInterfaces(baseNode, baseSourceFile);
283
- // Then extract methods from this base interface
284
- extractMethodsFromInterface(baseNode, baseSourceFile);
285
- }
286
- ts.forEachChild(baseNode, visitBase);
287
- }
288
-
289
- visitBase(baseSourceFile);
290
- break; // Found the file, no need to check other paths
291
- } catch (error) {
292
- // Continue to next possible path
293
- console.warn(`⚠️ Could not parse base interface ${baseInterfaceName} from ${possiblePath}:`, error.message);
294
- }
295
- }
296
- }
297
- });
298
- });
299
- }
300
- }
301
-
302
- function visit(node) {
303
- if (ts.isInterfaceDeclaration(node) && node.name.text === interfaceName) {
304
- parsedInterfaces.add(interfaceName);
305
-
306
- // First, resolve extended interfaces (inheritance hierarchy)
307
- resolveExtendedInterfaces(node, sourceFile);
308
-
309
- // Then extract methods from this interface (to allow overrides)
310
- extractMethodsFromInterface(node, sourceFile);
311
- }
312
-
313
- ts.forEachChild(node, visit);
314
- }
315
-
316
- visit(sourceFile);
317
- return { methods, usedEnums: Array.from(usedEnums) };
318
- }
319
-
320
- /**
321
- * Generate Zod schema string for a parameter type
322
- */
323
- function generateZodType(paramType, isOptional, paramName = '') {
324
- let zodType;
325
-
326
- // Handle union types like "string | null | undefined"
327
- if (paramType.includes('|')) {
328
- const types = paramType.split('|').map(t => t.trim());
329
- const hasNull = types.includes('null');
330
- const hasUndefined = types.includes('undefined');
331
- const nonNullableTypes = types.filter(t => t !== 'null' && t !== 'undefined');
332
-
333
- if (nonNullableTypes.length === 1) {
334
- // Single non-nullable type with null/undefined
335
- zodType = generateZodType(nonNullableTypes[0], false, paramName);
336
- if (hasNull || hasUndefined) {
337
- return `${zodType}.optional().nullable()`;
338
- }
339
- return zodType;
340
- } else if (nonNullableTypes.length > 1) {
341
- // Multiple types - generate z.union() for known types
342
- // This handles cases like "IExtensionIdentifier | string"
343
- const unionTypes = nonNullableTypes.map(type => {
344
- // Check if it's a GraphQL type
345
- if (GRAPHQL_ZOD_TYPES.has(type)) {
346
- const schemaName = type.replace(/^I/, '') + 'Schema';
347
- return `${schemaName}()`;
348
- }
349
- // Handle primitive types
350
- if (type === 'string') return 'z.string()';
351
- if (type === 'number') return 'z.number()';
352
- if (type === 'boolean') return 'z.boolean()';
353
- // Default to passthrough
354
- return 'PassthroughObjectSchema';
355
- });
356
-
357
- return `z.union([${unionTypes.join(', ')}])`;
358
- }
359
- }
360
-
361
- // Handle array types
362
- if (paramType.includes('[]')) {
363
- const innerType = paramType.replace('[]', '').trim();
364
- const innerZodType = generateZodType(innerType, false, paramName);
365
- zodType = `z.array(${innerZodType})`;
366
- }
367
- // Handle known enums
368
- else if (KNOWN_ENUMS.some((e) => paramType.includes(e))) {
369
- const enumName = KNOWN_ENUMS.find((e) => paramType.includes(e));
370
- zodType = `z.nativeEnum(${enumName})`;
371
- }
372
- // Handle const enums (use schema functions from graphql-zod-schemas)
373
- else if (CONST_ENUM_SCHEMAS.some((e) => paramType.includes(e))) {
374
- const enumName = CONST_ENUM_SCHEMAS.find((e) => paramType.includes(e));
375
- zodType = `${enumName}Schema()`;
376
- }
377
- // Handle primitive types
378
- else if (paramType === 'string') {
379
- zodType = 'z.string()';
380
- } else if (paramType === 'number') {
381
- zodType = 'z.number()';
382
- } else if (paramType === 'boolean') {
383
- zodType = 'z.boolean()';
384
- } else if (paramType === 'any') {
385
- zodType = 'z.any()';
386
- }
387
- // Handle Date
388
- else if (paramType === 'Date') {
389
- zodType = 'z.date()';
390
- }
391
- // Check if it's a GraphQL type with existing Zod schema
392
- else if (GRAPHQL_ZOD_TYPES.has(paramType)) {
393
- // Use the GraphQL-generated schema function
394
- const schemaName = paramType.replace(/^I/, '') + 'Schema';
395
- zodType = `${schemaName}()`;
396
- }
397
- // Handle Promise types (return type, not for validation)
398
- else if (paramType.startsWith('Promise<')) {
399
- zodType = 'z.any()';
400
- }
401
- // Use reusable schemas for common parameter names
402
- // Make complex objects optional by default to avoid strict validation errors
403
- else if (paramName === 'context' || paramName === 'userContext') {
404
- zodType = 'ContextSchema.optional()';
405
- } else if (paramName === 'resource') {
406
- zodType = 'ResourceSchema.optional()';
407
- } else if (paramName === 'options' || paramName === 'paginationOptions') {
408
- zodType = 'OptionsSchema.optional()';
409
- } else if (paramName === 'data' || paramName === 'updateData') {
410
- zodType = 'DataSchema.optional()';
411
- } else if (paramName === 'input') {
412
- zodType = 'InputSchema.optional()';
413
- } else if (paramName === 'filter' || paramName === 'criteria' || paramName === 'additionalFilters') {
414
- zodType = 'FilterSchema.optional()';
415
- } else if (paramName === 'where') {
416
- zodType = 'WhereSchema.optional()';
417
- } else if (paramName === 'request') {
418
- zodType = 'RequestSchema.optional()';
419
- }
420
- // Default: treat as object and make it optional
421
- else {
422
- zodType = 'PassthroughObjectSchema.optional()';
423
- }
424
-
425
- // Only add .optional() if not already added and isOptional is true
426
- return isOptional && !zodType.includes('.optional()') ? `${zodType}.optional()` : zodType;
427
- }
428
-
429
- function generateServiceSchemas() {
430
- const services = findServiceInterfaces();
431
-
432
- console.log(`\n🔍 Found ${services.length} service interfaces\n`);
433
-
434
- // Parse all services and collect used enums and GraphQL types
435
- const allUsedEnums = new Set();
436
- const allUsedGraphQLTypes = new Set();
437
- const allUsedConstEnumSchemas = new Set(); // Track const enum schemas
438
- const servicesWithMethods = [];
439
-
440
- services.forEach((service) => {
441
- const { methods, usedEnums } = parseServiceInterface(service.path, service.name);
442
- usedEnums.forEach((e) => {
443
- if (CONST_ENUM_SCHEMAS.includes(e)) {
444
- allUsedConstEnumSchemas.add(e);
445
- } else {
446
- allUsedEnums.add(e);
447
- }
448
- });
449
-
450
- // Track which GraphQL types are actually used
451
- methods.forEach((method) => {
452
- method.parameters.forEach((param) => {
453
- if (GRAPHQL_ZOD_TYPES.has(param.type)) {
454
- allUsedGraphQLTypes.add(param.type);
455
- }
456
- // Check in array types
457
- if (param.type.includes('[]')) {
458
- const innerType = param.type.replace('[]', '').trim();
459
- if (GRAPHQL_ZOD_TYPES.has(innerType)) {
460
- allUsedGraphQLTypes.add(innerType);
461
- }
462
- }
463
- // Check in union types (e.g., "IExtensionIdentifier | string")
464
- if (param.type.includes('|')) {
465
- const types = param.type.split('|').map(t => t.trim());
466
- types.forEach(type => {
467
- // Remove null and undefined
468
- if (type !== 'null' && type !== 'undefined' && GRAPHQL_ZOD_TYPES.has(type)) {
469
- allUsedGraphQLTypes.add(type);
470
- }
471
- });
472
- }
473
- });
474
- });
475
-
476
- servicesWithMethods.push({
477
- ...service,
478
- methods,
479
- });
480
- });
481
-
482
- // Start generating output
483
- let output = `// AUTO-GENERATED FILE - DO NOT EDIT
484
- // Generated from service interfaces in packages/common/src/services/
485
- // Run: yarn generateGraphql to regenerate
486
-
487
- import { z } from 'zod';
488
- `;
489
-
490
- // Import GraphQL Zod schemas (including const enum schemas)
491
- const allGraphQLSchemas = new Set([...allUsedGraphQLTypes, ...allUsedConstEnumSchemas]);
492
- if (allGraphQLSchemas.size > 0) {
493
- output += `\n// Import GraphQL-generated Zod schemas for detailed validation\nimport {\n`;
494
- allGraphQLSchemas.forEach((typeName) => {
495
- const schemaName = typeName.replace(/^I/, '') + 'Schema';
496
- output += ` ${schemaName},\n`;
497
- });
498
- output += `} from '${GRAPHQL_SCHEMAS_IMPORT_PATH}';\n`;
499
- }
500
-
501
- // Import used enums (only regular enums, not const enums)
502
- if (allUsedEnums.size > 0) {
503
- output += `\n// Import enums\nimport {\n`;
504
- allUsedEnums.forEach((enumName) => {
505
- output += ` ${enumName},\n`;
506
- });
507
- output += `} from 'common/server';\n`;
508
- }
509
-
510
- output += `
511
- /**
512
- * Centralized Zod schemas for all service interfaces
513
- *
514
- * Each service has its schemas exported as {ServiceName}Schemas
515
- * Use with zodSchemasToMoleculer() for Moleculer parameter validation
516
- *
517
- * Example:
518
- * \`\`\`typescript
519
- * import { AccountServiceSchemas, zodSchemasToMoleculer } from 'common/server';
520
- * const paramOverrides = zodSchemasToMoleculer(AccountServiceSchemas);
521
- * \`\`\`
522
- */
523
-
524
- // Reusable schemas for common parameter types
525
- const PassthroughObjectSchema = z.object({}).passthrough();
526
- const ContextSchema = PassthroughObjectSchema;
527
- const ResourceSchema = PassthroughObjectSchema;
528
- const OptionsSchema = PassthroughObjectSchema;
529
- const DataSchema = PassthroughObjectSchema;
530
- const InputSchema = PassthroughObjectSchema;
531
- const FilterSchema = PassthroughObjectSchema;
532
- const WhereSchema = PassthroughObjectSchema;
533
- const RequestSchema = PassthroughObjectSchema;
534
-
535
- `;
536
-
537
- // Generate schemas for each service
538
- servicesWithMethods.forEach((service) => {
539
- const schemaName = service.name.replace(/^I/, '').replace(/Service$/, 'Service');
540
- const serviceName = service.name.replace(/^I/, ''); // e.g., "TagService"
541
-
542
- output += `/**
543
- * Zod schemas for ${service.name}
544
- * Source: ${service.file}
545
- */
546
- export const ${schemaName}Schemas = {
547
- /** Moleculer service topic/name - safe for minification */
548
- topic: '${serviceName}' as const,
549
- `;
550
-
551
- if (service.methods.length === 0) {
552
- output += ` // No methods found\n`;
553
- } else {
554
- // Group methods by name to handle overloads (keep last signature)
555
- const methodMap = new Map();
556
- service.methods.forEach((method) => {
557
- methodMap.set(method.name, method);
558
- });
559
-
560
- // Generate schemas for unique methods
561
- methodMap.forEach((method, methodName) => {
562
- if (method.parameters.length === 0) {
563
- output += ` ${methodName}: PassthroughObjectSchema,\n`;
564
- } else {
565
- // Check if this method has only destructured params
566
- const hasOnlyDestructured = method.parameters.length === 1 && method.parameters[0].isDestructured;
567
-
568
- if (hasOnlyDestructured) {
569
- // For destructured params, use the type directly
570
- const param = method.parameters[0];
571
- const zodType = generateZodType(param.type, param.isOptional, param.name);
572
- output += ` ${methodName}: ${zodType},\n`;
573
- } else {
574
- output += ` ${methodName}: z.object({\n`;
575
- method.parameters.forEach((param) => {
576
- if (!param.isDestructured) {
577
- const zodType = generateZodType(param.type, param.isOptional, param.name);
578
- output += ` ${param.name}: ${zodType},\n`;
579
- }
580
- });
581
- output += ` }),\n`;
582
- }
583
- }
584
- });
585
- }
586
-
587
- output += `};\n\n`;
588
- });
589
-
590
- // Generate aggregated export with explicit type annotation to avoid TS7056 error
591
- output += `/**
592
- * All service schemas aggregated
593
- * Type annotation prevents TypeScript from inferring overly complex types
594
- */
595
- export const AllServiceSchemas: Record<string, Record<string, any>> = {\n`;
596
-
597
- servicesWithMethods.forEach((service) => {
598
- const schemaName = service.name.replace(/^I/, '').replace(/Service$/, 'Service');
599
- output += ` ${service.name}: ${schemaName}Schemas,\n`;
600
- });
601
-
602
- output += `};\n`;
603
-
604
- // Write the file
605
- fs.writeFileSync(OUTPUT_FILE, output, 'utf8');
606
-
607
- console.log(`✅ Generated schemas for ${services.length} services`);
608
-
609
- // Count total methods
610
- const totalMethods = servicesWithMethods.reduce((sum, s) => sum + s.methods.length, 0);
611
- console.log(`📊 Total methods: ${totalMethods}`);
612
- console.log(`📝 Output: ${path.relative(process.cwd(), OUTPUT_FILE)}\n`);
613
-
614
- return services.length;
615
- }
616
-
617
- // Export for CommonJS
618
- module.exports = { generateServiceSchemas };
619
-
620
- // CLI execution
621
- if (require.main === module) {
622
- try {
623
- generateServiceSchemas();
624
- } catch (error) {
625
- console.error('❌ Error generating service schemas:', error);
626
- process.exit(1);
627
- }
628
- }