@geekmidas/cli 10.0.0-alpha.40 → 10.0.0-alpha.42

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/index.cjs CHANGED
@@ -6,10 +6,10 @@ const require_config = require("./config-CJ-PAb7M.cjs");
6
6
  const require_workspace = require("./workspace-RYSYtHP7.cjs");
7
7
  const require_storage = require("./storage-CSGoC3bK.cjs");
8
8
  const require_store = require("./store-DQgxT_WR.cjs");
9
- const require_workspace$1 = require("./workspace-BIqeeqcR.cjs");
9
+ const require_workspace$1 = require("./workspace-CPVcs6r_.cjs");
10
10
  const require_OpenApiTsGenerator = require("./OpenApiTsGenerator-B4Kj_qNU.cjs");
11
11
  const require_openapi = require("./openapi.cjs");
12
- const require_ready = require("./ready-mcxamf73.cjs");
12
+ const require_ready = require("./ready-DXqKVRYN.cjs");
13
13
  const require_emit = require("./emit-BdoPFjZf.cjs");
14
14
  let commander = require("commander");
15
15
  let node_process = require("node:process");
@@ -43,11 +43,10 @@ crypto = require_rolldown_runtime.__toESM(crypto, 1);
43
43
  let _geekmidas_constructs_crons = require("@geekmidas/constructs/crons");
44
44
  let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions");
45
45
  let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
46
- let _geekmidas_constructs_subscribers = require("@geekmidas/constructs/subscribers");
47
46
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
48
47
  let node_dns_promises = require("node:dns/promises");
49
48
  //#region package.json
50
- var version = "10.0.0-alpha.40";
49
+ var version = "10.0.0-alpha.42";
51
50
  //#endregion
52
51
  //#region src/auth/credentials.ts
