@geekmidas/cli 0.2.0 → 0.2.2
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/dist/{SubscriberGenerator-BfMZCVNy.cjs → SubscriberGenerator-CB-NHtZW.cjs} +3 -2
- package/dist/SubscriberGenerator-CB-NHtZW.cjs.map +1 -0
- package/dist/{SubscriberGenerator-D2u00NI3.mjs → SubscriberGenerator-Cuu4co3-.mjs} +3 -2
- package/dist/SubscriberGenerator-Cuu4co3-.mjs.map +1 -0
- package/dist/build/index.cjs +2 -2
- package/dist/build/index.mjs +2 -2
- package/dist/{build-BBhlEjf5.cjs → build-Ajg356_5.cjs} +2 -2
- package/dist/{build-BBhlEjf5.cjs.map → build-Ajg356_5.cjs.map} +1 -1
- package/dist/{build-kY-lG30Q.mjs → build-zpABVsc0.mjs} +2 -2
- package/dist/{build-kY-lG30Q.mjs.map → build-zpABVsc0.mjs.map} +1 -1
- package/dist/generators/SubscriberGenerator.cjs +1 -1
- package/dist/generators/SubscriberGenerator.mjs +1 -1
- package/dist/generators/index.cjs +1 -1
- package/dist/generators/index.mjs +1 -1
- package/dist/index.cjs +11 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +11 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -7
- package/src/generators/SubscriberGenerator.ts +8 -5
- package/src/generators/__tests__/SubscriberGenerator.spec.ts +51 -0
- package/dist/SubscriberGenerator-BfMZCVNy.cjs.map +0 -1
- package/dist/SubscriberGenerator-D2u00NI3.mjs.map +0 -1
|
@@ -13,12 +13,12 @@ var SubscriberGenerator = class extends require_Generator.ConstructGenerator {
|
|
|
13
13
|
const provider = options?.provider || "aws-lambda";
|
|
14
14
|
const logger = console;
|
|
15
15
|
const subscriberInfos = [];
|
|
16
|
-
if (constructs.length === 0) return subscriberInfos;
|
|
17
16
|
if (provider === "server") {
|
|
18
17
|
await this.generateServerSubscribersFile(outputDir, constructs);
|
|
19
18
|
logger.log(`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`);
|
|
20
19
|
return subscriberInfos;
|
|
21
20
|
}
|
|
21
|
+
if (constructs.length === 0) return subscriberInfos;
|
|
22
22
|
if (provider !== "aws-lambda") return subscriberInfos;
|
|
23
23
|
const subscribersDir = (0, node_path.join)(outputDir, "subscribers");
|
|
24
24
|
await (0, node_fs_promises.mkdir)(subscribersDir, { recursive: true });
|
|
@@ -53,6 +53,7 @@ export const handler = adapter.handler;
|
|
|
53
53
|
return handlerPath;
|
|
54
54
|
}
|
|
55
55
|
async generateServerSubscribersFile(outputDir, subscribers) {
|
|
56
|
+
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
56
57
|
const subscribersFileName = "subscribers.ts";
|
|
57
58
|
const subscribersPath = (0, node_path.join)(outputDir, subscribersFileName);
|
|
58
59
|
const importsByFile = /* @__PURE__ */ new Map();
|
|
@@ -201,4 +202,4 @@ Object.defineProperty(exports, 'SubscriberGenerator', {
|
|
|
201
202
|
return SubscriberGenerator;
|
|
202
203
|
}
|
|
203
204
|
});
|
|
204
|
-
//# sourceMappingURL=SubscriberGenerator-
|
|
205
|
+
//# sourceMappingURL=SubscriberGenerator-CB-NHtZW.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscriberGenerator-CB-NHtZW.cjs","names":["ConstructGenerator","value: any","context: BuildContext","constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","subscriberInfos: SubscriberInfo[]","sourceFile: string","exportName: string","_subscriber: Subscriber<any, any, any, any, any, any>","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","exports"],"sources":["../src/generators/SubscriberGenerator.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { BuildContext } from '../build/types';\nimport type { SubscriberInfo } from '../types';\nimport {\n ConstructGenerator,\n type GeneratedConstruct,\n type GeneratorOptions,\n} from './Generator';\n\nexport class SubscriberGenerator extends ConstructGenerator<\n Subscriber<any, any, any, any, any, any>,\n SubscriberInfo[]\n> {\n isConstruct(value: any): value is Subscriber<any, any, any, any, any, any> {\n return Subscriber.isSubscriber(value);\n }\n\n async build(\n context: BuildContext,\n constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n outputDir: string,\n options?: GeneratorOptions,\n ): Promise<SubscriberInfo[]> {\n const provider = options?.provider || 'aws-lambda';\n const logger = console;\n const subscriberInfos: SubscriberInfo[] = [];\n\n if (provider === 'server') {\n // Generate subscribers.ts for server-based polling (even if empty)\n await this.generateServerSubscribersFile(outputDir, constructs);\n\n logger.log(\n `Generated server subscribers file with ${constructs.length} subscribers (polling mode)`,\n );\n\n // Return empty array as server subscribers don't have individual handlers\n return subscriberInfos;\n }\n\n if (constructs.length === 0) {\n return subscriberInfos;\n }\n\n if (provider !== 'aws-lambda') {\n return subscriberInfos;\n }\n\n // Create subscribers subdirectory\n const subscribersDir = join(outputDir, 'subscribers');\n await mkdir(subscribersDir, { recursive: true });\n\n // Generate subscriber handlers\n for (const { key, construct, path } of constructs) {\n const handlerFile = await this.generateSubscriberHandler(\n subscribersDir,\n path.relative,\n key,\n construct,\n context,\n );\n\n subscriberInfos.push({\n name: key,\n handler: relative(process.cwd(), handlerFile).replace(\n /\\.ts$/,\n '.handler',\n ),\n subscribedEvents: construct.subscribedEvents || [],\n timeout: construct.timeout,\n environment: await construct.getEnvironment(),\n });\n\n logger.log(`Generated subscriber handler: ${key}`);\n }\n\n return subscriberInfos;\n }\n\n private async generateSubscriberHandler(\n outputDir: string,\n sourceFile: string,\n exportName: string,\n _subscriber: Subscriber<any, any, any, any, any, any>,\n context: BuildContext,\n ): Promise<string> {\n const handlerFileName = `${exportName}.ts`;\n const handlerPath = join(outputDir, handlerFileName);\n\n const relativePath = relative(dirname(handlerPath), sourceFile);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n const relativeEnvParserPath = relative(\n dirname(handlerPath),\n context.envParserPath,\n );\n\n const content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaSubscriber(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n await writeFile(handlerPath, content);\n return handlerPath;\n }\n\n private async generateServerSubscribersFile(\n outputDir: string,\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n ): Promise<string> {\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n const subscribersFileName = 'subscribers.ts';\n const subscribersPath = join(outputDir, subscribersFileName);\n\n // Group imports by file\n const importsByFile = new Map<string, string[]>();\n\n for (const { path, key } of subscribers) {\n const relativePath = relative(dirname(subscribersPath), path.relative);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n if (!importsByFile.has(importPath)) {\n importsByFile.set(importPath, []);\n }\n importsByFile.get(importPath)!.push(key);\n }\n\n // Generate import statements\n const imports = Array.from(importsByFile.entries())\n .map(\n ([importPath, exports]) =>\n `import { ${exports.join(', ')} } from '${importPath}';`,\n )\n .join('\\n');\n\n const allExportNames = subscribers.map(({ key }) => key);\n\n const content = `/**\n * Generated subscribers setup\n *\n * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This uses event polling which is not suitable for production.\n *\n * For production, use AWS Lambda with SQS/SNS event source mappings.\n * Lambda automatically:\n * - Scales based on queue depth\n * - Handles batch processing and retries\n * - Manages dead letter queues\n * - Provides better cost optimization\n *\n * This polling implementation is useful for:\n * - Local development and testing\n * - Understanding event flow without Lambda deployment\n *\n * Supported connection strings:\n * - sqs://region/account-id/queue-name (SQS queue)\n * - sns://region/account-id/topic-name (SNS topic)\n * - rabbitmq://host:port/queue-name (RabbitMQ)\n * - basic://in-memory (In-memory for testing)\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst subscribers = [\n ${allExportNames.join(',\\n ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupSubscribers(\n envParser: EnvironmentParser<any>,\n logger: Logger,\n): Promise<void> {\n logger.info('Setting up subscribers in polling mode (local development)');\n\n const config = envParser.create((get) => ({\n connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\n\n const serviceDiscovery = ServiceDiscovery.getInstance(logger, envParser);\n\n // Create connection once, outside the loop (more efficient)\n // EventConnectionFactory automatically determines the right connection type\n let connection: EventConnection;\n try {\n connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n\n const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n logger.info({ connectionType }, 'Created shared event connection');\n } catch (error) {\n logger.error({ error }, 'Failed to create event connection');\n return;\n }\n\n for (const subscriber of subscribers) {\n try {\n // Create subscriber from shared connection\n const eventSubscriber = await Subscriber.fromConnection(connection);\n\n // Register services\n const services = subscriber.services.length > 0\n ? await serviceDiscovery.register(subscriber.services)\n : {};\n\n // Subscribe to events\n const subscribedEvents = subscriber.subscribedEvents || [];\n\n if (subscribedEvents.length === 0) {\n logger.warn({ subscriber: subscriber.constructor.name }, 'Subscriber has no subscribed events, skipping');\n continue;\n }\n\n await eventSubscriber.subscribe(subscribedEvents, async (event) => {\n try {\n // Process single event (batch of 1)\n await subscriber.handler({\n events: [event],\n services: services as any,\n logger: subscriber.logger,\n });\n\n logger.debug({ eventType: event.type }, 'Successfully processed event');\n } catch (error) {\n logger.error({ error, event }, 'Failed to process event');\n // Event will become visible again for retry\n }\n });\n\n activeSubscribers.push(eventSubscriber);\n\n logger.info(\n {\n events: subscribedEvents,\n },\n 'Subscriber started polling'\n );\n } catch (error) {\n logger.error({ error, subscriber: subscriber.constructor.name }, 'Failed to setup subscriber');\n }\n }\n\n // Setup graceful shutdown\n const shutdown = () => {\n logger.info('Stopping all subscribers');\n for (const eventSubscriber of activeSubscribers) {\n connection.stop();\n }\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n}\n`;\n\n await writeFile(subscribersPath, content);\n return subscribersPath;\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAa,sBAAb,cAAyCA,qCAGvC;CACA,YAAYC,OAA+D;AACzE,SAAO,8CAAW,aAAa,MAAM;CACtC;CAED,MAAM,MACJC,SACAC,YACAC,WACAC,SAC2B;EAC3B,MAAM,WAAW,SAAS,YAAY;EACtC,MAAM,SAAS;EACf,MAAMC,kBAAoC,CAAE;AAE5C,MAAI,aAAa,UAAU;AAEzB,SAAM,KAAK,8BAA8B,WAAW,WAAW;AAE/D,UAAO,KACJ,yCAAyC,WAAW,OAAO,6BAC7D;AAGD,UAAO;EACR;AAED,MAAI,WAAW,WAAW,EACxB,QAAO;AAGT,MAAI,aAAa,aACf,QAAO;EAIT,MAAM,iBAAiB,oBAAK,WAAW,cAAc;AACrD,QAAM,4BAAM,gBAAgB,EAAE,WAAW,KAAM,EAAC;AAGhD,OAAK,MAAM,EAAE,KAAK,WAAW,MAAM,IAAI,YAAY;GACjD,MAAM,cAAc,MAAM,KAAK,0BAC7B,gBACA,KAAK,UACL,KACA,WACA,QACD;AAED,mBAAgB,KAAK;IACnB,MAAM;IACN,SAAS,wBAAS,QAAQ,KAAK,EAAE,YAAY,CAAC,QAC5C,SACA,WACD;IACD,kBAAkB,UAAU,oBAAoB,CAAE;IAClD,SAAS,UAAU;IACnB,aAAa,MAAM,UAAU,gBAAgB;GAC9C,EAAC;AAEF,UAAO,KAAK,gCAAgC,IAAI,EAAE;EACnD;AAED,SAAO;CACR;CAED,MAAc,0BACZF,WACAG,YACAC,YACAC,aACAP,SACiB;EACjB,MAAM,mBAAmB,EAAE,WAAW;EACtC,MAAM,cAAc,oBAAK,WAAW,gBAAgB;EAEpD,MAAM,eAAe,wBAAS,uBAAQ,YAAY,EAAE,WAAW;EAC/D,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;EAEvD,MAAM,wBAAwB,wBAC5B,uBAAQ,YAAY,EACpB,QAAQ,cACT;EAED,MAAM,WAAW;WACV,WAAW,WAAW,WAAW;SACnC,QAAQ,uBAAuB,SAAS,sBAAsB;;qDAElB,WAAW;;;;AAK5D,QAAM,gCAAU,aAAa,QAAQ;AACrC,SAAO;CACR;CAED,MAAc,8BACZE,WACAM,aACiB;AAEjB,QAAM,4BAAM,WAAW,EAAE,WAAW,KAAM,EAAC;EAE3C,MAAM,sBAAsB;EAC5B,MAAM,kBAAkB,oBAAK,WAAW,oBAAoB;EAG5D,MAAM,gCAAgB,IAAI;AAE1B,OAAK,MAAM,EAAE,MAAM,KAAK,IAAI,aAAa;GACvC,MAAM,eAAe,wBAAS,uBAAQ,gBAAgB,EAAE,KAAK,SAAS;GACtE,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;AAEvD,QAAK,cAAc,IAAI,WAAW,CAChC,eAAc,IAAI,YAAY,CAAE,EAAC;AAEnC,iBAAc,IAAI,WAAW,CAAE,KAAK,IAAI;EACzC;EAGD,MAAM,UAAU,MAAM,KAAK,cAAc,SAAS,CAAC,CAChD,IACC,CAAC,CAAC,YAAYC,UAAQ,MACnB,WAAW,UAAQ,KAAK,KAAK,CAAC,WAAW,WAAW,IACxD,CACA,KAAK,KAAK;EAEb,MAAM,iBAAiB,YAAY,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI;EAExD,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BnB,QAAQ;;;IAGN,eAAe,KAAK,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+F7B,QAAM,gCAAU,iBAAiB,QAAQ;AACzC,SAAO;CACR;AACF"}
|
|
@@ -12,12 +12,12 @@ var SubscriberGenerator = class extends ConstructGenerator {
|
|
|
12
12
|
const provider = options?.provider || "aws-lambda";
|
|
13
13
|
const logger = console;
|
|
14
14
|
const subscriberInfos = [];
|
|
15
|
-
if (constructs.length === 0) return subscriberInfos;
|
|
16
15
|
if (provider === "server") {
|
|
17
16
|
await this.generateServerSubscribersFile(outputDir, constructs);
|
|
18
17
|
logger.log(`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`);
|
|
19
18
|
return subscriberInfos;
|
|
20
19
|
}
|
|
20
|
+
if (constructs.length === 0) return subscriberInfos;
|
|
21
21
|
if (provider !== "aws-lambda") return subscriberInfos;
|
|
22
22
|
const subscribersDir = join(outputDir, "subscribers");
|
|
23
23
|
await mkdir(subscribersDir, { recursive: true });
|
|
@@ -52,6 +52,7 @@ export const handler = adapter.handler;
|
|
|
52
52
|
return handlerPath;
|
|
53
53
|
}
|
|
54
54
|
async generateServerSubscribersFile(outputDir, subscribers) {
|
|
55
|
+
await mkdir(outputDir, { recursive: true });
|
|
55
56
|
const subscribersFileName = "subscribers.ts";
|
|
56
57
|
const subscribersPath = join(outputDir, subscribersFileName);
|
|
57
58
|
const importsByFile = /* @__PURE__ */ new Map();
|
|
@@ -195,4 +196,4 @@ export async function setupSubscribers(
|
|
|
195
196
|
|
|
196
197
|
//#endregion
|
|
197
198
|
export { SubscriberGenerator };
|
|
198
|
-
//# sourceMappingURL=SubscriberGenerator-
|
|
199
|
+
//# sourceMappingURL=SubscriberGenerator-Cuu4co3-.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscriberGenerator-Cuu4co3-.mjs","names":["value: any","context: BuildContext","constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","subscriberInfos: SubscriberInfo[]","sourceFile: string","exportName: string","_subscriber: Subscriber<any, any, any, any, any, any>","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]"],"sources":["../src/generators/SubscriberGenerator.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { BuildContext } from '../build/types';\nimport type { SubscriberInfo } from '../types';\nimport {\n ConstructGenerator,\n type GeneratedConstruct,\n type GeneratorOptions,\n} from './Generator';\n\nexport class SubscriberGenerator extends ConstructGenerator<\n Subscriber<any, any, any, any, any, any>,\n SubscriberInfo[]\n> {\n isConstruct(value: any): value is Subscriber<any, any, any, any, any, any> {\n return Subscriber.isSubscriber(value);\n }\n\n async build(\n context: BuildContext,\n constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n outputDir: string,\n options?: GeneratorOptions,\n ): Promise<SubscriberInfo[]> {\n const provider = options?.provider || 'aws-lambda';\n const logger = console;\n const subscriberInfos: SubscriberInfo[] = [];\n\n if (provider === 'server') {\n // Generate subscribers.ts for server-based polling (even if empty)\n await this.generateServerSubscribersFile(outputDir, constructs);\n\n logger.log(\n `Generated server subscribers file with ${constructs.length} subscribers (polling mode)`,\n );\n\n // Return empty array as server subscribers don't have individual handlers\n return subscriberInfos;\n }\n\n if (constructs.length === 0) {\n return subscriberInfos;\n }\n\n if (provider !== 'aws-lambda') {\n return subscriberInfos;\n }\n\n // Create subscribers subdirectory\n const subscribersDir = join(outputDir, 'subscribers');\n await mkdir(subscribersDir, { recursive: true });\n\n // Generate subscriber handlers\n for (const { key, construct, path } of constructs) {\n const handlerFile = await this.generateSubscriberHandler(\n subscribersDir,\n path.relative,\n key,\n construct,\n context,\n );\n\n subscriberInfos.push({\n name: key,\n handler: relative(process.cwd(), handlerFile).replace(\n /\\.ts$/,\n '.handler',\n ),\n subscribedEvents: construct.subscribedEvents || [],\n timeout: construct.timeout,\n environment: await construct.getEnvironment(),\n });\n\n logger.log(`Generated subscriber handler: ${key}`);\n }\n\n return subscriberInfos;\n }\n\n private async generateSubscriberHandler(\n outputDir: string,\n sourceFile: string,\n exportName: string,\n _subscriber: Subscriber<any, any, any, any, any, any>,\n context: BuildContext,\n ): Promise<string> {\n const handlerFileName = `${exportName}.ts`;\n const handlerPath = join(outputDir, handlerFileName);\n\n const relativePath = relative(dirname(handlerPath), sourceFile);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n const relativeEnvParserPath = relative(\n dirname(handlerPath),\n context.envParserPath,\n );\n\n const content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaSubscriber(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n await writeFile(handlerPath, content);\n return handlerPath;\n }\n\n private async generateServerSubscribersFile(\n outputDir: string,\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n ): Promise<string> {\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n const subscribersFileName = 'subscribers.ts';\n const subscribersPath = join(outputDir, subscribersFileName);\n\n // Group imports by file\n const importsByFile = new Map<string, string[]>();\n\n for (const { path, key } of subscribers) {\n const relativePath = relative(dirname(subscribersPath), path.relative);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n if (!importsByFile.has(importPath)) {\n importsByFile.set(importPath, []);\n }\n importsByFile.get(importPath)!.push(key);\n }\n\n // Generate import statements\n const imports = Array.from(importsByFile.entries())\n .map(\n ([importPath, exports]) =>\n `import { ${exports.join(', ')} } from '${importPath}';`,\n )\n .join('\\n');\n\n const allExportNames = subscribers.map(({ key }) => key);\n\n const content = `/**\n * Generated subscribers setup\n *\n * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This uses event polling which is not suitable for production.\n *\n * For production, use AWS Lambda with SQS/SNS event source mappings.\n * Lambda automatically:\n * - Scales based on queue depth\n * - Handles batch processing and retries\n * - Manages dead letter queues\n * - Provides better cost optimization\n *\n * This polling implementation is useful for:\n * - Local development and testing\n * - Understanding event flow without Lambda deployment\n *\n * Supported connection strings:\n * - sqs://region/account-id/queue-name (SQS queue)\n * - sns://region/account-id/topic-name (SNS topic)\n * - rabbitmq://host:port/queue-name (RabbitMQ)\n * - basic://in-memory (In-memory for testing)\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst subscribers = [\n ${allExportNames.join(',\\n ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupSubscribers(\n envParser: EnvironmentParser<any>,\n logger: Logger,\n): Promise<void> {\n logger.info('Setting up subscribers in polling mode (local development)');\n\n const config = envParser.create((get) => ({\n connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\n\n const serviceDiscovery = ServiceDiscovery.getInstance(logger, envParser);\n\n // Create connection once, outside the loop (more efficient)\n // EventConnectionFactory automatically determines the right connection type\n let connection: EventConnection;\n try {\n connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n\n const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n logger.info({ connectionType }, 'Created shared event connection');\n } catch (error) {\n logger.error({ error }, 'Failed to create event connection');\n return;\n }\n\n for (const subscriber of subscribers) {\n try {\n // Create subscriber from shared connection\n const eventSubscriber = await Subscriber.fromConnection(connection);\n\n // Register services\n const services = subscriber.services.length > 0\n ? await serviceDiscovery.register(subscriber.services)\n : {};\n\n // Subscribe to events\n const subscribedEvents = subscriber.subscribedEvents || [];\n\n if (subscribedEvents.length === 0) {\n logger.warn({ subscriber: subscriber.constructor.name }, 'Subscriber has no subscribed events, skipping');\n continue;\n }\n\n await eventSubscriber.subscribe(subscribedEvents, async (event) => {\n try {\n // Process single event (batch of 1)\n await subscriber.handler({\n events: [event],\n services: services as any,\n logger: subscriber.logger,\n });\n\n logger.debug({ eventType: event.type }, 'Successfully processed event');\n } catch (error) {\n logger.error({ error, event }, 'Failed to process event');\n // Event will become visible again for retry\n }\n });\n\n activeSubscribers.push(eventSubscriber);\n\n logger.info(\n {\n events: subscribedEvents,\n },\n 'Subscriber started polling'\n );\n } catch (error) {\n logger.error({ error, subscriber: subscriber.constructor.name }, 'Failed to setup subscriber');\n }\n }\n\n // Setup graceful shutdown\n const shutdown = () => {\n logger.info('Stopping all subscribers');\n for (const eventSubscriber of activeSubscribers) {\n connection.stop();\n }\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n}\n`;\n\n await writeFile(subscribersPath, content);\n return subscribersPath;\n }\n}\n"],"mappings":";;;;;;AAWA,IAAa,sBAAb,cAAyC,mBAGvC;CACA,YAAYA,OAA+D;AACzE,SAAO,WAAW,aAAa,MAAM;CACtC;CAED,MAAM,MACJC,SACAC,YACAC,WACAC,SAC2B;EAC3B,MAAM,WAAW,SAAS,YAAY;EACtC,MAAM,SAAS;EACf,MAAMC,kBAAoC,CAAE;AAE5C,MAAI,aAAa,UAAU;AAEzB,SAAM,KAAK,8BAA8B,WAAW,WAAW;AAE/D,UAAO,KACJ,yCAAyC,WAAW,OAAO,6BAC7D;AAGD,UAAO;EACR;AAED,MAAI,WAAW,WAAW,EACxB,QAAO;AAGT,MAAI,aAAa,aACf,QAAO;EAIT,MAAM,iBAAiB,KAAK,WAAW,cAAc;AACrD,QAAM,MAAM,gBAAgB,EAAE,WAAW,KAAM,EAAC;AAGhD,OAAK,MAAM,EAAE,KAAK,WAAW,MAAM,IAAI,YAAY;GACjD,MAAM,cAAc,MAAM,KAAK,0BAC7B,gBACA,KAAK,UACL,KACA,WACA,QACD;AAED,mBAAgB,KAAK;IACnB,MAAM;IACN,SAAS,SAAS,QAAQ,KAAK,EAAE,YAAY,CAAC,QAC5C,SACA,WACD;IACD,kBAAkB,UAAU,oBAAoB,CAAE;IAClD,SAAS,UAAU;IACnB,aAAa,MAAM,UAAU,gBAAgB;GAC9C,EAAC;AAEF,UAAO,KAAK,gCAAgC,IAAI,EAAE;EACnD;AAED,SAAO;CACR;CAED,MAAc,0BACZF,WACAG,YACAC,YACAC,aACAP,SACiB;EACjB,MAAM,mBAAmB,EAAE,WAAW;EACtC,MAAM,cAAc,KAAK,WAAW,gBAAgB;EAEpD,MAAM,eAAe,SAAS,QAAQ,YAAY,EAAE,WAAW;EAC/D,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;EAEvD,MAAM,wBAAwB,SAC5B,QAAQ,YAAY,EACpB,QAAQ,cACT;EAED,MAAM,WAAW;WACV,WAAW,WAAW,WAAW;SACnC,QAAQ,uBAAuB,SAAS,sBAAsB;;qDAElB,WAAW;;;;AAK5D,QAAM,UAAU,aAAa,QAAQ;AACrC,SAAO;CACR;CAED,MAAc,8BACZE,WACAM,aACiB;AAEjB,QAAM,MAAM,WAAW,EAAE,WAAW,KAAM,EAAC;EAE3C,MAAM,sBAAsB;EAC5B,MAAM,kBAAkB,KAAK,WAAW,oBAAoB;EAG5D,MAAM,gCAAgB,IAAI;AAE1B,OAAK,MAAM,EAAE,MAAM,KAAK,IAAI,aAAa;GACvC,MAAM,eAAe,SAAS,QAAQ,gBAAgB,EAAE,KAAK,SAAS;GACtE,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;AAEvD,QAAK,cAAc,IAAI,WAAW,CAChC,eAAc,IAAI,YAAY,CAAE,EAAC;AAEnC,iBAAc,IAAI,WAAW,CAAE,KAAK,IAAI;EACzC;EAGD,MAAM,UAAU,MAAM,KAAK,cAAc,SAAS,CAAC,CAChD,IACC,CAAC,CAAC,YAAY,QAAQ,MACnB,WAAW,QAAQ,KAAK,KAAK,CAAC,WAAW,WAAW,IACxD,CACA,KAAK,KAAK;EAEb,MAAM,iBAAiB,YAAY,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI;EAExD,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BnB,QAAQ;;;IAGN,eAAe,KAAK,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+F7B,QAAM,UAAU,iBAAiB,QAAQ;AACzC,SAAO;CACR;AACF"}
|
package/dist/build/index.cjs
CHANGED
|
@@ -3,10 +3,10 @@ require('../Generator-CDoEXCDg.cjs');
|
|
|
3
3
|
require('../CronGenerator-1PflEYe2.cjs');
|
|
4
4
|
require('../EndpointGenerator-BbGrDiCP.cjs');
|
|
5
5
|
require('../FunctionGenerator-Clw64SwQ.cjs');
|
|
6
|
-
require('../SubscriberGenerator-
|
|
6
|
+
require('../SubscriberGenerator-CB-NHtZW.cjs');
|
|
7
7
|
require('../generators-CEKtVh81.cjs');
|
|
8
8
|
require('../manifests-D0saShvH.cjs');
|
|
9
9
|
require('../providerResolver-DgvzNfP4.cjs');
|
|
10
|
-
const require_build = require('../build-
|
|
10
|
+
const require_build = require('../build-Ajg356_5.cjs');
|
|
11
11
|
|
|
12
12
|
exports.buildCommand = require_build.buildCommand;
|
package/dist/build/index.mjs
CHANGED
|
@@ -3,10 +3,10 @@ import "../Generator-UanJW0_V.mjs";
|
|
|
3
3
|
import "../CronGenerator-DXRfHQcV.mjs";
|
|
4
4
|
import "../EndpointGenerator-BmZ9BxbO.mjs";
|
|
5
5
|
import "../FunctionGenerator-DOEB_yPh.mjs";
|
|
6
|
-
import "../SubscriberGenerator-
|
|
6
|
+
import "../SubscriberGenerator-Cuu4co3-.mjs";
|
|
7
7
|
import "../generators-CsLujGXs.mjs";
|
|
8
8
|
import "../manifests-BrJXpHrf.mjs";
|
|
9
9
|
import "../providerResolver-B_TjNF0_.mjs";
|
|
10
|
-
import { buildCommand } from "../build-
|
|
10
|
+
import { buildCommand } from "../build-zpABVsc0.mjs";
|
|
11
11
|
|
|
12
12
|
export { buildCommand };
|
|
@@ -3,7 +3,7 @@ const require_config = require('./config-D1EpSGk6.cjs');
|
|
|
3
3
|
const require_CronGenerator = require('./CronGenerator-1PflEYe2.cjs');
|
|
4
4
|
const require_EndpointGenerator = require('./EndpointGenerator-BbGrDiCP.cjs');
|
|
5
5
|
const require_FunctionGenerator = require('./FunctionGenerator-Clw64SwQ.cjs');
|
|
6
|
-
const require_SubscriberGenerator = require('./SubscriberGenerator-
|
|
6
|
+
const require_SubscriberGenerator = require('./SubscriberGenerator-CB-NHtZW.cjs');
|
|
7
7
|
const require_manifests = require('./manifests-D0saShvH.cjs');
|
|
8
8
|
const require_providerResolver = require('./providerResolver-DgvzNfP4.cjs');
|
|
9
9
|
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
@@ -86,4 +86,4 @@ Object.defineProperty(exports, 'buildCommand', {
|
|
|
86
86
|
return buildCommand;
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
|
-
//# sourceMappingURL=build-
|
|
89
|
+
//# sourceMappingURL=build-Ajg356_5.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-
|
|
1
|
+
{"version":3,"file":"build-Ajg356_5.cjs","names":["options: BuildOptions","buildContext: BuildContext","EndpointGenerator","FunctionGenerator","CronGenerator","SubscriberGenerator","provider: LegacyProvider","context: BuildContext","endpointGenerator: EndpointGenerator","functionGenerator: FunctionGenerator","cronGenerator: CronGenerator","subscriberGenerator: SubscriberGenerator","endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[]","functions: GeneratedConstruct<Function<any, any, any, any>>[]","crons: GeneratedConstruct<Cron<any, any, any, any>>[]","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","enableOpenApi: boolean"],"sources":["../src/build/index.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\nimport type { Subscriber } from '@geekmidas/constructs/subscribers';\nimport { loadConfig } from '../config';\nimport {\n CronGenerator,\n EndpointGenerator,\n FunctionGenerator,\n type GeneratedConstruct,\n SubscriberGenerator,\n} from '../generators';\nimport type {\n BuildOptions,\n CronInfo,\n FunctionInfo,\n LegacyProvider,\n RouteInfo,\n SubscriberInfo,\n} from '../types';\nimport { generateManifests } from './manifests';\nimport { resolveProviders } from './providerResolver';\nimport type { BuildContext } from './types';\n\nconst logger = console;\n\nexport async function buildCommand(options: BuildOptions): Promise<void> {\n const config = await loadConfig();\n\n // Resolve providers from new config format\n const resolved = resolveProviders(config, options);\n\n logger.log(`Building with providers: ${resolved.providers.join(', ')}`);\n logger.log(`Loading routes from: ${config.routes}`);\n if (config.functions) {\n logger.log(`Loading functions from: ${config.functions}`);\n }\n if (config.crons) {\n logger.log(`Loading crons from: ${config.crons}`);\n }\n if (config.subscribers) {\n logger.log(`Loading subscribers from: ${config.subscribers}`);\n }\n logger.log(`Using envParser: ${config.envParser}`);\n\n // Parse envParser configuration\n const [envParserPath, envParserName] = config.envParser.split('#');\n const envParserImportPattern = !envParserName\n ? 'envParser'\n : envParserName === 'envParser'\n ? '{ envParser }'\n : `{ ${envParserName} as envParser }`;\n\n // Parse logger configuration\n const [loggerPath, loggerName] = config.logger.split('#');\n const loggerImportPattern = !loggerName\n ? 'logger'\n : loggerName === 'logger'\n ? '{ logger }'\n : `{ ${loggerName} as logger }`;\n\n const buildContext: BuildContext = {\n envParserPath,\n envParserImportPattern,\n loggerPath,\n loggerImportPattern,\n };\n\n // Initialize generators\n const endpointGenerator = new EndpointGenerator();\n const functionGenerator = new FunctionGenerator();\n const cronGenerator = new CronGenerator();\n const subscriberGenerator = new SubscriberGenerator();\n\n // Load all constructs in parallel\n const [allEndpoints, allFunctions, allCrons, allSubscribers] =\n await Promise.all([\n endpointGenerator.load(config.routes),\n config.functions ? functionGenerator.load(config.functions) : [],\n config.crons ? cronGenerator.load(config.crons) : [],\n config.subscribers ? subscriberGenerator.load(config.subscribers) : [],\n ]);\n\n logger.log(`Found ${allEndpoints.length} endpoints`);\n logger.log(`Found ${allFunctions.length} functions`);\n logger.log(`Found ${allCrons.length} crons`);\n logger.log(`Found ${allSubscribers.length} subscribers`);\n\n if (\n allEndpoints.length === 0 &&\n allFunctions.length === 0 &&\n allCrons.length === 0 &&\n allSubscribers.length === 0\n ) {\n logger.log(\n 'No endpoints, functions, crons, or subscribers found to process',\n );\n return;\n }\n\n // Ensure .gkm directory exists\n const rootOutputDir = join(process.cwd(), '.gkm');\n await mkdir(rootOutputDir, { recursive: true });\n\n // Collect all build results from each provider\n const allBuildResults = await Promise.all(\n resolved.providers.map((provider) =>\n buildForProvider(\n provider,\n buildContext,\n endpointGenerator,\n functionGenerator,\n cronGenerator,\n subscriberGenerator,\n allEndpoints,\n allFunctions,\n allCrons,\n allSubscribers,\n resolved.enableOpenApi,\n ),\n ),\n );\n\n // Aggregate all routes, functions, crons, and subscribers from all providers\n const aggregatedRoutes = allBuildResults.flatMap((result) => result.routes);\n const aggregatedFunctions = allBuildResults.flatMap(\n (result) => result.functions,\n );\n const aggregatedCrons = allBuildResults.flatMap((result) => result.crons);\n const aggregatedSubscribers = allBuildResults.flatMap(\n (result) => result.subscribers,\n );\n\n // Generate single manifest at root .gkm directory\n await generateManifests(\n rootOutputDir,\n aggregatedRoutes,\n aggregatedFunctions,\n aggregatedCrons,\n aggregatedSubscribers,\n );\n}\n\ninterface BuildResult {\n routes: RouteInfo[];\n functions: FunctionInfo[];\n crons: CronInfo[];\n subscribers: SubscriberInfo[];\n}\n\nasync function buildForProvider(\n provider: LegacyProvider,\n context: BuildContext,\n endpointGenerator: EndpointGenerator,\n functionGenerator: FunctionGenerator,\n cronGenerator: CronGenerator,\n subscriberGenerator: SubscriberGenerator,\n endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],\n functions: GeneratedConstruct<Function<any, any, any, any>>[],\n crons: GeneratedConstruct<Cron<any, any, any, any>>[],\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n enableOpenApi: boolean,\n): Promise<BuildResult> {\n const outputDir = join(process.cwd(), '.gkm', provider);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n logger.log(`\\nGenerating handlers for provider: ${provider}`);\n\n // Build all constructs in parallel\n const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(\n [\n endpointGenerator.build(context, endpoints, outputDir, {\n provider,\n enableOpenApi,\n }),\n functionGenerator.build(context, functions, outputDir, { provider }),\n cronGenerator.build(context, crons, outputDir, { provider }),\n subscriberGenerator.build(context, subscribers, outputDir, { provider }),\n ],\n );\n\n logger.log(\n `Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,\n );\n\n // Return build results instead of generating manifest here\n return {\n routes,\n functions: functionInfos,\n crons: cronInfos,\n subscribers: subscriberInfos,\n };\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { loadConfig } from "./config-U-mdW-7Y.mjs";
|
|
|
2
2
|
import { CronGenerator } from "./CronGenerator-DXRfHQcV.mjs";
|
|
3
3
|
import { EndpointGenerator } from "./EndpointGenerator-BmZ9BxbO.mjs";
|
|
4
4
|
import { FunctionGenerator } from "./FunctionGenerator-DOEB_yPh.mjs";
|
|
5
|
-
import { SubscriberGenerator } from "./SubscriberGenerator-
|
|
5
|
+
import { SubscriberGenerator } from "./SubscriberGenerator-Cuu4co3-.mjs";
|
|
6
6
|
import { generateManifests } from "./manifests-BrJXpHrf.mjs";
|
|
7
7
|
import { resolveProviders } from "./providerResolver-B_TjNF0_.mjs";
|
|
8
8
|
import { mkdir } from "node:fs/promises";
|
|
@@ -80,4 +80,4 @@ async function buildForProvider(provider, context, endpointGenerator, functionGe
|
|
|
80
80
|
|
|
81
81
|
//#endregion
|
|
82
82
|
export { buildCommand };
|
|
83
|
-
//# sourceMappingURL=build-
|
|
83
|
+
//# sourceMappingURL=build-zpABVsc0.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-
|
|
1
|
+
{"version":3,"file":"build-zpABVsc0.mjs","names":["options: BuildOptions","buildContext: BuildContext","provider: LegacyProvider","context: BuildContext","endpointGenerator: EndpointGenerator","functionGenerator: FunctionGenerator","cronGenerator: CronGenerator","subscriberGenerator: SubscriberGenerator","endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[]","functions: GeneratedConstruct<Function<any, any, any, any>>[]","crons: GeneratedConstruct<Cron<any, any, any, any>>[]","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","enableOpenApi: boolean"],"sources":["../src/build/index.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\nimport type { Subscriber } from '@geekmidas/constructs/subscribers';\nimport { loadConfig } from '../config';\nimport {\n CronGenerator,\n EndpointGenerator,\n FunctionGenerator,\n type GeneratedConstruct,\n SubscriberGenerator,\n} from '../generators';\nimport type {\n BuildOptions,\n CronInfo,\n FunctionInfo,\n LegacyProvider,\n RouteInfo,\n SubscriberInfo,\n} from '../types';\nimport { generateManifests } from './manifests';\nimport { resolveProviders } from './providerResolver';\nimport type { BuildContext } from './types';\n\nconst logger = console;\n\nexport async function buildCommand(options: BuildOptions): Promise<void> {\n const config = await loadConfig();\n\n // Resolve providers from new config format\n const resolved = resolveProviders(config, options);\n\n logger.log(`Building with providers: ${resolved.providers.join(', ')}`);\n logger.log(`Loading routes from: ${config.routes}`);\n if (config.functions) {\n logger.log(`Loading functions from: ${config.functions}`);\n }\n if (config.crons) {\n logger.log(`Loading crons from: ${config.crons}`);\n }\n if (config.subscribers) {\n logger.log(`Loading subscribers from: ${config.subscribers}`);\n }\n logger.log(`Using envParser: ${config.envParser}`);\n\n // Parse envParser configuration\n const [envParserPath, envParserName] = config.envParser.split('#');\n const envParserImportPattern = !envParserName\n ? 'envParser'\n : envParserName === 'envParser'\n ? '{ envParser }'\n : `{ ${envParserName} as envParser }`;\n\n // Parse logger configuration\n const [loggerPath, loggerName] = config.logger.split('#');\n const loggerImportPattern = !loggerName\n ? 'logger'\n : loggerName === 'logger'\n ? '{ logger }'\n : `{ ${loggerName} as logger }`;\n\n const buildContext: BuildContext = {\n envParserPath,\n envParserImportPattern,\n loggerPath,\n loggerImportPattern,\n };\n\n // Initialize generators\n const endpointGenerator = new EndpointGenerator();\n const functionGenerator = new FunctionGenerator();\n const cronGenerator = new CronGenerator();\n const subscriberGenerator = new SubscriberGenerator();\n\n // Load all constructs in parallel\n const [allEndpoints, allFunctions, allCrons, allSubscribers] =\n await Promise.all([\n endpointGenerator.load(config.routes),\n config.functions ? functionGenerator.load(config.functions) : [],\n config.crons ? cronGenerator.load(config.crons) : [],\n config.subscribers ? subscriberGenerator.load(config.subscribers) : [],\n ]);\n\n logger.log(`Found ${allEndpoints.length} endpoints`);\n logger.log(`Found ${allFunctions.length} functions`);\n logger.log(`Found ${allCrons.length} crons`);\n logger.log(`Found ${allSubscribers.length} subscribers`);\n\n if (\n allEndpoints.length === 0 &&\n allFunctions.length === 0 &&\n allCrons.length === 0 &&\n allSubscribers.length === 0\n ) {\n logger.log(\n 'No endpoints, functions, crons, or subscribers found to process',\n );\n return;\n }\n\n // Ensure .gkm directory exists\n const rootOutputDir = join(process.cwd(), '.gkm');\n await mkdir(rootOutputDir, { recursive: true });\n\n // Collect all build results from each provider\n const allBuildResults = await Promise.all(\n resolved.providers.map((provider) =>\n buildForProvider(\n provider,\n buildContext,\n endpointGenerator,\n functionGenerator,\n cronGenerator,\n subscriberGenerator,\n allEndpoints,\n allFunctions,\n allCrons,\n allSubscribers,\n resolved.enableOpenApi,\n ),\n ),\n );\n\n // Aggregate all routes, functions, crons, and subscribers from all providers\n const aggregatedRoutes = allBuildResults.flatMap((result) => result.routes);\n const aggregatedFunctions = allBuildResults.flatMap(\n (result) => result.functions,\n );\n const aggregatedCrons = allBuildResults.flatMap((result) => result.crons);\n const aggregatedSubscribers = allBuildResults.flatMap(\n (result) => result.subscribers,\n );\n\n // Generate single manifest at root .gkm directory\n await generateManifests(\n rootOutputDir,\n aggregatedRoutes,\n aggregatedFunctions,\n aggregatedCrons,\n aggregatedSubscribers,\n );\n}\n\ninterface BuildResult {\n routes: RouteInfo[];\n functions: FunctionInfo[];\n crons: CronInfo[];\n subscribers: SubscriberInfo[];\n}\n\nasync function buildForProvider(\n provider: LegacyProvider,\n context: BuildContext,\n endpointGenerator: EndpointGenerator,\n functionGenerator: FunctionGenerator,\n cronGenerator: CronGenerator,\n subscriberGenerator: SubscriberGenerator,\n endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],\n functions: GeneratedConstruct<Function<any, any, any, any>>[],\n crons: GeneratedConstruct<Cron<any, any, any, any>>[],\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n enableOpenApi: boolean,\n): Promise<BuildResult> {\n const outputDir = join(process.cwd(), '.gkm', provider);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n logger.log(`\\nGenerating handlers for provider: ${provider}`);\n\n // Build all constructs in parallel\n const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(\n [\n endpointGenerator.build(context, endpoints, outputDir, {\n provider,\n enableOpenApi,\n }),\n functionGenerator.build(context, functions, outputDir, { provider }),\n cronGenerator.build(context, crons, outputDir, { provider }),\n subscriberGenerator.build(context, subscribers, outputDir, { provider }),\n ],\n );\n\n logger.log(\n `Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,\n );\n\n // Return build results instead of generating manifest here\n return {\n routes,\n functions: functionInfos,\n crons: cronInfos,\n subscribers: subscriberInfos,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
require('../Generator-CDoEXCDg.cjs');
|
|
2
|
-
const require_SubscriberGenerator = require('../SubscriberGenerator-
|
|
2
|
+
const require_SubscriberGenerator = require('../SubscriberGenerator-CB-NHtZW.cjs');
|
|
3
3
|
|
|
4
4
|
exports.SubscriberGenerator = require_SubscriberGenerator.SubscriberGenerator;
|
|
@@ -2,7 +2,7 @@ const require_Generator = require('../Generator-CDoEXCDg.cjs');
|
|
|
2
2
|
const require_CronGenerator = require('../CronGenerator-1PflEYe2.cjs');
|
|
3
3
|
const require_EndpointGenerator = require('../EndpointGenerator-BbGrDiCP.cjs');
|
|
4
4
|
const require_FunctionGenerator = require('../FunctionGenerator-Clw64SwQ.cjs');
|
|
5
|
-
const require_SubscriberGenerator = require('../SubscriberGenerator-
|
|
5
|
+
const require_SubscriberGenerator = require('../SubscriberGenerator-CB-NHtZW.cjs');
|
|
6
6
|
require('../generators-CEKtVh81.cjs');
|
|
7
7
|
|
|
8
8
|
exports.ConstructGenerator = require_Generator.ConstructGenerator;
|
|
@@ -2,7 +2,7 @@ import { ConstructGenerator } from "../Generator-UanJW0_V.mjs";
|
|
|
2
2
|
import { CronGenerator } from "../CronGenerator-DXRfHQcV.mjs";
|
|
3
3
|
import { EndpointGenerator } from "../EndpointGenerator-BmZ9BxbO.mjs";
|
|
4
4
|
import { FunctionGenerator } from "../FunctionGenerator-DOEB_yPh.mjs";
|
|
5
|
-
import { SubscriberGenerator } from "../SubscriberGenerator-
|
|
5
|
+
import { SubscriberGenerator } from "../SubscriberGenerator-Cuu4co3-.mjs";
|
|
6
6
|
import "../generators-CsLujGXs.mjs";
|
|
7
7
|
|
|
8
8
|
export { ConstructGenerator, CronGenerator, EndpointGenerator, FunctionGenerator, SubscriberGenerator };
|
package/dist/index.cjs
CHANGED
|
@@ -5,18 +5,18 @@ require('./Generator-CDoEXCDg.cjs');
|
|
|
5
5
|
require('./CronGenerator-1PflEYe2.cjs');
|
|
6
6
|
require('./EndpointGenerator-BbGrDiCP.cjs');
|
|
7
7
|
require('./FunctionGenerator-Clw64SwQ.cjs');
|
|
8
|
-
require('./SubscriberGenerator-
|
|
8
|
+
require('./SubscriberGenerator-CB-NHtZW.cjs');
|
|
9
9
|
require('./generators-CEKtVh81.cjs');
|
|
10
10
|
require('./manifests-D0saShvH.cjs');
|
|
11
11
|
require('./providerResolver-DgvzNfP4.cjs');
|
|
12
|
-
const require_build = require('./build-
|
|
12
|
+
const require_build = require('./build-Ajg356_5.cjs');
|
|
13
13
|
const require_openapi_react_query = require('./openapi-react-query-Dvjqx_Eo.cjs');
|
|
14
14
|
const require_openapi = require('./openapi-CMLr04cz.cjs');
|
|
15
15
|
const commander = require_chunk.__toESM(require("commander"));
|
|
16
16
|
|
|
17
17
|
//#region package.json
|
|
18
18
|
var name = "@geekmidas/cli";
|
|
19
|
-
var version = "0.2.
|
|
19
|
+
var version = "0.2.2";
|
|
20
20
|
var private$1 = false;
|
|
21
21
|
var type = "module";
|
|
22
22
|
var exports$1 = {
|
|
@@ -45,9 +45,6 @@ var scripts = {
|
|
|
45
45
|
};
|
|
46
46
|
var dependencies = {
|
|
47
47
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
48
|
-
"@geekmidas/constructs": "workspace:*",
|
|
49
|
-
"@geekmidas/schema": "workspace:*",
|
|
50
|
-
"@geekmidas/envkit": "workspace:*",
|
|
51
48
|
"commander": "^12.1.0",
|
|
52
49
|
"fast-glob": "^3.3.2",
|
|
53
50
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -58,9 +55,14 @@ var devDependencies = {
|
|
|
58
55
|
"@geekmidas/testkit": "workspace:*",
|
|
59
56
|
"typescript": "^5.8.2",
|
|
60
57
|
"vitest": "^3.2.4",
|
|
61
|
-
"@geekmidas/logger": "workspace:*",
|
|
62
58
|
"zod": "^3.23.8"
|
|
63
59
|
};
|
|
60
|
+
var peerDependencies = {
|
|
61
|
+
"@geekmidas/constructs": "workspace:~",
|
|
62
|
+
"@geekmidas/schema": "workspace:~",
|
|
63
|
+
"@geekmidas/envkit": "workspace:~",
|
|
64
|
+
"@geekmidas/logger": "workspace:~"
|
|
65
|
+
};
|
|
64
66
|
var package_default = {
|
|
65
67
|
name,
|
|
66
68
|
version,
|
|
@@ -70,7 +72,8 @@ var package_default = {
|
|
|
70
72
|
bin,
|
|
71
73
|
scripts,
|
|
72
74
|
dependencies,
|
|
73
|
-
devDependencies
|
|
75
|
+
devDependencies,
|
|
76
|
+
peerDependencies
|
|
74
77
|
};
|
|
75
78
|
|
|
76
79
|
//#endregion
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Command","pkg","options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }","options: { output?: string }","options: { input?: string; output?: string; name?: string }"],"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@geekmidas/cli\",\n \"version\": \"0.2.
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Command","pkg","options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }","options: { output?: string }","options: { input?: string; output?: string; name?: string }"],"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@geekmidas/cli\",\n \"version\": \"0.2.2\",\n \"private\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./openapi\": {\n \"types\": \"./dist/openapi.d.ts\",\n \"import\": \"./dist/openapi.mjs\",\n \"require\": \"./dist/openapi.cjs\"\n },\n \"./openapi-react-query\": {\n \"types\": \"./dist/openapi-react-query.d.ts\",\n \"import\": \"./dist/openapi-react-query.mjs\",\n \"require\": \"./dist/openapi-react-query.cjs\"\n }\n },\n \"bin\": {\n \"gkm\": \"./dist/index.cjs\"\n },\n \"scripts\": {\n \"ts\": \"tsc --noEmit --skipLibCheck src/**/*.ts\",\n \"test\": \"vitest\",\n \"test:once\": \"vitest run\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"dependencies\": {\n \"@apidevtools/swagger-parser\": \"^10.1.0\",\n \"commander\": \"^12.1.0\",\n \"fast-glob\": \"^3.3.2\",\n \"lodash.kebabcase\": \"^4.1.1\",\n \"openapi-typescript\": \"^7.4.2\"\n },\n \"devDependencies\": {\n \"@types/lodash.kebabcase\": \"^4.1.9\",\n \"@geekmidas/testkit\": \"workspace:*\",\n \"typescript\": \"^5.8.2\",\n \"vitest\": \"^3.2.4\",\n \"zod\": \"^3.23.8\"\n },\n \"peerDependencies\": {\n \"@geekmidas/constructs\": \"workspace:~\",\n \"@geekmidas/schema\": \"workspace:~\",\n \"@geekmidas/envkit\": \"workspace:~\",\n \"@geekmidas/logger\": \"workspace:~\"\n }\n}\n","#!/usr/bin/env -S npx tsx\n\nimport { Command } from 'commander';\nimport pkg from '../package.json' assert { type: 'json' };\nimport { buildCommand } from './build/index.ts';\nimport { generateReactQueryCommand } from './openapi-react-query.ts';\nimport { openapiCommand } from './openapi.ts';\nimport type { LegacyProvider, MainProvider } from './types.ts';\n\nconst program = new Command();\n\nprogram\n .name('gkm')\n .description('GeekMidas backend framework CLI')\n .version(pkg.version)\n .option('--cwd <path>', 'Change working directory');\n\nprogram\n .command('build')\n .description('Build handlers from endpoints, functions, and crons')\n .option(\n '--provider <provider>',\n 'Target provider for generated handlers (aws, server)',\n )\n .option(\n '--providers <providers>',\n '[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)',\n )\n .option(\n '--enable-openapi',\n 'Enable OpenAPI documentation generation for server builds',\n )\n .action(\n async (options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n\n // Handle new single provider option\n if (options.provider) {\n if (!['aws', 'server'].includes(options.provider)) {\n console.error(\n `Invalid provider: ${options.provider}. Must be 'aws' or 'server'.`,\n );\n process.exit(1);\n }\n await buildCommand({\n provider: options.provider as MainProvider,\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n // Handle legacy providers option\n else if (options.providers) {\n console.warn(\n '⚠️ --providers flag is deprecated. Use --provider instead.',\n );\n const providerList = [\n ...new Set(options.providers.split(',').map((p) => p.trim())),\n ] as LegacyProvider[];\n await buildCommand({\n providers: providerList,\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n // Default to config-driven build\n else {\n await buildCommand({\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n } catch (error) {\n console.error('Build failed:', (error as Error).message);\n process.exit(1);\n }\n },\n );\n\nprogram\n .command('cron')\n .description('Manage cron jobs')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('Cron management - coming soon\\n');\n });\n\nprogram\n .command('function')\n .description('Manage serverless functions')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('Serverless function management - coming soon\\n');\n });\n\nprogram\n .command('api')\n .description('Manage REST API endpoints')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('REST API management - coming soon\\n');\n });\n\nprogram\n .command('openapi')\n .description('Generate OpenAPI 3.0 specification from endpoints')\n .option(\n '--output <path>',\n 'Output file path for the OpenAPI spec',\n 'openapi.json',\n )\n .action(async (options: { output?: string }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n await openapiCommand(options);\n } catch (error) {\n console.error('OpenAPI generation failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('generate:react-query')\n .description('Generate React Query hooks from OpenAPI specification')\n .option('--input <path>', 'Input OpenAPI spec file path', 'openapi.json')\n .option(\n '--output <path>',\n 'Output file path for generated hooks',\n 'src/api/hooks.ts',\n )\n .option('--name <name>', 'API name prefix for generated code', 'API')\n .action(\n async (options: { input?: string; output?: string; name?: string }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n await generateReactQueryCommand(options);\n } catch (error) {\n console.error(\n 'React Query generation failed:',\n (error as Error).message,\n );\n process.exit(1);\n }\n },\n );\n\nprogram.parse();\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -4,18 +4,18 @@ import "./Generator-UanJW0_V.mjs";
|
|
|
4
4
|
import "./CronGenerator-DXRfHQcV.mjs";
|
|
5
5
|
import "./EndpointGenerator-BmZ9BxbO.mjs";
|
|
6
6
|
import "./FunctionGenerator-DOEB_yPh.mjs";
|
|
7
|
-
import "./SubscriberGenerator-
|
|
7
|
+
import "./SubscriberGenerator-Cuu4co3-.mjs";
|
|
8
8
|
import "./generators-CsLujGXs.mjs";
|
|
9
9
|
import "./manifests-BrJXpHrf.mjs";
|
|
10
10
|
import "./providerResolver-B_TjNF0_.mjs";
|
|
11
|
-
import { buildCommand } from "./build-
|
|
11
|
+
import { buildCommand } from "./build-zpABVsc0.mjs";
|
|
12
12
|
import { generateReactQueryCommand } from "./openapi-react-query-DbrWwQzb.mjs";
|
|
13
13
|
import { openapiCommand } from "./openapi-BQx3_JbM.mjs";
|
|
14
14
|
import { Command } from "commander";
|
|
15
15
|
|
|
16
16
|
//#region package.json
|
|
17
17
|
var name = "@geekmidas/cli";
|
|
18
|
-
var version = "0.2.
|
|
18
|
+
var version = "0.2.2";
|
|
19
19
|
var private$1 = false;
|
|
20
20
|
var type = "module";
|
|
21
21
|
var exports = {
|
|
@@ -44,9 +44,6 @@ var scripts = {
|
|
|
44
44
|
};
|
|
45
45
|
var dependencies = {
|
|
46
46
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
47
|
-
"@geekmidas/constructs": "workspace:*",
|
|
48
|
-
"@geekmidas/schema": "workspace:*",
|
|
49
|
-
"@geekmidas/envkit": "workspace:*",
|
|
50
47
|
"commander": "^12.1.0",
|
|
51
48
|
"fast-glob": "^3.3.2",
|
|
52
49
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -57,9 +54,14 @@ var devDependencies = {
|
|
|
57
54
|
"@geekmidas/testkit": "workspace:*",
|
|
58
55
|
"typescript": "^5.8.2",
|
|
59
56
|
"vitest": "^3.2.4",
|
|
60
|
-
"@geekmidas/logger": "workspace:*",
|
|
61
57
|
"zod": "^3.23.8"
|
|
62
58
|
};
|
|
59
|
+
var peerDependencies = {
|
|
60
|
+
"@geekmidas/constructs": "workspace:~",
|
|
61
|
+
"@geekmidas/schema": "workspace:~",
|
|
62
|
+
"@geekmidas/envkit": "workspace:~",
|
|
63
|
+
"@geekmidas/logger": "workspace:~"
|
|
64
|
+
};
|
|
63
65
|
var package_default = {
|
|
64
66
|
name,
|
|
65
67
|
version,
|
|
@@ -69,7 +71,8 @@ var package_default = {
|
|
|
69
71
|
bin,
|
|
70
72
|
scripts,
|
|
71
73
|
dependencies,
|
|
72
|
-
devDependencies
|
|
74
|
+
devDependencies,
|
|
75
|
+
peerDependencies
|
|
73
76
|
};
|
|
74
77
|
|
|
75
78
|
//#endregion
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["pkg","options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }","options: { output?: string }","options: { input?: string; output?: string; name?: string }"],"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@geekmidas/cli\",\n \"version\": \"0.2.
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["pkg","options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }","options: { output?: string }","options: { input?: string; output?: string; name?: string }"],"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@geekmidas/cli\",\n \"version\": \"0.2.2\",\n \"private\": false,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./openapi\": {\n \"types\": \"./dist/openapi.d.ts\",\n \"import\": \"./dist/openapi.mjs\",\n \"require\": \"./dist/openapi.cjs\"\n },\n \"./openapi-react-query\": {\n \"types\": \"./dist/openapi-react-query.d.ts\",\n \"import\": \"./dist/openapi-react-query.mjs\",\n \"require\": \"./dist/openapi-react-query.cjs\"\n }\n },\n \"bin\": {\n \"gkm\": \"./dist/index.cjs\"\n },\n \"scripts\": {\n \"ts\": \"tsc --noEmit --skipLibCheck src/**/*.ts\",\n \"test\": \"vitest\",\n \"test:once\": \"vitest run\",\n \"test:coverage\": \"vitest run --coverage\"\n },\n \"dependencies\": {\n \"@apidevtools/swagger-parser\": \"^10.1.0\",\n \"commander\": \"^12.1.0\",\n \"fast-glob\": \"^3.3.2\",\n \"lodash.kebabcase\": \"^4.1.1\",\n \"openapi-typescript\": \"^7.4.2\"\n },\n \"devDependencies\": {\n \"@types/lodash.kebabcase\": \"^4.1.9\",\n \"@geekmidas/testkit\": \"workspace:*\",\n \"typescript\": \"^5.8.2\",\n \"vitest\": \"^3.2.4\",\n \"zod\": \"^3.23.8\"\n },\n \"peerDependencies\": {\n \"@geekmidas/constructs\": \"workspace:~\",\n \"@geekmidas/schema\": \"workspace:~\",\n \"@geekmidas/envkit\": \"workspace:~\",\n \"@geekmidas/logger\": \"workspace:~\"\n }\n}\n","#!/usr/bin/env -S npx tsx\n\nimport { Command } from 'commander';\nimport pkg from '../package.json' assert { type: 'json' };\nimport { buildCommand } from './build/index.ts';\nimport { generateReactQueryCommand } from './openapi-react-query.ts';\nimport { openapiCommand } from './openapi.ts';\nimport type { LegacyProvider, MainProvider } from './types.ts';\n\nconst program = new Command();\n\nprogram\n .name('gkm')\n .description('GeekMidas backend framework CLI')\n .version(pkg.version)\n .option('--cwd <path>', 'Change working directory');\n\nprogram\n .command('build')\n .description('Build handlers from endpoints, functions, and crons')\n .option(\n '--provider <provider>',\n 'Target provider for generated handlers (aws, server)',\n )\n .option(\n '--providers <providers>',\n '[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)',\n )\n .option(\n '--enable-openapi',\n 'Enable OpenAPI documentation generation for server builds',\n )\n .action(\n async (options: {\n provider?: string;\n providers?: string;\n enableOpenapi?: boolean;\n }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n\n // Handle new single provider option\n if (options.provider) {\n if (!['aws', 'server'].includes(options.provider)) {\n console.error(\n `Invalid provider: ${options.provider}. Must be 'aws' or 'server'.`,\n );\n process.exit(1);\n }\n await buildCommand({\n provider: options.provider as MainProvider,\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n // Handle legacy providers option\n else if (options.providers) {\n console.warn(\n '⚠️ --providers flag is deprecated. Use --provider instead.',\n );\n const providerList = [\n ...new Set(options.providers.split(',').map((p) => p.trim())),\n ] as LegacyProvider[];\n await buildCommand({\n providers: providerList,\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n // Default to config-driven build\n else {\n await buildCommand({\n enableOpenApi: options.enableOpenapi || false,\n });\n }\n } catch (error) {\n console.error('Build failed:', (error as Error).message);\n process.exit(1);\n }\n },\n );\n\nprogram\n .command('cron')\n .description('Manage cron jobs')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('Cron management - coming soon\\n');\n });\n\nprogram\n .command('function')\n .description('Manage serverless functions')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('Serverless function management - coming soon\\n');\n });\n\nprogram\n .command('api')\n .description('Manage REST API endpoints')\n .action(() => {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n process.stdout.write('REST API management - coming soon\\n');\n });\n\nprogram\n .command('openapi')\n .description('Generate OpenAPI 3.0 specification from endpoints')\n .option(\n '--output <path>',\n 'Output file path for the OpenAPI spec',\n 'openapi.json',\n )\n .action(async (options: { output?: string }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n await openapiCommand(options);\n } catch (error) {\n console.error('OpenAPI generation failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command('generate:react-query')\n .description('Generate React Query hooks from OpenAPI specification')\n .option('--input <path>', 'Input OpenAPI spec file path', 'openapi.json')\n .option(\n '--output <path>',\n 'Output file path for generated hooks',\n 'src/api/hooks.ts',\n )\n .option('--name <name>', 'API name prefix for generated code', 'API')\n .action(\n async (options: { input?: string; output?: string; name?: string }) => {\n try {\n const globalOptions = program.opts();\n if (globalOptions.cwd) {\n process.chdir(globalOptions.cwd);\n }\n await generateReactQueryCommand(options);\n } catch (error) {\n console.error(\n 'React Query generation failed:',\n (error as Error).message,\n );\n process.exit(1);\n }\n },\n );\n\nprogram.parse();\n"],"mappings":";;;;;;;;;;;;;;;;WACU;cACG;gBACA;WACH;cACG;CACT,KAAK;EACH,SAAS;EACT,UAAU;EACV,WAAW;CACZ;CACD,aAAa;EACX,SAAS;EACT,UAAU;EACV,WAAW;CACZ;CACD,yBAAyB;EACvB,SAAS;EACT,UAAU;EACV,WAAW;CACZ;AACF;UACM,EACL,OAAO,mBACR;cACU;CACT,MAAM;CACN,QAAQ;CACR,aAAa;CACb,iBAAiB;AAClB;mBACe;CACd,+BAA+B;CAC/B,aAAa;CACb,aAAa;CACb,oBAAoB;CACpB,sBAAsB;AACvB;sBACkB;CACjB,2BAA2B;CAC3B,sBAAsB;CACtB,cAAc;CACd,UAAU;CACV,OAAO;AACR;uBACmB;CAClB,yBAAyB;CACzB,qBAAqB;CACrB,qBAAqB;CACrB,qBAAqB;AACtB;sBAlDH;;;;;;;;;;;AAmDC;;;;AC1CD,MAAM,UAAU,IAAI;AAEpB,QACG,KAAK,MAAM,CACX,YAAY,kCAAkC,CAC9C,QAAQA,gBAAI,QAAQ,CACpB,OAAO,gBAAgB,2BAA2B;AAErD,QACG,QAAQ,QAAQ,CAChB,YAAY,sDAAsD,CAClE,OACC,yBACA,uDACD,CACA,OACC,2BACA,iGACD,CACA,OACC,oBACA,4DACD,CACA,OACC,OAAOC,YAID;AACJ,KAAI;EACF,MAAM,gBAAgB,QAAQ,MAAM;AACpC,MAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAIlC,MAAI,QAAQ,UAAU;AACpB,QAAK,CAAC,OAAO,QAAS,EAAC,SAAS,QAAQ,SAAS,EAAE;AACjD,YAAQ,OACL,oBAAoB,QAAQ,SAAS,8BACvC;AACD,YAAQ,KAAK,EAAE;GAChB;AACD,SAAM,aAAa;IACjB,UAAU,QAAQ;IAClB,eAAe,QAAQ,iBAAiB;GACzC,EAAC;EACH,WAEQ,QAAQ,WAAW;AAC1B,WAAQ,KACN,8DACD;GACD,MAAM,eAAe,CACnB,GAAG,IAAI,IAAI,QAAQ,UAAU,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAC7D;AACD,SAAM,aAAa;IACjB,WAAW;IACX,eAAe,QAAQ,iBAAiB;GACzC,EAAC;EACH,MAGC,OAAM,aAAa,EACjB,eAAe,QAAQ,iBAAiB,MACzC,EAAC;CAEL,SAAQ,OAAO;AACd,UAAQ,MAAM,iBAAkB,MAAgB,QAAQ;AACxD,UAAQ,KAAK,EAAE;CAChB;AACF,EACF;AAEH,QACG,QAAQ,OAAO,CACf,YAAY,mBAAmB,CAC/B,OAAO,MAAM;CACZ,MAAM,gBAAgB,QAAQ,MAAM;AACpC,KAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAElC,SAAQ,OAAO,MAAM,kCAAkC;AACxD,EAAC;AAEJ,QACG,QAAQ,WAAW,CACnB,YAAY,8BAA8B,CAC1C,OAAO,MAAM;CACZ,MAAM,gBAAgB,QAAQ,MAAM;AACpC,KAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAElC,SAAQ,OAAO,MAAM,iDAAiD;AACvE,EAAC;AAEJ,QACG,QAAQ,MAAM,CACd,YAAY,4BAA4B,CACxC,OAAO,MAAM;CACZ,MAAM,gBAAgB,QAAQ,MAAM;AACpC,KAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAElC,SAAQ,OAAO,MAAM,sCAAsC;AAC5D,EAAC;AAEJ,QACG,QAAQ,UAAU,CAClB,YAAY,oDAAoD,CAChE,OACC,mBACA,yCACA,eACD,CACA,OAAO,OAAOC,YAAiC;AAC9C,KAAI;EACF,MAAM,gBAAgB,QAAQ,MAAM;AACpC,MAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAElC,QAAM,eAAe,QAAQ;CAC9B,SAAQ,OAAO;AACd,UAAQ,MAAM,8BAA+B,MAAgB,QAAQ;AACrE,UAAQ,KAAK,EAAE;CAChB;AACF,EAAC;AAEJ,QACG,QAAQ,uBAAuB,CAC/B,YAAY,wDAAwD,CACpE,OAAO,kBAAkB,gCAAgC,eAAe,CACxE,OACC,mBACA,wCACA,mBACD,CACA,OAAO,iBAAiB,sCAAsC,MAAM,CACpE,OACC,OAAOC,YAAgE;AACrE,KAAI;EACF,MAAM,gBAAgB,QAAQ,MAAM;AACpC,MAAI,cAAc,IAChB,SAAQ,MAAM,cAAc,IAAI;AAElC,QAAM,0BAA0B,QAAQ;CACzC,SAAQ,OAAO;AACd,UAAQ,MACN,kCACC,MAAgB,QAClB;AACD,UAAQ,KAAK,EAAE;CAChB;AACF,EACF;AAEH,QAAQ,OAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,18 +28,20 @@
|
|
|
28
28
|
"commander": "^12.1.0",
|
|
29
29
|
"fast-glob": "^3.3.2",
|
|
30
30
|
"lodash.kebabcase": "^4.1.1",
|
|
31
|
-
"openapi-typescript": "^7.4.2"
|
|
32
|
-
"@geekmidas/constructs": "0.0.1",
|
|
33
|
-
"@geekmidas/schema": "0.0.1",
|
|
34
|
-
"@geekmidas/envkit": "0.0.7"
|
|
31
|
+
"openapi-typescript": "^7.4.2"
|
|
35
32
|
},
|
|
36
33
|
"devDependencies": {
|
|
37
34
|
"@types/lodash.kebabcase": "^4.1.9",
|
|
38
35
|
"typescript": "^5.8.2",
|
|
39
36
|
"vitest": "^3.2.4",
|
|
40
37
|
"zod": "^3.23.8",
|
|
41
|
-
"@geekmidas/testkit": "0.0.16"
|
|
42
|
-
|
|
38
|
+
"@geekmidas/testkit": "0.0.16"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@geekmidas/constructs": "~0.0.5",
|
|
42
|
+
"@geekmidas/schema": "~0.0.1",
|
|
43
|
+
"@geekmidas/logger": "~0.0.1",
|
|
44
|
+
"@geekmidas/envkit": "~0.0.7"
|
|
43
45
|
},
|
|
44
46
|
"scripts": {
|
|
45
47
|
"ts": "tsc --noEmit --skipLibCheck src/**/*.ts",
|
|
@@ -27,12 +27,8 @@ export class SubscriberGenerator extends ConstructGenerator<
|
|
|
27
27
|
const logger = console;
|
|
28
28
|
const subscriberInfos: SubscriberInfo[] = [];
|
|
29
29
|
|
|
30
|
-
if (constructs.length === 0) {
|
|
31
|
-
return subscriberInfos;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
30
|
if (provider === 'server') {
|
|
35
|
-
// Generate subscribers.ts for server-based polling
|
|
31
|
+
// Generate subscribers.ts for server-based polling (even if empty)
|
|
36
32
|
await this.generateServerSubscribersFile(outputDir, constructs);
|
|
37
33
|
|
|
38
34
|
logger.log(
|
|
@@ -43,6 +39,10 @@ export class SubscriberGenerator extends ConstructGenerator<
|
|
|
43
39
|
return subscriberInfos;
|
|
44
40
|
}
|
|
45
41
|
|
|
42
|
+
if (constructs.length === 0) {
|
|
43
|
+
return subscriberInfos;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
46
|
if (provider !== 'aws-lambda') {
|
|
47
47
|
return subscriberInfos;
|
|
48
48
|
}
|
|
@@ -113,6 +113,9 @@ export const handler = adapter.handler;
|
|
|
113
113
|
outputDir: string,
|
|
114
114
|
subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],
|
|
115
115
|
): Promise<string> {
|
|
116
|
+
// Ensure output directory exists
|
|
117
|
+
await mkdir(outputDir, { recursive: true });
|
|
118
|
+
|
|
116
119
|
const subscribersFileName = 'subscribers.ts';
|
|
117
120
|
const subscribersPath = join(outputDir, subscribersFileName);
|
|
118
121
|
|
|
@@ -249,6 +249,57 @@ describe('SubscriberGenerator', () => {
|
|
|
249
249
|
expect(subscriberInfos).toEqual([]);
|
|
250
250
|
});
|
|
251
251
|
|
|
252
|
+
it('should generate subscribers.ts file for server provider even with no subscribers', async () => {
|
|
253
|
+
const subscriberInfos = await generator.build(
|
|
254
|
+
context,
|
|
255
|
+
[],
|
|
256
|
+
outputDir,
|
|
257
|
+
{ provider: 'server' },
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
expect(subscriberInfos).toEqual([]);
|
|
261
|
+
|
|
262
|
+
// Check that subscribers.ts was generated
|
|
263
|
+
const subscribersPath = join(outputDir, 'subscribers.ts');
|
|
264
|
+
const subscribersContent = await readFile(subscribersPath, 'utf-8');
|
|
265
|
+
|
|
266
|
+
expect(subscribersContent).toContain('export async function setupSubscribers');
|
|
267
|
+
expect(subscribersContent).toContain('const subscribers = [');
|
|
268
|
+
expect(subscribersContent).toContain('import type { EnvironmentParser }');
|
|
269
|
+
expect(subscribersContent).toContain('import type { Logger }');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should generate subscribers.ts file for server provider with subscribers', async () => {
|
|
273
|
+
const constructs = [
|
|
274
|
+
createSubscriberConstruct('userEventSubscriber', [
|
|
275
|
+
'user.created',
|
|
276
|
+
'user.updated',
|
|
277
|
+
]),
|
|
278
|
+
createSubscriberConstruct('orderEventSubscriber', ['order.placed']),
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
const subscriberInfos = await generator.build(
|
|
282
|
+
context,
|
|
283
|
+
constructs,
|
|
284
|
+
outputDir,
|
|
285
|
+
{ provider: 'server' },
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
expect(subscriberInfos).toEqual([]);
|
|
289
|
+
|
|
290
|
+
// Check that subscribers.ts was generated
|
|
291
|
+
const subscribersPath = join(outputDir, 'subscribers.ts');
|
|
292
|
+
const subscribersContent = await readFile(subscribersPath, 'utf-8');
|
|
293
|
+
|
|
294
|
+
expect(subscribersContent).toContain('export async function setupSubscribers');
|
|
295
|
+
expect(subscribersContent).toContain('import { userEventSubscriber }');
|
|
296
|
+
expect(subscribersContent).toContain('import { orderEventSubscriber }');
|
|
297
|
+
expect(subscribersContent).toContain('const subscribers = [');
|
|
298
|
+
expect(subscribersContent).toContain('userEventSubscriber');
|
|
299
|
+
expect(subscribersContent).toContain('orderEventSubscriber');
|
|
300
|
+
expect(subscribersContent).toContain('Setting up subscribers in polling mode');
|
|
301
|
+
});
|
|
302
|
+
|
|
252
303
|
it('should handle subscribers with custom environment parser patterns', async () => {
|
|
253
304
|
const customContext = {
|
|
254
305
|
...context,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriberGenerator-BfMZCVNy.cjs","names":["ConstructGenerator","value: any","context: BuildContext","constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","subscriberInfos: SubscriberInfo[]","sourceFile: string","exportName: string","_subscriber: Subscriber<any, any, any, any, any, any>","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","exports"],"sources":["../src/generators/SubscriberGenerator.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { BuildContext } from '../build/types';\nimport type { SubscriberInfo } from '../types';\nimport {\n ConstructGenerator,\n type GeneratedConstruct,\n type GeneratorOptions,\n} from './Generator';\n\nexport class SubscriberGenerator extends ConstructGenerator<\n Subscriber<any, any, any, any, any, any>,\n SubscriberInfo[]\n> {\n isConstruct(value: any): value is Subscriber<any, any, any, any, any, any> {\n return Subscriber.isSubscriber(value);\n }\n\n async build(\n context: BuildContext,\n constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n outputDir: string,\n options?: GeneratorOptions,\n ): Promise<SubscriberInfo[]> {\n const provider = options?.provider || 'aws-lambda';\n const logger = console;\n const subscriberInfos: SubscriberInfo[] = [];\n\n if (constructs.length === 0) {\n return subscriberInfos;\n }\n\n if (provider === 'server') {\n // Generate subscribers.ts for server-based polling\n await this.generateServerSubscribersFile(outputDir, constructs);\n\n logger.log(\n `Generated server subscribers file with ${constructs.length} subscribers (polling mode)`,\n );\n\n // Return empty array as server subscribers don't have individual handlers\n return subscriberInfos;\n }\n\n if (provider !== 'aws-lambda') {\n return subscriberInfos;\n }\n\n // Create subscribers subdirectory\n const subscribersDir = join(outputDir, 'subscribers');\n await mkdir(subscribersDir, { recursive: true });\n\n // Generate subscriber handlers\n for (const { key, construct, path } of constructs) {\n const handlerFile = await this.generateSubscriberHandler(\n subscribersDir,\n path.relative,\n key,\n construct,\n context,\n );\n\n subscriberInfos.push({\n name: key,\n handler: relative(process.cwd(), handlerFile).replace(\n /\\.ts$/,\n '.handler',\n ),\n subscribedEvents: construct.subscribedEvents || [],\n timeout: construct.timeout,\n environment: await construct.getEnvironment(),\n });\n\n logger.log(`Generated subscriber handler: ${key}`);\n }\n\n return subscriberInfos;\n }\n\n private async generateSubscriberHandler(\n outputDir: string,\n sourceFile: string,\n exportName: string,\n _subscriber: Subscriber<any, any, any, any, any, any>,\n context: BuildContext,\n ): Promise<string> {\n const handlerFileName = `${exportName}.ts`;\n const handlerPath = join(outputDir, handlerFileName);\n\n const relativePath = relative(dirname(handlerPath), sourceFile);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n const relativeEnvParserPath = relative(\n dirname(handlerPath),\n context.envParserPath,\n );\n\n const content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaSubscriber(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n await writeFile(handlerPath, content);\n return handlerPath;\n }\n\n private async generateServerSubscribersFile(\n outputDir: string,\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n ): Promise<string> {\n const subscribersFileName = 'subscribers.ts';\n const subscribersPath = join(outputDir, subscribersFileName);\n\n // Group imports by file\n const importsByFile = new Map<string, string[]>();\n\n for (const { path, key } of subscribers) {\n const relativePath = relative(dirname(subscribersPath), path.relative);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n if (!importsByFile.has(importPath)) {\n importsByFile.set(importPath, []);\n }\n importsByFile.get(importPath)!.push(key);\n }\n\n // Generate import statements\n const imports = Array.from(importsByFile.entries())\n .map(\n ([importPath, exports]) =>\n `import { ${exports.join(', ')} } from '${importPath}';`,\n )\n .join('\\n');\n\n const allExportNames = subscribers.map(({ key }) => key);\n\n const content = `/**\n * Generated subscribers setup\n *\n * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This uses event polling which is not suitable for production.\n *\n * For production, use AWS Lambda with SQS/SNS event source mappings.\n * Lambda automatically:\n * - Scales based on queue depth\n * - Handles batch processing and retries\n * - Manages dead letter queues\n * - Provides better cost optimization\n *\n * This polling implementation is useful for:\n * - Local development and testing\n * - Understanding event flow without Lambda deployment\n *\n * Supported connection strings:\n * - sqs://region/account-id/queue-name (SQS queue)\n * - sns://region/account-id/topic-name (SNS topic)\n * - rabbitmq://host:port/queue-name (RabbitMQ)\n * - basic://in-memory (In-memory for testing)\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst subscribers = [\n ${allExportNames.join(',\\n ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupSubscribers(\n envParser: EnvironmentParser<any>,\n logger: Logger,\n): Promise<void> {\n logger.info('Setting up subscribers in polling mode (local development)');\n\n const config = envParser.create((get) => ({\n connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\n\n const serviceDiscovery = ServiceDiscovery.getInstance(logger, envParser);\n\n // Create connection once, outside the loop (more efficient)\n // EventConnectionFactory automatically determines the right connection type\n let connection: EventConnection;\n try {\n connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n\n const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n logger.info({ connectionType }, 'Created shared event connection');\n } catch (error) {\n logger.error({ error }, 'Failed to create event connection');\n return;\n }\n\n for (const subscriber of subscribers) {\n try {\n // Create subscriber from shared connection\n const eventSubscriber = await Subscriber.fromConnection(connection);\n\n // Register services\n const services = subscriber.services.length > 0\n ? await serviceDiscovery.register(subscriber.services)\n : {};\n\n // Subscribe to events\n const subscribedEvents = subscriber.subscribedEvents || [];\n\n if (subscribedEvents.length === 0) {\n logger.warn({ subscriber: subscriber.constructor.name }, 'Subscriber has no subscribed events, skipping');\n continue;\n }\n\n await eventSubscriber.subscribe(subscribedEvents, async (event) => {\n try {\n // Process single event (batch of 1)\n await subscriber.handler({\n events: [event],\n services: services as any,\n logger: subscriber.logger,\n });\n\n logger.debug({ eventType: event.type }, 'Successfully processed event');\n } catch (error) {\n logger.error({ error, event }, 'Failed to process event');\n // Event will become visible again for retry\n }\n });\n\n activeSubscribers.push(eventSubscriber);\n\n logger.info(\n {\n events: subscribedEvents,\n },\n 'Subscriber started polling'\n );\n } catch (error) {\n logger.error({ error, subscriber: subscriber.constructor.name }, 'Failed to setup subscriber');\n }\n }\n\n // Setup graceful shutdown\n const shutdown = () => {\n logger.info('Stopping all subscribers');\n for (const eventSubscriber of activeSubscribers) {\n connection.stop();\n }\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n}\n`;\n\n await writeFile(subscribersPath, content);\n return subscribersPath;\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAa,sBAAb,cAAyCA,qCAGvC;CACA,YAAYC,OAA+D;AACzE,SAAO,8CAAW,aAAa,MAAM;CACtC;CAED,MAAM,MACJC,SACAC,YACAC,WACAC,SAC2B;EAC3B,MAAM,WAAW,SAAS,YAAY;EACtC,MAAM,SAAS;EACf,MAAMC,kBAAoC,CAAE;AAE5C,MAAI,WAAW,WAAW,EACxB,QAAO;AAGT,MAAI,aAAa,UAAU;AAEzB,SAAM,KAAK,8BAA8B,WAAW,WAAW;AAE/D,UAAO,KACJ,yCAAyC,WAAW,OAAO,6BAC7D;AAGD,UAAO;EACR;AAED,MAAI,aAAa,aACf,QAAO;EAIT,MAAM,iBAAiB,oBAAK,WAAW,cAAc;AACrD,QAAM,4BAAM,gBAAgB,EAAE,WAAW,KAAM,EAAC;AAGhD,OAAK,MAAM,EAAE,KAAK,WAAW,MAAM,IAAI,YAAY;GACjD,MAAM,cAAc,MAAM,KAAK,0BAC7B,gBACA,KAAK,UACL,KACA,WACA,QACD;AAED,mBAAgB,KAAK;IACnB,MAAM;IACN,SAAS,wBAAS,QAAQ,KAAK,EAAE,YAAY,CAAC,QAC5C,SACA,WACD;IACD,kBAAkB,UAAU,oBAAoB,CAAE;IAClD,SAAS,UAAU;IACnB,aAAa,MAAM,UAAU,gBAAgB;GAC9C,EAAC;AAEF,UAAO,KAAK,gCAAgC,IAAI,EAAE;EACnD;AAED,SAAO;CACR;CAED,MAAc,0BACZF,WACAG,YACAC,YACAC,aACAP,SACiB;EACjB,MAAM,mBAAmB,EAAE,WAAW;EACtC,MAAM,cAAc,oBAAK,WAAW,gBAAgB;EAEpD,MAAM,eAAe,wBAAS,uBAAQ,YAAY,EAAE,WAAW;EAC/D,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;EAEvD,MAAM,wBAAwB,wBAC5B,uBAAQ,YAAY,EACpB,QAAQ,cACT;EAED,MAAM,WAAW;WACV,WAAW,WAAW,WAAW;SACnC,QAAQ,uBAAuB,SAAS,sBAAsB;;qDAElB,WAAW;;;;AAK5D,QAAM,gCAAU,aAAa,QAAQ;AACrC,SAAO;CACR;CAED,MAAc,8BACZE,WACAM,aACiB;EACjB,MAAM,sBAAsB;EAC5B,MAAM,kBAAkB,oBAAK,WAAW,oBAAoB;EAG5D,MAAM,gCAAgB,IAAI;AAE1B,OAAK,MAAM,EAAE,MAAM,KAAK,IAAI,aAAa;GACvC,MAAM,eAAe,wBAAS,uBAAQ,gBAAgB,EAAE,KAAK,SAAS;GACtE,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;AAEvD,QAAK,cAAc,IAAI,WAAW,CAChC,eAAc,IAAI,YAAY,CAAE,EAAC;AAEnC,iBAAc,IAAI,WAAW,CAAE,KAAK,IAAI;EACzC;EAGD,MAAM,UAAU,MAAM,KAAK,cAAc,SAAS,CAAC,CAChD,IACC,CAAC,CAAC,YAAYC,UAAQ,MACnB,WAAW,UAAQ,KAAK,KAAK,CAAC,WAAW,WAAW,IACxD,CACA,KAAK,KAAK;EAEb,MAAM,iBAAiB,YAAY,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI;EAExD,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BnB,QAAQ;;;IAGN,eAAe,KAAK,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+F7B,QAAM,gCAAU,iBAAiB,QAAQ;AACzC,SAAO;CACR;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriberGenerator-D2u00NI3.mjs","names":["value: any","context: BuildContext","constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","subscriberInfos: SubscriberInfo[]","sourceFile: string","exportName: string","_subscriber: Subscriber<any, any, any, any, any, any>","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]"],"sources":["../src/generators/SubscriberGenerator.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { BuildContext } from '../build/types';\nimport type { SubscriberInfo } from '../types';\nimport {\n ConstructGenerator,\n type GeneratedConstruct,\n type GeneratorOptions,\n} from './Generator';\n\nexport class SubscriberGenerator extends ConstructGenerator<\n Subscriber<any, any, any, any, any, any>,\n SubscriberInfo[]\n> {\n isConstruct(value: any): value is Subscriber<any, any, any, any, any, any> {\n return Subscriber.isSubscriber(value);\n }\n\n async build(\n context: BuildContext,\n constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n outputDir: string,\n options?: GeneratorOptions,\n ): Promise<SubscriberInfo[]> {\n const provider = options?.provider || 'aws-lambda';\n const logger = console;\n const subscriberInfos: SubscriberInfo[] = [];\n\n if (constructs.length === 0) {\n return subscriberInfos;\n }\n\n if (provider === 'server') {\n // Generate subscribers.ts for server-based polling\n await this.generateServerSubscribersFile(outputDir, constructs);\n\n logger.log(\n `Generated server subscribers file with ${constructs.length} subscribers (polling mode)`,\n );\n\n // Return empty array as server subscribers don't have individual handlers\n return subscriberInfos;\n }\n\n if (provider !== 'aws-lambda') {\n return subscriberInfos;\n }\n\n // Create subscribers subdirectory\n const subscribersDir = join(outputDir, 'subscribers');\n await mkdir(subscribersDir, { recursive: true });\n\n // Generate subscriber handlers\n for (const { key, construct, path } of constructs) {\n const handlerFile = await this.generateSubscriberHandler(\n subscribersDir,\n path.relative,\n key,\n construct,\n context,\n );\n\n subscriberInfos.push({\n name: key,\n handler: relative(process.cwd(), handlerFile).replace(\n /\\.ts$/,\n '.handler',\n ),\n subscribedEvents: construct.subscribedEvents || [],\n timeout: construct.timeout,\n environment: await construct.getEnvironment(),\n });\n\n logger.log(`Generated subscriber handler: ${key}`);\n }\n\n return subscriberInfos;\n }\n\n private async generateSubscriberHandler(\n outputDir: string,\n sourceFile: string,\n exportName: string,\n _subscriber: Subscriber<any, any, any, any, any, any>,\n context: BuildContext,\n ): Promise<string> {\n const handlerFileName = `${exportName}.ts`;\n const handlerPath = join(outputDir, handlerFileName);\n\n const relativePath = relative(dirname(handlerPath), sourceFile);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n const relativeEnvParserPath = relative(\n dirname(handlerPath),\n context.envParserPath,\n );\n\n const content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaSubscriber(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n await writeFile(handlerPath, content);\n return handlerPath;\n }\n\n private async generateServerSubscribersFile(\n outputDir: string,\n subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n ): Promise<string> {\n const subscribersFileName = 'subscribers.ts';\n const subscribersPath = join(outputDir, subscribersFileName);\n\n // Group imports by file\n const importsByFile = new Map<string, string[]>();\n\n for (const { path, key } of subscribers) {\n const relativePath = relative(dirname(subscribersPath), path.relative);\n const importPath = relativePath.replace(/\\.ts$/, '.js');\n\n if (!importsByFile.has(importPath)) {\n importsByFile.set(importPath, []);\n }\n importsByFile.get(importPath)!.push(key);\n }\n\n // Generate import statements\n const imports = Array.from(importsByFile.entries())\n .map(\n ([importPath, exports]) =>\n `import { ${exports.join(', ')} } from '${importPath}';`,\n )\n .join('\\n');\n\n const allExportNames = subscribers.map(({ key }) => key);\n\n const content = `/**\n * Generated subscribers setup\n *\n * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This uses event polling which is not suitable for production.\n *\n * For production, use AWS Lambda with SQS/SNS event source mappings.\n * Lambda automatically:\n * - Scales based on queue depth\n * - Handles batch processing and retries\n * - Manages dead letter queues\n * - Provides better cost optimization\n *\n * This polling implementation is useful for:\n * - Local development and testing\n * - Understanding event flow without Lambda deployment\n *\n * Supported connection strings:\n * - sqs://region/account-id/queue-name (SQS queue)\n * - sns://region/account-id/topic-name (SNS topic)\n * - rabbitmq://host:port/queue-name (RabbitMQ)\n * - basic://in-memory (In-memory for testing)\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst subscribers = [\n ${allExportNames.join(',\\n ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupSubscribers(\n envParser: EnvironmentParser<any>,\n logger: Logger,\n): Promise<void> {\n logger.info('Setting up subscribers in polling mode (local development)');\n\n const config = envParser.create((get) => ({\n connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\n\n const serviceDiscovery = ServiceDiscovery.getInstance(logger, envParser);\n\n // Create connection once, outside the loop (more efficient)\n // EventConnectionFactory automatically determines the right connection type\n let connection: EventConnection;\n try {\n connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n\n const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n logger.info({ connectionType }, 'Created shared event connection');\n } catch (error) {\n logger.error({ error }, 'Failed to create event connection');\n return;\n }\n\n for (const subscriber of subscribers) {\n try {\n // Create subscriber from shared connection\n const eventSubscriber = await Subscriber.fromConnection(connection);\n\n // Register services\n const services = subscriber.services.length > 0\n ? await serviceDiscovery.register(subscriber.services)\n : {};\n\n // Subscribe to events\n const subscribedEvents = subscriber.subscribedEvents || [];\n\n if (subscribedEvents.length === 0) {\n logger.warn({ subscriber: subscriber.constructor.name }, 'Subscriber has no subscribed events, skipping');\n continue;\n }\n\n await eventSubscriber.subscribe(subscribedEvents, async (event) => {\n try {\n // Process single event (batch of 1)\n await subscriber.handler({\n events: [event],\n services: services as any,\n logger: subscriber.logger,\n });\n\n logger.debug({ eventType: event.type }, 'Successfully processed event');\n } catch (error) {\n logger.error({ error, event }, 'Failed to process event');\n // Event will become visible again for retry\n }\n });\n\n activeSubscribers.push(eventSubscriber);\n\n logger.info(\n {\n events: subscribedEvents,\n },\n 'Subscriber started polling'\n );\n } catch (error) {\n logger.error({ error, subscriber: subscriber.constructor.name }, 'Failed to setup subscriber');\n }\n }\n\n // Setup graceful shutdown\n const shutdown = () => {\n logger.info('Stopping all subscribers');\n for (const eventSubscriber of activeSubscribers) {\n connection.stop();\n }\n };\n\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n}\n`;\n\n await writeFile(subscribersPath, content);\n return subscribersPath;\n }\n}\n"],"mappings":";;;;;;AAWA,IAAa,sBAAb,cAAyC,mBAGvC;CACA,YAAYA,OAA+D;AACzE,SAAO,WAAW,aAAa,MAAM;CACtC;CAED,MAAM,MACJC,SACAC,YACAC,WACAC,SAC2B;EAC3B,MAAM,WAAW,SAAS,YAAY;EACtC,MAAM,SAAS;EACf,MAAMC,kBAAoC,CAAE;AAE5C,MAAI,WAAW,WAAW,EACxB,QAAO;AAGT,MAAI,aAAa,UAAU;AAEzB,SAAM,KAAK,8BAA8B,WAAW,WAAW;AAE/D,UAAO,KACJ,yCAAyC,WAAW,OAAO,6BAC7D;AAGD,UAAO;EACR;AAED,MAAI,aAAa,aACf,QAAO;EAIT,MAAM,iBAAiB,KAAK,WAAW,cAAc;AACrD,QAAM,MAAM,gBAAgB,EAAE,WAAW,KAAM,EAAC;AAGhD,OAAK,MAAM,EAAE,KAAK,WAAW,MAAM,IAAI,YAAY;GACjD,MAAM,cAAc,MAAM,KAAK,0BAC7B,gBACA,KAAK,UACL,KACA,WACA,QACD;AAED,mBAAgB,KAAK;IACnB,MAAM;IACN,SAAS,SAAS,QAAQ,KAAK,EAAE,YAAY,CAAC,QAC5C,SACA,WACD;IACD,kBAAkB,UAAU,oBAAoB,CAAE;IAClD,SAAS,UAAU;IACnB,aAAa,MAAM,UAAU,gBAAgB;GAC9C,EAAC;AAEF,UAAO,KAAK,gCAAgC,IAAI,EAAE;EACnD;AAED,SAAO;CACR;CAED,MAAc,0BACZF,WACAG,YACAC,YACAC,aACAP,SACiB;EACjB,MAAM,mBAAmB,EAAE,WAAW;EACtC,MAAM,cAAc,KAAK,WAAW,gBAAgB;EAEpD,MAAM,eAAe,SAAS,QAAQ,YAAY,EAAE,WAAW;EAC/D,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;EAEvD,MAAM,wBAAwB,SAC5B,QAAQ,YAAY,EACpB,QAAQ,cACT;EAED,MAAM,WAAW;WACV,WAAW,WAAW,WAAW;SACnC,QAAQ,uBAAuB,SAAS,sBAAsB;;qDAElB,WAAW;;;;AAK5D,QAAM,UAAU,aAAa,QAAQ;AACrC,SAAO;CACR;CAED,MAAc,8BACZE,WACAM,aACiB;EACjB,MAAM,sBAAsB;EAC5B,MAAM,kBAAkB,KAAK,WAAW,oBAAoB;EAG5D,MAAM,gCAAgB,IAAI;AAE1B,OAAK,MAAM,EAAE,MAAM,KAAK,IAAI,aAAa;GACvC,MAAM,eAAe,SAAS,QAAQ,gBAAgB,EAAE,KAAK,SAAS;GACtE,MAAM,aAAa,aAAa,QAAQ,SAAS,MAAM;AAEvD,QAAK,cAAc,IAAI,WAAW,CAChC,eAAc,IAAI,YAAY,CAAE,EAAC;AAEnC,iBAAc,IAAI,WAAW,CAAE,KAAK,IAAI;EACzC;EAGD,MAAM,UAAU,MAAM,KAAK,cAAc,SAAS,CAAC,CAChD,IACC,CAAC,CAAC,YAAY,QAAQ,MACnB,WAAW,QAAQ,KAAK,KAAK,CAAC,WAAW,WAAW,IACxD,CACA,KAAK,KAAK;EAEb,MAAM,iBAAiB,YAAY,IAAI,CAAC,EAAE,KAAK,KAAK,IAAI;EAExD,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BnB,QAAQ;;;IAGN,eAAe,KAAK,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+F7B,QAAM,UAAU,iBAAiB,QAAQ;AACzC,SAAO;CACR;AACF"}
|