53
52
  /**
@@ -1572,9 +1571,9 @@ async function workspaceDevCommand(workspace, options) {
1572
1571
  const fakes = options.fake ? await serveFakes(reconciled.fakes, reconciled.ports) : [];
1573
1572
  for (const { id, port } of fakes) logger$10.log(`🎭 ${id} fake: http://localhost:${port}`);
1574
1573
  if (options.migrate || options.seed) {
1575
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs"));
1574
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs"));
1576
1575
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
1577
- } else await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1576
+ } else await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
1578
1577
  logger$10.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
1579
1578
  });
1580
1579
  const appUrls = {};
@@ -2464,6 +2463,12 @@ export async function setupQueues(
2464
2463
  const services = queue.services.length > 0
2465
2464
  ? await serviceDiscovery.register(queue.services)
2466
2465
  : {};
2466
+ // The queue's database — the worker's, or its own — handed over as \`db\`.
2467
+ const db = queue.databaseService
2468
+ ? (await serviceDiscovery.register([queue.databaseService]))[
2469
+ queue.databaseService.serviceName
2470
+ ]
2471
+ : undefined;
2467
2472
 
2468
2473
  // A queue's messages carry one type — its own name.
2469
2474
  await eventSubscriber.subscribe([queue.name], async (message) => {
@@ -2478,7 +2483,8 @@ export async function setupQueues(
2478
2483
  messages: [validation.value],
2479
2484
  services: services,
2480
2485
  logger: queue.logger,
2481
- });
2486
+ db,
2487
+ } as any);
2482
2488
  } catch (error) {
2483
2489
  logger.error({ error, queue: queue.name }, 'Failed to process queue message');
2484
2490
  // Rethrown so the transport keeps the message for a retry.
@@ -2503,266 +2509,6 @@ export async function setupQueues(
2503
2509
  }
2504
2510
  };
2505
2511
  //#endregion
2506
- //#region src/generators/SubscriberGenerator.ts
2507
- var SubscriberGenerator = class extends require_discover.ConstructGenerator {
2508
- isConstruct(value) {
2509
- return _geekmidas_constructs_subscribers.Subscriber.isSubscriber(value);
2510
- }
2511
- async build(context, constructs, outputDir, options) {
2512
- const provider = options?.provider || "aws-lambda";
2513
- const logger = console;
2514
- const subscriberInfos = [];
2515
- if (provider === "server") {
2516
- await this.generateServerSubscribersFile(outputDir, constructs);
2517
- logger.log(`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`);
2518
- return subscriberInfos;
2519
- }
2520
- if (constructs.length === 0) return subscriberInfos;
2521
- if (provider !== "aws-lambda") return subscriberInfos;
2522
- const subscribersDir = (0, node_path.join)(outputDir, "subscribers");
2523
- await (0, node_fs_promises.mkdir)(subscribersDir, { recursive: true });
2524
- for (const { key, construct, path } of constructs) {
2525
- const handlerFile = await this.generateSubscriberHandler(subscribersDir, path.relative, key, construct, context, construct.owner);
2526
- subscriberInfos.push({
2527
- name: key,
2528
- handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
2529
- subscribedEvents: construct.subscribedEvents || [],
2530
- ...construct.topicName ? {
2531
- transport: "topic",
2532
- topic: construct.topicName
2533
- } : {},
2534
- timeout: construct.timeout,
2535
- memorySize: construct.memorySize,
2536
- environment: await construct.getEnvironment({ markOptional: context.markOptional }),
2537
- dependencies: construct.constructs
2538
- });
2539
- logger.log(`Generated subscriber handler: ${key}`);
2540
- }
2541
- return subscriberInfos;
2542
- }
2543
- async generateSubscriberHandler(outputDir, sourceFile, exportName, _subscriber, context, owner) {
2544
- const handlerFileName = `${exportName}.ts`;
2545
- const handlerPath = (0, node_path.join)(outputDir, handlerFileName);
2546
- const importPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile).replace(/\.ts$/, ".js");
2547
- const runtime = require_OpenApiTsGenerator.runtimeFor(context, (0, node_path.dirname)(handlerPath), owner);
2548
- const content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';
2549
- import { ${exportName} } from '${importPath}';
2550
- ${runtime.imports}
2551
- ${runtime.bindings}
2552
-
2553
- const adapter = new AWSLambdaSubscriber(envParser, ${exportName});
2554
-
2555
- export const handler = adapter.handler;
2556
- `;
2557
- await (0, node_fs_promises.writeFile)(handlerPath, content);
2558
- return handlerPath;
2559
- }
2560
- async generateServerSubscribersFile(outputDir, subscribers) {
2561
- await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
2562
- const subscribersPath = (0, node_path.join)(outputDir, "subscribers.ts");
2563
- if (subscribers.length === 0) {
2564
- await (0, node_fs_promises.writeFile)(subscribersPath, `/**
2565
- * Generated subscribers setup — this app declares none.
2566
- */
2567
- import type { EnvironmentParser } from '@geekmidas/envkit';
2568
- import type { Logger } from '@geekmidas/logger';
2569
-
2570
- export async function setupSubscribers(
2571
- _app: unknown,
2572
- _envParser: EnvironmentParser<any>,
2573
- _logger: Logger,
2574
- ): Promise<(port: number) => Promise<void>> {
2575
- return async () => {};
2576
- }
2577
- `);
2578
- return subscribersPath;
2579
- }
2580
- const importsByFile = /* @__PURE__ */ new Map();
2581
- for (const { path, key } of subscribers) {
2582
- const importPath = (0, node_path.relative)((0, node_path.dirname)(subscribersPath), path.relative).replace(/\.ts$/, ".js");
2583
- importsByFile.set(importPath, [...importsByFile.get(importPath) ?? [], key]);
2584
- }
2585
- const content = `/**
2586
- * Generated subscribers setup.
2587
- *
2588
- * Each subscriber is run against the topic it is bound to, through that
2589
- * topic's own connection string:
2590
- *
2591
- * - **sns://** — pushed, not polled. The subscriber gets an HTTP route on this
2592
- * server, and the route is subscribed to the topic with a filter policy of
2593
- * the events it named, so SNS fans out to each subscriber. The route runs the
2594
- * subscriber through the same adaptor a Lambda subscription does.
2595
- * - **anything else** (pgboss://, rabbitmq://, sqs://) — polled. On pg-boss
2596
- * each subscriber drains a queue of its own, \`<topic>/<subscriber>\`, so
2597
- * every subscriber sees every event; replicas of one subscriber share it.
2598
- *
2599
- * GKM_SUBSCRIBERS=off (\`gkm dev --no-subscribers\`) runs none of them.
2600
- * GKM_SUBSCRIBER_PUSH_URL is the address SNS pushes to; against the local
2601
- * emulator it defaults to this server through host.docker.internal.
2602
- */
2603
- import { connect } from 'node:net';
2604
- import type { EnvironmentParser } from '@geekmidas/envkit';
2605
- import type { Logger } from '@geekmidas/logger';
2606
- import { EventConnectionFactory, Subscriber } from '@geekmidas/events';
2607
- import type { EventConnection } from '@geekmidas/events';
2608
- import { ServiceDiscovery } from '@geekmidas/services';
2609
- ${Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n")}
2610
-
2611
- const subscribers = [
2612
- ${subscribers.map(({ key, construct }) => {
2613
- const connectionKey = construct.topicName ? (0, _geekmidas_manifest.provideKey)((0, _geekmidas_manifest.canonicalId)(construct.topicName), "publisherConnectionString") : void 0;
2614
- return ` { id: '${key}', subscriber: ${key}, topic: ${construct.topicName ? `'${construct.topicName}'` : "undefined"}, connectionKey: ${connectionKey ? `'${connectionKey}'` : "undefined"} },`;
2615
- }).join("\n")}
2616
- ];
2617
-
2618
- /** The route a subscriber's pushes arrive on. */
2619
- export const SUBSCRIBER_ROUTE = (id: string) => \`/__gkm/subscribers/\${id}\`;
2620
-
2621
- /** Resolves once something is accepting connections on the port. */
2622
- async function listening(port: number): Promise<void> {
2623
- for (let attempt = 0; attempt < 100; attempt++) {
2624
- const open = await new Promise<boolean>((resolve) => {
2625
- const socket = connect(port, '127.0.0.1');
2626
- socket.once('connect', () => { socket.end(); resolve(true); });
2627
- socket.once('error', () => resolve(false));
2628
- });
2629
- if (open) return;
2630
- await new Promise((resolve) => setTimeout(resolve, 50));
2631
- }
2632
- }
2633
-
2634
- /**
2635
- * Mount each pushed subscriber's route and start each polled one. Returns what
2636
- * to run once the server is listening: subscribing a route makes SNS send its
2637
- * confirmation at once, so the route has to be reachable first.
2638
- */
2639
- export async function setupSubscribers(
2640
- app: { post: (path: string, handler: (c: any) => unknown) => unknown },
2641
- envParser: EnvironmentParser<any>,
2642
- logger: Logger,
2643
- ): Promise<(port: number) => Promise<void>> {
2644
- if (process.env.GKM_SUBSCRIBERS === 'off') {
2645
- logger.info('Subscribers are off (--no-subscribers)');
2646
- return async () => {};
2647
- }
2648
-
2649
- const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
2650
- const connections = new Map<string, EventConnection>();
2651
- const afterListening: ((port: number) => Promise<void>)[] = [];
2652
-
2653
- for (const { id, subscriber, topic, connectionKey } of subscribers) {
2654
- const events = subscriber.subscribedEvents || [];
2655
- if (events.length === 0) {
2656
- logger.warn({ subscriber: id }, 'Subscriber has no subscribed events, skipping');
2657
- continue;
2658
- }
2659
- const connectionString = connectionKey ? process.env[connectionKey] : undefined;
2660
- if (!connectionString) {
2661
- logger.error(
2662
- { subscriber: id, connectionKey },
2663
- 'No connection string for the topic this subscriber is bound to',
2664
- );
2665
- continue;
2666
- }
2667
-
2668
- try {
2669
- if (connectionString.startsWith('sns:')) {
2670
- const { SNSConnection, snsUrl, subscribeHttpEndpoint } = await import('@geekmidas/events/sns');
2671
- const { SnsPushSubscriberAdaptor } = await import('@geekmidas/constructs/aws');
2672
- const address = snsUrl.parse(connectionString);
2673
- const route = SUBSCRIBER_ROUTE(id);
2674
- const adaptor = new SnsPushSubscriberAdaptor(envParser, subscriber, {
2675
- topicArn: address.topicArn,
2676
- // An emulator signs nothing. Decided by the address this server was
2677
- // configured with, never by anything a request says about itself.
2678
- verify: !address.endpoint,
2679
- ...(address.endpoint ? { emulatorEndpoint: address.endpoint } : {}),
2680
- });
2681
-
2682
- app.post(route, async (c: any) => {
2683
- const body = JSON.parse(await c.req.text());
2684
- const response = await adaptor.handle(body);
2685
- return c.json(response.body, response.status);
2686
- });
2687
-
2688
- afterListening.push(async (port) => {
2689
- const base =
2690
- process.env.GKM_SUBSCRIBER_PUSH_URL ??
2691
- (address.endpoint ? \`http://host.docker.internal:\${port}\` : undefined);
2692
- if (!base) {
2693
- logger.error(
2694
- { subscriber: id },
2695
- 'Set GKM_SUBSCRIBER_PUSH_URL to the public URL of this worker, which SNS pushes to',
2696
- );
2697
- return;
2698
- }
2699
- const connection = await SNSConnection.fromConnectionString(connectionString);
2700
- await subscribeHttpEndpoint(connection, {
2701
- endpoint: new URL(route, base).toString(),
2702
- events,
2703
- });
2704
- logger.info({ subscriber: id, events }, 'Subscriber subscribed for push');
2705
- });
2706
- continue;
2707
- }
2708
-
2709
- let connection = connections.get(connectionString);
2710
- if (!connection) {
2711
- connection = await EventConnectionFactory.fromConnectionString(connectionString);
2712
- connections.set(connectionString, connection);
2713
- }
2714
- // Named, so a broker with one address for everything (pg-boss) gives
2715
- // this subscriber a queue of its own: fan-out, not competition.
2716
- const eventSubscriber = await Subscriber.fromConnection(connection, {
2717
- topic,
2718
- subscription: id,
2719
- });
2720
- const services = subscriber.services.length > 0
2721
- ? await serviceDiscovery.register(subscriber.services)
2722
- : {};
2723
-
2724
- await eventSubscriber.subscribe(events, async (event) => {
2725
- try {
2726
- await subscriber.handler({
2727
- events: [event],
2728
- services: services as any,
2729
- logger: subscriber.logger,
2730
- });
2731
- } catch (error) {
2732
- logger.error({ error, event, subscriber: id }, 'Failed to process event');
2733
- // Rethrown so the transport keeps the event for a retry — as a queue
2734
- // consumer's failure does, and as a pushed subscriber's 500 does.
2735
- throw error;
2736
- }
2737
- });
2738
- logger.info({ subscriber: id, events }, 'Subscriber started polling');
2739
- } catch (error) {
2740
- logger.error({ error, subscriber: id }, 'Failed to set up subscriber');
2741
- }
2742
- }
2743
-
2744
- const shutdown = () => {
2745
- for (const connection of connections.values()) void connection.close();
2746
- };
2747
- process.once('SIGTERM', shutdown);
2748
- process.once('SIGINT', shutdown);
2749
-
2750
- return async (port) => {
2751
- if (afterListening.length === 0) return;
2752
- await listening(port);
2753
- for (const subscribe of afterListening) {
2754
- await subscribe(port).catch((error) => {
2755
- logger.error({ error }, 'Failed to subscribe for push');
2756
- });
2757
- }
2758
- };
2759
- }
2760
- `;
2761
- await (0, node_fs_promises.writeFile)(subscribersPath, content);
2762
- return subscribersPath;
2763
- }
2764
- };
2765
- //#endregion
2766
2512
  //#region src/generators/TopicGenerator.ts
2767
2513
  /**
2768
2514
  * Discovers topics (`new Topic(…)`) into `manifest.topics`. A topic is a
@@ -3260,7 +3006,7 @@ async function buildApp(input) {
3260
3006
  const endpointGenerator = new require_OpenApiTsGenerator.EndpointGenerator();
3261
3007
  const functionGenerator = new FunctionGenerator();
3262
3008
  const cronGenerator = new CronGenerator();
3263
- const subscriberGenerator = new SubscriberGenerator();
3009
+ const subscriberGenerator = new require_ready.SubscriberGenerator();
3264
3010
  const queueGenerator = new QueueGenerator();
3265
3011
  const topicGenerator = new TopicGenerator();
3266
3012
  const code = constructGlobs;
@@ -9588,26 +9334,26 @@ function loadPackageJson() {
9588
9334
  * Run: pnpm --filter @geekmidas/cli sync-versions
9589
9335
  */
9590
9336
  const GEEKMIDAS_VERSIONS = {
9591
- "@geekmidas/audit": "~10.0.0-alpha.40",
9592
- "@geekmidas/auth": "~10.0.0-alpha.40",
9593
- "@geekmidas/cache": "~10.0.0-alpha.40",
9594
- "@geekmidas/client": "~10.0.0-alpha.40",
9595
- "@geekmidas/cloud": "~10.0.0-alpha.40",
9596
- "@geekmidas/constructs": "~10.0.0-alpha.40",
9597
- "@geekmidas/db": "~10.0.0-alpha.40",
9598
- "@geekmidas/emailkit": "~10.0.0-alpha.40",
9599
- "@geekmidas/envkit": "~10.0.0-alpha.40",
9600
- "@geekmidas/errors": "~10.0.0-alpha.40",
9601
- "@geekmidas/events": "~10.0.0-alpha.40",
9602
- "@geekmidas/logger": "~10.0.0-alpha.40",
9603
- "@geekmidas/manifest": "~10.0.0-alpha.40",
9604
- "@geekmidas/rate-limit": "~10.0.0-alpha.40",
9605
- "@geekmidas/schema": "~10.0.0-alpha.40",
9606
- "@geekmidas/services": "~10.0.0-alpha.40",
9607
- "@geekmidas/storage": "~10.0.0-alpha.40",
9608
- "@geekmidas/studio": "~10.0.0-alpha.40",
9609
- "@geekmidas/telescope": "~10.0.0-alpha.40",
9610
- "@geekmidas/testkit": "~10.0.0-alpha.40",
9337
+ "@geekmidas/audit": "~10.0.0-alpha.42",
9338
+ "@geekmidas/auth": "~10.0.0-alpha.42",
9339
+ "@geekmidas/cache": "~10.0.0-alpha.42",
9340
+ "@geekmidas/client": "~10.0.0-alpha.42",
9341
+ "@geekmidas/cloud": "~10.0.0-alpha.42",
9342
+ "@geekmidas/constructs": "~10.0.0-alpha.42",
9343
+ "@geekmidas/db": "~10.0.0-alpha.42",
9344
+ "@geekmidas/emailkit": "~10.0.0-alpha.42",
9345
+ "@geekmidas/envkit": "~10.0.0-alpha.42",
9346
+ "@geekmidas/errors": "~10.0.0-alpha.42",
9347
+ "@geekmidas/events": "~10.0.0-alpha.42",
9348
+ "@geekmidas/logger": "~10.0.0-alpha.42",
9349
+ "@geekmidas/manifest": "~10.0.0-alpha.42",
9350
+ "@geekmidas/rate-limit": "~10.0.0-alpha.42",
9351
+ "@geekmidas/schema": "~10.0.0-alpha.42",
9352
+ "@geekmidas/services": "~10.0.0-alpha.42",
9353
+ "@geekmidas/storage": "~10.0.0-alpha.42",
9354
+ "@geekmidas/studio": "~10.0.0-alpha.42",
9355
+ "@geekmidas/telescope": "~10.0.0-alpha.42",
9356
+ "@geekmidas/testkit": "~10.0.0-alpha.42",
9611
9357
  "@geekmidas/cli": `~${loadPackageJson().version}`
9612
9358
  };
9613
9359
  //#endregion
@@ -16356,7 +16102,7 @@ function testDatabases(reconciled) {
16356
16102
  * starts without the reference data the app needs.
16357
16103
  */
16358
16104
  async function migrateTestStage(workspace, env) {
16359
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs"));
16105
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs"));
16360
16106
  const { discover } = await Promise.resolve().then(() => require("./discover-B0f_kuNN.cjs")).then((n) => n.discover_exports);
16361
16107
  const sources = {};
16362
16108
  const manifest = await discover({
@@ -16803,7 +16549,7 @@ program.command("migrate").description("Apply each database construct's migratio
16803
16549
  try {
16804
16550
  const globalOptions = program.opts();
16805
16551
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16806
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs"));
16552
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs"));
16807
16553
  await migrateCommand({
16808
16554
  ...options,
16809
16555
  ...construct ? { construct } : {}
@@ -16817,7 +16563,7 @@ program.command("seed").description("Migrate, then run each database construct's
16817
16563
  try {
16818
16564
  const globalOptions = program.opts();
16819
16565
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16820
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs"));
16566
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs"));
16821
16567
  await seedCommand({
16822
16568
  ...options,
16823
16569
  ...construct ? { construct } : {}
@@ -16831,7 +16577,7 @@ program.command("migration").description("Write a construct's next migration: an
16831
16577
  try {
16832
16578
  const globalOptions = program.opts();
16833
16579
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16834
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-CFOUApUt.cjs"));
16580
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-CM-pf0Mk.cjs"));
16835
16581
  await migrationCommand({
16836
16582
  construct,
16837
16583
  ...name ? { name } : {}
@@ -16970,7 +16716,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16970
16716
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16971
16717
  process.exit(1);
16972
16718
  }
16973
- const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-BIqeeqcR.cjs")).then((n) => n.workspace_exports);
16719
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-CPVcs6r_.cjs")).then((n) => n.workspace_exports);
16974
16720
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16975
16721
  if (!result) {
16976
16722
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);