@geekmidas/events 10.0.0-alpha.71 → 10.0.0-alpha.73

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.
Files changed (66) hide show
  1. package/README.md +46 -1
  2. package/dist/basic/index.cjs +19 -0
  3. package/dist/basic/index.cjs.map +1 -1
  4. package/dist/basic/index.d.cts +8 -1
  5. package/dist/basic/index.d.cts.map +1 -1
  6. package/dist/basic/index.d.mts +8 -1
  7. package/dist/basic/index.d.mts.map +1 -1
  8. package/dist/basic/index.mjs +19 -1
  9. package/dist/basic/index.mjs.map +1 -1
  10. package/dist/index.cjs +33 -137
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +15 -33
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +15 -33
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +30 -138
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/pgboss/index.cjs +41 -22
  19. package/dist/pgboss/index.cjs.map +1 -1
  20. package/dist/pgboss/index.d.cts +16 -1
  21. package/dist/pgboss/index.d.cts.map +1 -1
  22. package/dist/pgboss/index.d.mts +16 -1
  23. package/dist/pgboss/index.d.mts.map +1 -1
  24. package/dist/pgboss/index.mjs +41 -22
  25. package/dist/pgboss/index.mjs.map +1 -1
  26. package/dist/rabbitmq/index.cjs +28 -12
  27. package/dist/rabbitmq/index.cjs.map +1 -1
  28. package/dist/rabbitmq/index.d.cts +9 -1
  29. package/dist/rabbitmq/index.d.cts.map +1 -1
  30. package/dist/rabbitmq/index.d.mts +9 -1
  31. package/dist/rabbitmq/index.d.mts.map +1 -1
  32. package/dist/rabbitmq/index.mjs +29 -12
  33. package/dist/rabbitmq/index.mjs.map +1 -1
  34. package/dist/{types-gGaoT8qc.d.cts → registry-DIx25Q5s.d.cts} +108 -2
  35. package/dist/registry-DIx25Q5s.d.cts.map +1 -0
  36. package/dist/{types-gGaoT8qc.d.mts → registry-DIx25Q5s.d.mts} +108 -2
  37. package/dist/registry-DIx25Q5s.d.mts.map +1 -0
  38. package/dist/registry-DLnflkMm.mjs +99 -0
  39. package/dist/registry-DLnflkMm.mjs.map +1 -0
  40. package/dist/registry-DNk5GnGq.cjs +122 -0
  41. package/dist/registry-DNk5GnGq.cjs.map +1 -0
  42. package/dist/sns/index.cjs +261 -244
  43. package/dist/sns/index.cjs.map +1 -1
  44. package/dist/sns/index.d.cts +9 -1
  45. package/dist/sns/index.d.cts.map +1 -1
  46. package/dist/sns/index.d.mts +9 -1
  47. package/dist/sns/index.d.mts.map +1 -1
  48. package/dist/sns/index.mjs +261 -244
  49. package/dist/sns/index.mjs.map +1 -1
  50. package/dist/sqs/index.cjs +21 -0
  51. package/dist/sqs/index.cjs.map +1 -1
  52. package/dist/sqs/index.d.cts +9 -1
  53. package/dist/sqs/index.d.cts.map +1 -1
  54. package/dist/sqs/index.d.mts +9 -1
  55. package/dist/sqs/index.d.mts.map +1 -1
  56. package/dist/sqs/index.mjs +21 -1
  57. package/dist/sqs/index.mjs.map +1 -1
  58. package/package.json +3 -3
  59. package/dist/PgBossConnection-CywKoAZU.cjs +0 -2
  60. package/dist/PgBossConnection-DjoqT84r.mjs +0 -2
  61. package/dist/RabbitMQConnection-C9eccBL8.cjs +0 -2
  62. package/dist/RabbitMQConnection-CAp7VqyT.mjs +0 -2
  63. package/dist/SNSConnection-BWDC1wAF.cjs +0 -2
  64. package/dist/SNSConnection-ezQvVrDv.mjs +0 -2
  65. package/dist/types-gGaoT8qc.d.cts.map +0 -1
  66. package/dist/types-gGaoT8qc.d.mts.map +0 -1
@@ -1,24 +1,8 @@
1
+ import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
1
2
  import "../types-Bk5JM6MP.mjs";
2
3
  import { PgBoss } from "pg-boss";
3
- //#region src/pgboss/errors.ts
4
- /** pg-boss connected but its instance never started. */
5
- var PgBossNotStarted = class extends Error {
6
- constructor() {
7
- super("pg-boss did not start. Check the database in the connection string is reachable and the role may create the pg-boss schema.");
8
- this.name = "PgBossNotStarted";
9
- }
10
- };
11
- /** A topic subscription with no name to give the subscriber's own queue. */
12
- var PgBossSubscriptionNeedsName = class extends Error {
13
- topic;
14
- constructor(topic) {
15
- super(`Subscribing to topic '${topic}' on pg-boss needs a subscription name: each subscriber drains a queue of its own, and that queue is named for it. Pass \`subscription\`.`);
16
- this.topic = topic;
17
- this.name = "PgBossSubscriptionNeedsName";
18
- }
19
- };
20
- //#endregion
21
4
  //#region src/pgboss/PgBossConnection.ts
5
+ var PgBossConnection_exports = /* @__PURE__ */ __exportAll({ PgBossConnection: () => PgBossConnection });
22
6
  var PgBossConnection = class PgBossConnection {
23
7
  config;
24
8
  type = "pgboss";
@@ -50,9 +34,11 @@ var PgBossConnection = class PgBossConnection {
50
34
  }
51
35
  this.connecting = (async () => {
52
36
  try {
37
+ const applicationName = this.config.applicationName ?? process.env.GKM_APP_NAME;
53
38
  const boss = new PgBoss({
54
39
  connectionString: this.config.connectionString,
55
- ...this.config.schema && { schema: this.config.schema }
40
+ ...this.config.schema && { schema: this.config.schema },
41
+ ...applicationName && { application_name: applicationName }
56
42
  });
57
43
  await boss.start();
58
44
  this.boss = boss;
@@ -86,6 +72,24 @@ var PgBossConnection = class PgBossConnection {
86
72
  }
87
73
  };
88
74
  //#endregion
75
+ //#region src/pgboss/errors.ts
76
+ /** pg-boss connected but its instance never started. */
77
+ var PgBossNotStarted = class extends Error {
78
+ constructor() {
79
+ super("pg-boss did not start. Check the database in the connection string is reachable and the role may create the pg-boss schema.");
80
+ this.name = "PgBossNotStarted";
81
+ }
82
+ };
83
+ /** A topic subscription with no name to give the subscriber's own queue. */
84
+ var PgBossSubscriptionNeedsName = class extends Error {
85
+ topic;
86
+ constructor(topic) {
87
+ super(`Subscribing to topic '${topic}' on pg-boss needs a subscription name: each subscriber drains a queue of its own, and that queue is named for it. Pass \`subscription\`.`);
88
+ this.topic = topic;
89
+ this.name = "PgBossSubscriptionNeedsName";
90
+ }
91
+ };
92
+ //#endregion
89
93
  //#region src/pgboss/PgBossPublisher.ts
90
94
  /** The pg-boss event a topic's message type is published as. */
91
95
  function topicEvent(topic, type) {
@@ -103,7 +107,7 @@ var PgBossPublisher = class PgBossPublisher {
103
107
  * Format: pgboss://user:pass@host:5432/database?schema=pgboss
104
108
  */
105
109
  static async fromConnectionString(connectionString, options = {}) {
106
- const { PgBossConnection } = await import("../PgBossConnection-DjoqT84r.mjs");
110
+ const { PgBossConnection } = await Promise.resolve().then(() => PgBossConnection_exports);
107
111
  const connection = await PgBossConnection.fromConnectionString(connectionString);
108
112
  return new PgBossPublisher(connection, options);
109
113
  }
@@ -147,7 +151,7 @@ var PgBossSubscriber = class PgBossSubscriber {
147
151
  */
148
152
  static async fromConnectionString(connectionString) {
149
153
  const params = new URL(connectionString).searchParams;
150
- const { PgBossConnection } = await import("../PgBossConnection-DjoqT84r.mjs");
154
+ const { PgBossConnection } = await Promise.resolve().then(() => PgBossConnection_exports);
151
155
  const connection = await PgBossConnection.fromConnectionString(connectionString);
152
156
  const options = {
153
157
  batchSize: params.get("batchSize") ? Number.parseInt(params.get("batchSize"), 10) : void 0,
@@ -189,6 +193,21 @@ var PgBossSubscriber = class PgBossSubscriber {
189
193
  }
190
194
  };
191
195
  //#endregion
192
- export { PgBossConnection, PgBossNotStarted, PgBossPublisher, PgBossSubscriber, PgBossSubscriptionNeedsName, topicEvent };
196
+ //#region src/pgboss/driver.ts
197
+ /**
198
+ * `pgboss://` — queues and topics in Postgres. Register it with
199
+ * `registerEventsDriver(pgbossEventsDriver)`; this subpath is the only one
200
+ * that imports `pg-boss`.
201
+ */
202
+ const pgbossEventsDriver = {
203
+ scheme: "pgboss",
204
+ connect: (url) => PgBossConnection.fromConnectionString(url),
205
+ publisher: (url, options) => PgBossPublisher.fromConnectionString(url, options),
206
+ publisherFor: (connection, options) => new PgBossPublisher(connection, options),
207
+ subscriber: (url) => PgBossSubscriber.fromConnectionString(url),
208
+ subscriberFor: (connection, options) => new PgBossSubscriber(connection, options)
209
+ };
210
+ //#endregion
211
+ export { PgBossConnection, PgBossNotStarted, PgBossPublisher, PgBossSubscriber, PgBossSubscriptionNeedsName, pgbossEventsDriver, topicEvent };
193
212
 
194
213
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/pgboss/errors.ts","../../src/pgboss/PgBossConnection.ts","../../src/pgboss/PgBossPublisher.ts","../../src/pgboss/PgBossSubscriber.ts"],"sourcesContent":["// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** pg-boss connected but its instance never started. */\nexport class PgBossNotStarted extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'pg-boss did not start. Check the database in the connection string is reachable and the role may create the pg-boss schema.',\n\t\t);\n\t\tthis.name = 'PgBossNotStarted';\n\t}\n}\n\n/** A topic subscription with no name to give the subscriber's own queue. */\nexport class PgBossSubscriptionNeedsName extends Error {\n\tconstructor(readonly topic: string) {\n\t\tsuper(\n\t\t\t`Subscribing to topic '${topic}' on pg-boss needs a subscription name: ` +\n\t\t\t\t'each subscriber drains a queue of its own, and that queue is named ' +\n\t\t\t\t'for it. Pass `subscription`.',\n\t\t);\n\t\tthis.name = 'PgBossSubscriptionNeedsName';\n\t}\n}\n","import { PgBoss } from 'pg-boss';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface PgBossConnectionConfig {\n\tconnectionString: string;\n\tschema?: string;\n}\n\nexport class PgBossConnection implements EventConnection {\n\treadonly type = EventPublisherType.PgBoss;\n\tprivate boss?: PgBoss;\n\tprivate connecting?: Promise<void>;\n\n\tconstructor(private config: PgBossConnectionConfig) {}\n\n\t/**\n\t * Create a PgBossConnection from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<PgBossConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst postgresUrl = `postgres://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst config: PgBossConnectionConfig = {\n\t\t\tconnectionString: postgresUrl,\n\t\t\tschema: params.get('schema') || undefined,\n\t\t};\n\n\t\tconst connection = new PgBossConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.boss) return;\n\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst boss = new PgBoss({\n\t\t\t\t\tconnectionString: this.config.connectionString,\n\t\t\t\t\t...(this.config.schema && { schema: this.config.schema }),\n\t\t\t\t});\n\n\t\t\t\tawait boss.start();\n\t\t\t\tthis.boss = boss;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.boss?.stop({ graceful: true });\n\t\t} catch {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.boss;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.boss = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying pg-boss instance for publishing/subscribing\n\t */\n\tget instance(): PgBoss | undefined {\n\t\treturn this.boss;\n\t}\n}\n","import type { EventPublisher, PublishableMessage } from '../types';\nimport { PgBossNotStarted } from './errors';\nimport type { PgBossConnection } from './PgBossConnection';\n\nexport interface PgBossPublisherOptions {\n\t/**\n\t * Publishing to a topic: each message is fanned out to every subscriber's\n\t * own queue rather than inserted into one shared queue. Without it, a\n\t * message goes to the queue named by its type — a work queue, one consumer.\n\t */\n\ttopic?: string;\n}\n\n/** The pg-boss event a topic's message type is published as. */\nexport function topicEvent(topic: string, type: string): string {\n\treturn `${topic}/${type}`;\n}\n\nexport class PgBossPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: PgBossConnection,\n\t\tprivate options: PgBossPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a PgBossPublisher from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(\n\t\tconnectionString: string,\n\t\toptions: PgBossPublisherOptions = {},\n\t): Promise<PgBossPublisher<TMessage>> {\n\t\tconst { PgBossConnection } = await import('./PgBossConnection');\n\t\tconst connection =\n\t\t\tawait PgBossConnection.fromConnectionString(connectionString);\n\t\treturn new PgBossPublisher<TMessage>(connection, options);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst boss = this.connection.instance;\n\t\tif (!boss) {\n\t\t\tthrow new PgBossNotStarted();\n\t\t}\n\n\t\t// A topic: pg-boss copies the job into every queue subscribed to the\n\t\t// event — one per subscriber — so each subscriber sees each message.\n\t\t// The type rides in the data, because the job is named for the queue.\n\t\tconst { topic } = this.options;\n\t\tif (topic) {\n\t\t\tfor (const m of messages) {\n\t\t\t\tawait boss.publish(topicEvent(topic, m.type), {\n\t\t\t\t\ttype: m.type,\n\t\t\t\t\tpayload: m.payload,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Group jobs by queue name (v11+ requires per-queue insert calls)\n\t\tconst groups = new Map<string, { data: TMessage['payload'] }[]>();\n\t\tfor (const m of messages) {\n\t\t\tconst list = groups.get(m.type) ?? [];\n\t\t\tlist.push({ data: m.payload });\n\t\t\tgroups.set(m.type, list);\n\t\t}\n\n\t\tfor (const [name, jobs] of groups) {\n\t\t\tawait boss.createQueue(name);\n\t\t\tawait boss.insert(name, jobs);\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t}\n}\n","import type { EventSubscriber, PublishableMessage } from '../types';\nimport { PgBossNotStarted, PgBossSubscriptionNeedsName } from './errors';\nimport type { PgBossConnection } from './PgBossConnection';\nimport { topicEvent } from './PgBossPublisher';\n\nexport interface PgBossSubscriberOptions {\n\tbatchSize?: number;\n\tpollingIntervalSeconds?: number;\n\t/**\n\t * Subscribing to a topic. Each subscriber then drains a queue of its own,\n\t * `<topic>/<subscription>`, bound to the events it names — so every\n\t * subscriber sees every message, and replicas of one subscriber share it.\n\t * Without it, messages are drained from the queue named by their type:\n\t * work shared among whoever drains it.\n\t */\n\ttopic?: string;\n\t/** The subscriber's own name on the topic. Required with `topic`. */\n\tsubscription?: string;\n}\n\nexport class PgBossSubscriber<TMessage extends PublishableMessage<string, any>>\n\timplements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: PgBossConnection,\n\t\tprivate options: PgBossSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a PgBossSubscriber from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss&batchSize=5\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<PgBossSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { PgBossConnection } = await import('./PgBossConnection');\n\t\tconst connection =\n\t\t\tawait PgBossConnection.fromConnectionString(connectionString);\n\n\t\tconst options: PgBossSubscriberOptions = {\n\t\t\tbatchSize: params.get('batchSize')\n\t\t\t\t? Number.parseInt(params.get('batchSize')!, 10)\n\t\t\t\t: undefined,\n\t\t\tpollingIntervalSeconds: params.get('pollingIntervalSeconds')\n\t\t\t\t? Number.parseInt(params.get('pollingIntervalSeconds')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new PgBossSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst boss = this.connection.instance;\n\t\tif (!boss) {\n\t\t\tthrow new PgBossNotStarted();\n\t\t}\n\n\t\tconst work = {\n\t\t\t...(this.options.batchSize && { batchSize: this.options.batchSize }),\n\t\t\t...(this.options.pollingIntervalSeconds && {\n\t\t\t\tpollingIntervalSeconds: this.options.pollingIntervalSeconds,\n\t\t\t}),\n\t\t};\n\n\t\tconst { topic, subscription } = this.options;\n\t\tif (topic) {\n\t\t\tif (!subscription) throw new PgBossSubscriptionNeedsName(topic);\n\n\t\t\tconst queue = topicEvent(topic, subscription);\n\t\t\tawait boss.createQueue(queue);\n\t\t\tfor (const type of messages) {\n\t\t\t\tawait boss.subscribe(topicEvent(topic, type), queue);\n\t\t\t}\n\t\t\tawait boss.work<{ type: string; payload: unknown }>(\n\t\t\t\tqueue,\n\t\t\t\twork,\n\t\t\t\tasync (jobs) => {\n\t\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\t\tawait listener({\n\t\t\t\t\t\t\ttype: job.data.type,\n\t\t\t\t\t\t\tpayload: job.data.payload,\n\t\t\t\t\t\t} as TMessage);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const messageType of messages) {\n\t\t\tawait boss.createQueue(messageType);\n\t\t\tawait boss.work(messageType, work, async (jobs) => {\n\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\tconst fullMessage = {\n\t\t\t\t\t\ttype: job.name,\n\t\t\t\t\t\tpayload: job.data,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\tawait listener(fullMessage);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/pgboss/PgBossConnection.ts","../../src/pgboss/errors.ts","../../src/pgboss/PgBossPublisher.ts","../../src/pgboss/PgBossSubscriber.ts","../../src/pgboss/driver.ts"],"sourcesContent":["import { PgBoss } from 'pg-boss';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface PgBossConnectionConfig {\n\tconnectionString: string;\n\tschema?: string;\n\t/**\n\t * Who this connection is to Postgres. Defaults to `GKM_APP_NAME`, which a\n\t * generated entry sets to the construct it runs — so the broker's\n\t * connections are named for the process that holds them, as its database\n\t * pools are, rather than all being `pgboss`.\n\t */\n\tapplicationName?: string;\n}\n\nexport class PgBossConnection implements EventConnection {\n\treadonly type = EventPublisherType.PgBoss;\n\tprivate boss?: PgBoss;\n\tprivate connecting?: Promise<void>;\n\n\tconstructor(private config: PgBossConnectionConfig) {}\n\n\t/**\n\t * Create a PgBossConnection from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<PgBossConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst postgresUrl = `postgres://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst config: PgBossConnectionConfig = {\n\t\t\tconnectionString: postgresUrl,\n\t\t\tschema: params.get('schema') || undefined,\n\t\t};\n\n\t\tconst connection = new PgBossConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.boss) return;\n\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst applicationName =\n\t\t\t\t\tthis.config.applicationName ?? process.env.GKM_APP_NAME;\n\t\t\t\tconst boss = new PgBoss({\n\t\t\t\t\tconnectionString: this.config.connectionString,\n\t\t\t\t\t...(this.config.schema && { schema: this.config.schema }),\n\t\t\t\t\t...(applicationName && { application_name: applicationName }),\n\t\t\t\t});\n\n\t\t\t\tawait boss.start();\n\t\t\t\tthis.boss = boss;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.boss?.stop({ graceful: true });\n\t\t} catch {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.boss;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.boss = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying pg-boss instance for publishing/subscribing\n\t */\n\tget instance(): PgBoss | undefined {\n\t\treturn this.boss;\n\t}\n}\n","// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** pg-boss connected but its instance never started. */\nexport class PgBossNotStarted extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'pg-boss did not start. Check the database in the connection string is reachable and the role may create the pg-boss schema.',\n\t\t);\n\t\tthis.name = 'PgBossNotStarted';\n\t}\n}\n\n/** A topic subscription with no name to give the subscriber's own queue. */\nexport class PgBossSubscriptionNeedsName extends Error {\n\tconstructor(readonly topic: string) {\n\t\tsuper(\n\t\t\t`Subscribing to topic '${topic}' on pg-boss needs a subscription name: ` +\n\t\t\t\t'each subscriber drains a queue of its own, and that queue is named ' +\n\t\t\t\t'for it. Pass `subscription`.',\n\t\t);\n\t\tthis.name = 'PgBossSubscriptionNeedsName';\n\t}\n}\n","import type { EventPublisher, PublishableMessage } from '../types';\nimport { PgBossNotStarted } from './errors';\nimport type { PgBossConnection } from './PgBossConnection';\n\nexport interface PgBossPublisherOptions {\n\t/**\n\t * Publishing to a topic: each message is fanned out to every subscriber's\n\t * own queue rather than inserted into one shared queue. Without it, a\n\t * message goes to the queue named by its type — a work queue, one consumer.\n\t */\n\ttopic?: string;\n}\n\n/** The pg-boss event a topic's message type is published as. */\nexport function topicEvent(topic: string, type: string): string {\n\treturn `${topic}/${type}`;\n}\n\nexport class PgBossPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: PgBossConnection,\n\t\tprivate options: PgBossPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a PgBossPublisher from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(\n\t\tconnectionString: string,\n\t\toptions: PgBossPublisherOptions = {},\n\t): Promise<PgBossPublisher<TMessage>> {\n\t\tconst { PgBossConnection } = await import('./PgBossConnection');\n\t\tconst connection =\n\t\t\tawait PgBossConnection.fromConnectionString(connectionString);\n\t\treturn new PgBossPublisher<TMessage>(connection, options);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst boss = this.connection.instance;\n\t\tif (!boss) {\n\t\t\tthrow new PgBossNotStarted();\n\t\t}\n\n\t\t// A topic: pg-boss copies the job into every queue subscribed to the\n\t\t// event — one per subscriber — so each subscriber sees each message.\n\t\t// The type rides in the data, because the job is named for the queue.\n\t\tconst { topic } = this.options;\n\t\tif (topic) {\n\t\t\tfor (const m of messages) {\n\t\t\t\tawait boss.publish(topicEvent(topic, m.type), {\n\t\t\t\t\ttype: m.type,\n\t\t\t\t\tpayload: m.payload,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Group jobs by queue name (v11+ requires per-queue insert calls)\n\t\tconst groups = new Map<string, { data: TMessage['payload'] }[]>();\n\t\tfor (const m of messages) {\n\t\t\tconst list = groups.get(m.type) ?? [];\n\t\t\tlist.push({ data: m.payload });\n\t\t\tgroups.set(m.type, list);\n\t\t}\n\n\t\tfor (const [name, jobs] of groups) {\n\t\t\tawait boss.createQueue(name);\n\t\t\tawait boss.insert(name, jobs);\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t}\n}\n","import type { EventSubscriber, PublishableMessage } from '../types';\nimport { PgBossNotStarted, PgBossSubscriptionNeedsName } from './errors';\nimport type { PgBossConnection } from './PgBossConnection';\nimport { topicEvent } from './PgBossPublisher';\n\nexport interface PgBossSubscriberOptions {\n\tbatchSize?: number;\n\tpollingIntervalSeconds?: number;\n\t/**\n\t * Subscribing to a topic. Each subscriber then drains a queue of its own,\n\t * `<topic>/<subscription>`, bound to the events it names — so every\n\t * subscriber sees every message, and replicas of one subscriber share it.\n\t * Without it, messages are drained from the queue named by their type:\n\t * work shared among whoever drains it.\n\t */\n\ttopic?: string;\n\t/** The subscriber's own name on the topic. Required with `topic`. */\n\tsubscription?: string;\n}\n\nexport class PgBossSubscriber<TMessage extends PublishableMessage<string, any>>\n\timplements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: PgBossConnection,\n\t\tprivate options: PgBossSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a PgBossSubscriber from a connection string.\n\t * Format: pgboss://user:pass@host:5432/database?schema=pgboss&batchSize=5\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<PgBossSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { PgBossConnection } = await import('./PgBossConnection');\n\t\tconst connection =\n\t\t\tawait PgBossConnection.fromConnectionString(connectionString);\n\n\t\tconst options: PgBossSubscriberOptions = {\n\t\t\tbatchSize: params.get('batchSize')\n\t\t\t\t? Number.parseInt(params.get('batchSize')!, 10)\n\t\t\t\t: undefined,\n\t\t\tpollingIntervalSeconds: params.get('pollingIntervalSeconds')\n\t\t\t\t? Number.parseInt(params.get('pollingIntervalSeconds')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new PgBossSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst boss = this.connection.instance;\n\t\tif (!boss) {\n\t\t\tthrow new PgBossNotStarted();\n\t\t}\n\n\t\tconst work = {\n\t\t\t...(this.options.batchSize && { batchSize: this.options.batchSize }),\n\t\t\t...(this.options.pollingIntervalSeconds && {\n\t\t\t\tpollingIntervalSeconds: this.options.pollingIntervalSeconds,\n\t\t\t}),\n\t\t};\n\n\t\tconst { topic, subscription } = this.options;\n\t\tif (topic) {\n\t\t\tif (!subscription) throw new PgBossSubscriptionNeedsName(topic);\n\n\t\t\tconst queue = topicEvent(topic, subscription);\n\t\t\tawait boss.createQueue(queue);\n\t\t\tfor (const type of messages) {\n\t\t\t\tawait boss.subscribe(topicEvent(topic, type), queue);\n\t\t\t}\n\t\t\tawait boss.work<{ type: string; payload: unknown }>(\n\t\t\t\tqueue,\n\t\t\t\twork,\n\t\t\t\tasync (jobs) => {\n\t\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\t\tawait listener({\n\t\t\t\t\t\t\ttype: job.data.type,\n\t\t\t\t\t\t\tpayload: job.data.payload,\n\t\t\t\t\t\t} as TMessage);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const messageType of messages) {\n\t\t\tawait boss.createQueue(messageType);\n\t\t\tawait boss.work(messageType, work, async (jobs) => {\n\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\tconst fullMessage = {\n\t\t\t\t\t\ttype: job.name,\n\t\t\t\t\t\tpayload: job.data,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\tawait listener(fullMessage);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n}\n","import type { EventsDriver } from '../registry';\nimport { EventPublisherType } from '../types';\nimport { PgBossConnection } from './PgBossConnection';\nimport { PgBossPublisher } from './PgBossPublisher';\nimport { PgBossSubscriber } from './PgBossSubscriber';\n\n/**\n * `pgboss://` — queues and topics in Postgres. Register it with\n * `registerEventsDriver(pgbossEventsDriver)`; this subpath is the only one\n * that imports `pg-boss`.\n */\nexport const pgbossEventsDriver: EventsDriver = {\n\tscheme: EventPublisherType.PgBoss,\n\tconnect: (url) => PgBossConnection.fromConnectionString(url),\n\tpublisher: (url, options) =>\n\t\tPgBossPublisher.fromConnectionString(url, options),\n\tpublisherFor: (connection, options) =>\n\t\tnew PgBossPublisher(connection as PgBossConnection, options),\n\tsubscriber: (url) => PgBossSubscriber.fromConnectionString(url),\n\tsubscriberFor: (connection, options) =>\n\t\tnew PgBossSubscriber(connection as PgBossConnection, options),\n};\n"],"mappings":"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"}
@@ -3,16 +3,8 @@ const require_rolldown_runtime = require("../rolldown-runtime-C0BPl7ul.cjs");
3
3
  require("../types-BcZjLxVV.cjs");
4
4
  let amqplib = require("amqplib");
5
5
  amqplib = require_rolldown_runtime.__toESM(amqplib, 1);
6
- //#region src/rabbitmq/errors.ts
7
- /** The connection opened but has no channel to publish or consume on. */
8
- var RabbitMQChannelUnavailable = class extends Error {
9
- constructor() {
10
- super("RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.");
11
- this.name = "RabbitMQChannelUnavailable";
12
- }
13
- };
14
- //#endregion
15
6
  //#region src/rabbitmq/RabbitMQConnection.ts
7
+ var RabbitMQConnection_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({ RabbitMQConnection: () => RabbitMQConnection });
16
8
  var RabbitMQConnection = class RabbitMQConnection {
17
9
  type = "rabbitmq";
18
10
  connection;
@@ -113,6 +105,15 @@ var RabbitMQConnection = class RabbitMQConnection {
113
105
  }
114
106
  };
115
107
  //#endregion
108
+ //#region src/rabbitmq/errors.ts
109
+ /** The connection opened but has no channel to publish or consume on. */
110
+ var RabbitMQChannelUnavailable = class extends Error {
111
+ constructor() {
112
+ super("RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.");
113
+ this.name = "RabbitMQChannelUnavailable";
114
+ }
115
+ };
116
+ //#endregion
116
117
  //#region src/rabbitmq/RabbitMQPublisher.ts
117
118
  var RabbitMQPublisher = class RabbitMQPublisher {
118
119
  connection;
@@ -126,7 +127,7 @@ var RabbitMQPublisher = class RabbitMQPublisher {
126
127
  * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000
127
128
  */
128
129
  static async fromConnectionString(connectionString) {
129
- const { RabbitMQConnection } = await Promise.resolve().then(() => require("../RabbitMQConnection-C9eccBL8.cjs"));
130
+ const { RabbitMQConnection } = await Promise.resolve().then(() => RabbitMQConnection_exports);
130
131
  const connection = await RabbitMQConnection.fromConnectionString(connectionString);
131
132
  return new RabbitMQPublisher(connection);
132
133
  }
@@ -164,7 +165,7 @@ var RabbitMQSubscriber = class RabbitMQSubscriber {
164
165
  */
165
166
  static async fromConnectionString(connectionString) {
166
167
  const params = new URL(connectionString).searchParams;
167
- const { RabbitMQConnection } = await Promise.resolve().then(() => require("../RabbitMQConnection-C9eccBL8.cjs"));
168
+ const { RabbitMQConnection } = await Promise.resolve().then(() => RabbitMQConnection_exports);
168
169
  const connection = await RabbitMQConnection.fromConnectionString(connectionString);
169
170
  const options = {
170
171
  queueName: params.get("queueName") || void 0,
@@ -202,10 +203,25 @@ var RabbitMQSubscriber = class RabbitMQSubscriber {
202
203
  }
203
204
  };
204
205
  //#endregion
206
+ //#region src/rabbitmq/driver.ts
207
+ /**
208
+ * `rabbitmq://` — an AMQP exchange. Register it with
209
+ * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one
210
+ * that imports `amqplib`.
211
+ */
212
+ const rabbitmqEventsDriver = {
213
+ scheme: "rabbitmq",
214
+ connect: (url) => RabbitMQConnection.fromConnectionString(url),
215
+ publisher: (url) => RabbitMQPublisher.fromConnectionString(url),
216
+ publisherFor: (connection) => new RabbitMQPublisher(connection),
217
+ subscriber: (url) => RabbitMQSubscriber.fromConnectionString(url),
218
+ subscriberFor: (connection) => new RabbitMQSubscriber(connection)
219
+ };
220
+ //#endregion
205
221
  exports.RabbitMQChannelUnavailable = RabbitMQChannelUnavailable;
206
222
  exports.RabbitMQConnection = RabbitMQConnection;
207
- exports.RabbitMQConnection$1 = RabbitMQConnection;
208
223
  exports.RabbitMQPublisher = RabbitMQPublisher;
209
224
  exports.RabbitMQSubscriber = RabbitMQSubscriber;
225
+ exports.rabbitmqEventsDriver = rabbitmqEventsDriver;
210
226
 
211
227
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"sourcesContent":["// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** The connection opened but has no channel to publish or consume on. */\nexport class RabbitMQChannelUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.',\n\t\t);\n\t\tthis.name = 'RabbitMQChannelUnavailable';\n\t}\n}\n","import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n\turl: string;\n\texchange?: string;\n\texchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n\texchangeOptions?: amqplib.Options.AssertExchange;\n\ttimeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n\treadonly type = EventPublisherType.RabbitMQ;\n\tprivate connection?: amqplib.ChannelModel;\n\tprivate channel?: amqplib.Channel;\n\tprivate connecting?: Promise<void>;\n\tprivate config: Required<\n\t\tPick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n\t> &\n\t\tRabbitMQConnectionConfig;\n\n\tconstructor(config: RabbitMQConnectionConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\texchange: config.exchange || 'geekmidas.events',\n\t\t\texchangeType: config.exchangeType || 'topic',\n\t\t\ttimeout: config.timeout ?? 5000,\n\t\t\texchangeOptions: {\n\t\t\t\tdurable: true,\n\t\t\t\t...config.exchangeOptions,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Create a RabbitMQConnection from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<RabbitMQConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\t// Extract connection URL without query params\n\t\tconst baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst timeoutParam = params.get('timeout');\n\t\tconst config: RabbitMQConnectionConfig = {\n\t\t\turl: baseUrl,\n\t\t\texchange: params.get('exchange') || 'geekmidas.events',\n\t\t\texchangeType: (params.get('type') as any) || 'topic',\n\t\t\ttimeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n\t\t};\n\n\t\tconst connection = new RabbitMQConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.channel) return;\n\n\t\t// Prevent multiple simultaneous connection attempts\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst connection = await amqplib.connect(this.config.url, {\n\t\t\t\t\ttimeout: this.config.timeout,\n\t\t\t\t});\n\t\t\t\tconst channel = await connection.createChannel();\n\n\t\t\t\t// Assert the exchange exists\n\t\t\t\tawait channel.assertExchange(\n\t\t\t\t\tthis.config.exchange!,\n\t\t\t\t\tthis.config.exchangeType!,\n\t\t\t\t\tthis.config.exchangeOptions,\n\t\t\t\t);\n\n\t\t\t\t// Handle connection errors\n\t\t\t\tconnection.on('error', (_err: Error) => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\tconnection.on('close', () => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\t// Only set after successful setup\n\t\t\t\tthis.connection = connection;\n\t\t\t\tthis.channel = channel;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.channel?.close();\n\t\t\tawait this.connection?.close();\n\t\t} catch (_error) {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.channel;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.channel = undefined;\n\t\tthis.connection = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying channel for publishing/subscribing\n\t */\n\tget amqpChannel(): amqplib.Channel | undefined {\n\t\treturn this.channel;\n\t}\n\n\t/**\n\t * Get the exchange name for this connection\n\t */\n\tget exchangeName(): string {\n\t\treturn this.config.exchange;\n\t}\n\n\t/**\n\t * Get the exchange type for this connection\n\t */\n\tget exchangeType(): string {\n\t\treturn this.config.exchangeType;\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQPublisherOptions {\n\tpublishOptions?: amqplib.Options.Publish;\n}\n\nexport class RabbitMQPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQPublisher from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQPublisher<TMessage>> {\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\t\treturn new RabbitMQPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\tfor (const message of messages) {\n\t\t\tconst content = Buffer.from(JSON.stringify(message.payload));\n\n\t\t\t// Use message type as routing key for topic exchanges\n\t\t\tconst routingKey = message.type;\n\n\t\t\tconst published = channel.publish(exchange, routingKey, content, {\n\t\t\t\tcontentType: 'application/json',\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\ttype: message.type,\n\t\t\t\tpersistent: true,\n\t\t\t\t...this.options.publishOptions,\n\t\t\t});\n\n\t\t\t// Handle backpressure\n\t\t\tif (!published) {\n\t\t\t\tawait new Promise((resolve) => channel.once('drain', resolve));\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n\tqueueName?: string; // If not provided, a unique queue will be generated\n\tqueueOptions?: amqplib.Options.AssertQueue;\n\tconsumeOptions?: amqplib.Options.Consume;\n\tprefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n\tTMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQSubscriber from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\n\t\tconst options: RabbitMQSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tprefetch: params.get('prefetch')\n\t\t\t\t? Number.parseInt(params.get('prefetch')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new RabbitMQSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\t// Set prefetch if specified\n\t\tif (this.options.prefetch) {\n\t\t\tawait channel.prefetch(this.options.prefetch);\n\t\t}\n\n\t\t// Assert queue\n\t\tconst queueName = this.options.queueName || '';\n\t\tconst queueOptions: amqplib.Options.AssertQueue = {\n\t\t\tdurable: true,\n\t\t\t...this.options.queueOptions,\n\t\t};\n\n\t\tconst { queue } = await channel.assertQueue(queueName, queueOptions);\n\n\t\t// Bind queue to exchange for each message type\n\t\tfor (const messageType of messages) {\n\t\t\tawait channel.bindQueue(queue, exchange, messageType);\n\t\t}\n\n\t\t// Consume messages\n\t\tawait channel.consume(\n\t\t\tqueue,\n\t\t\tasync (msg) => {\n\t\t\t\tif (!msg) return;\n\n\t\t\t\ttry {\n\t\t\t\t\t// Parse message payload\n\t\t\t\t\tconst content = msg.content.toString();\n\t\t\t\t\tconst payload = JSON.parse(content);\n\n\t\t\t\t\t// Get message type from properties\n\t\t\t\t\tconst messageType = msg.properties.type;\n\n\t\t\t\t\t// Reconstruct full message\n\t\t\t\t\tconst fullMessage: TMessage = {\n\t\t\t\t\t\ttype: messageType,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\t// Call listener\n\t\t\t\t\tawait listener(fullMessage);\n\n\t\t\t\t\t// Ack message\n\t\t\t\t\tchannel.ack(msg);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tchannel.nack(msg, false, true);\n\t\t\t\t}\n\t\t\t},\n\t\t\tthis.options.consumeOptions,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts","../../src/rabbitmq/driver.ts"],"sourcesContent":["import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n\turl: string;\n\texchange?: string;\n\texchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n\texchangeOptions?: amqplib.Options.AssertExchange;\n\ttimeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n\treadonly type = EventPublisherType.RabbitMQ;\n\tprivate connection?: amqplib.ChannelModel;\n\tprivate channel?: amqplib.Channel;\n\tprivate connecting?: Promise<void>;\n\tprivate config: Required<\n\t\tPick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n\t> &\n\t\tRabbitMQConnectionConfig;\n\n\tconstructor(config: RabbitMQConnectionConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\texchange: config.exchange || 'geekmidas.events',\n\t\t\texchangeType: config.exchangeType || 'topic',\n\t\t\ttimeout: config.timeout ?? 5000,\n\t\t\texchangeOptions: {\n\t\t\t\tdurable: true,\n\t\t\t\t...config.exchangeOptions,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Create a RabbitMQConnection from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<RabbitMQConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\t// Extract connection URL without query params\n\t\tconst baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst timeoutParam = params.get('timeout');\n\t\tconst config: RabbitMQConnectionConfig = {\n\t\t\turl: baseUrl,\n\t\t\texchange: params.get('exchange') || 'geekmidas.events',\n\t\t\texchangeType: (params.get('type') as any) || 'topic',\n\t\t\ttimeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n\t\t};\n\n\t\tconst connection = new RabbitMQConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.channel) return;\n\n\t\t// Prevent multiple simultaneous connection attempts\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst connection = await amqplib.connect(this.config.url, {\n\t\t\t\t\ttimeout: this.config.timeout,\n\t\t\t\t});\n\t\t\t\tconst channel = await connection.createChannel();\n\n\t\t\t\t// Assert the exchange exists\n\t\t\t\tawait channel.assertExchange(\n\t\t\t\t\tthis.config.exchange!,\n\t\t\t\t\tthis.config.exchangeType!,\n\t\t\t\t\tthis.config.exchangeOptions,\n\t\t\t\t);\n\n\t\t\t\t// Handle connection errors\n\t\t\t\tconnection.on('error', (_err: Error) => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\tconnection.on('close', () => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\t// Only set after successful setup\n\t\t\t\tthis.connection = connection;\n\t\t\t\tthis.channel = channel;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.channel?.close();\n\t\t\tawait this.connection?.close();\n\t\t} catch (_error) {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.channel;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.channel = undefined;\n\t\tthis.connection = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying channel for publishing/subscribing\n\t */\n\tget amqpChannel(): amqplib.Channel | undefined {\n\t\treturn this.channel;\n\t}\n\n\t/**\n\t * Get the exchange name for this connection\n\t */\n\tget exchangeName(): string {\n\t\treturn this.config.exchange;\n\t}\n\n\t/**\n\t * Get the exchange type for this connection\n\t */\n\tget exchangeType(): string {\n\t\treturn this.config.exchangeType;\n\t}\n}\n","// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** The connection opened but has no channel to publish or consume on. */\nexport class RabbitMQChannelUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.',\n\t\t);\n\t\tthis.name = 'RabbitMQChannelUnavailable';\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQPublisherOptions {\n\tpublishOptions?: amqplib.Options.Publish;\n}\n\nexport class RabbitMQPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQPublisher from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQPublisher<TMessage>> {\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\t\treturn new RabbitMQPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\tfor (const message of messages) {\n\t\t\tconst content = Buffer.from(JSON.stringify(message.payload));\n\n\t\t\t// Use message type as routing key for topic exchanges\n\t\t\tconst routingKey = message.type;\n\n\t\t\tconst published = channel.publish(exchange, routingKey, content, {\n\t\t\t\tcontentType: 'application/json',\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\ttype: message.type,\n\t\t\t\tpersistent: true,\n\t\t\t\t...this.options.publishOptions,\n\t\t\t});\n\n\t\t\t// Handle backpressure\n\t\t\tif (!published) {\n\t\t\t\tawait new Promise((resolve) => channel.once('drain', resolve));\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n\tqueueName?: string; // If not provided, a unique queue will be generated\n\tqueueOptions?: amqplib.Options.AssertQueue;\n\tconsumeOptions?: amqplib.Options.Consume;\n\tprefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n\tTMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQSubscriber from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\n\t\tconst options: RabbitMQSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tprefetch: params.get('prefetch')\n\t\t\t\t? Number.parseInt(params.get('prefetch')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new RabbitMQSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\t// Set prefetch if specified\n\t\tif (this.options.prefetch) {\n\t\t\tawait channel.prefetch(this.options.prefetch);\n\t\t}\n\n\t\t// Assert queue\n\t\tconst queueName = this.options.queueName || '';\n\t\tconst queueOptions: amqplib.Options.AssertQueue = {\n\t\t\tdurable: true,\n\t\t\t...this.options.queueOptions,\n\t\t};\n\n\t\tconst { queue } = await channel.assertQueue(queueName, queueOptions);\n\n\t\t// Bind queue to exchange for each message type\n\t\tfor (const messageType of messages) {\n\t\t\tawait channel.bindQueue(queue, exchange, messageType);\n\t\t}\n\n\t\t// Consume messages\n\t\tawait channel.consume(\n\t\t\tqueue,\n\t\t\tasync (msg) => {\n\t\t\t\tif (!msg) return;\n\n\t\t\t\ttry {\n\t\t\t\t\t// Parse message payload\n\t\t\t\t\tconst content = msg.content.toString();\n\t\t\t\t\tconst payload = JSON.parse(content);\n\n\t\t\t\t\t// Get message type from properties\n\t\t\t\t\tconst messageType = msg.properties.type;\n\n\t\t\t\t\t// Reconstruct full message\n\t\t\t\t\tconst fullMessage: TMessage = {\n\t\t\t\t\t\ttype: messageType,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\t// Call listener\n\t\t\t\t\tawait listener(fullMessage);\n\n\t\t\t\t\t// Ack message\n\t\t\t\t\tchannel.ack(msg);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tchannel.nack(msg, false, true);\n\t\t\t\t}\n\t\t\t},\n\t\t\tthis.options.consumeOptions,\n\t\t);\n\t}\n}\n","import type { EventsDriver } from '../registry';\nimport { EventPublisherType } from '../types';\nimport { RabbitMQConnection } from './RabbitMQConnection';\nimport { RabbitMQPublisher } from './RabbitMQPublisher';\nimport { RabbitMQSubscriber } from './RabbitMQSubscriber';\n\n/**\n * `rabbitmq://` — an AMQP exchange. Register it with\n * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one\n * that imports `amqplib`.\n */\nexport const rabbitmqEventsDriver: EventsDriver = {\n\tscheme: EventPublisherType.RabbitMQ,\n\tconnect: (url) => RabbitMQConnection.fromConnectionString(url),\n\tpublisher: (url) => RabbitMQPublisher.fromConnectionString(url),\n\tpublisherFor: (connection) =>\n\t\tnew RabbitMQPublisher(connection as RabbitMQConnection),\n\tsubscriber: (url) => RabbitMQSubscriber.fromConnectionString(url),\n\tsubscriberFor: (connection) =>\n\t\tnew RabbitMQSubscriber(connection as RabbitMQConnection),\n};\n"],"mappings":"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"}
@@ -1,5 +1,13 @@
1
- import { i as EventSubscriber, n as EventPublisher, r as EventPublisherType, s as PublishableMessage, t as EventConnection } from "../types-gGaoT8qc.cjs";
1
+ import { d as EventPublisher, f as EventPublisherType, g as PublishableMessage, p as EventSubscriber, t as EventsDriver, u as EventConnection } from "../registry-DIx25Q5s.cjs";
2
2
  import amqplib from "amqplib";
3
+ //#region src/rabbitmq/driver.d.ts
4
+ /**
5
+ * `rabbitmq://` — an AMQP exchange. Register it with
6
+ * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one
7
+ * that imports `amqplib`.
8
+ */
9
+ export declare const rabbitmqEventsDriver: EventsDriver;
10
+ //#endregion
3
11
  //#region src/rabbitmq/errors.d.ts
4
12
  /** The connection opened but has no channel to publish or consume on. */
5
13
  export declare class RabbitMQChannelUnavailable extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"mappings":";;;;qBAKa,mCAAmC;EAC/C;;;;UCFgB;EAChB;EACA;EACA;EACA,kBAAkB,QAAQ,QAAQ;EAClC;;qBAGY,8BAA8B;WACjC,OAAI,mBAAA;UACL;UACA;UACA;UACA;EAKR,YAAY,QAAQ;;;;;SAiBP,qBACZ,2BACE,QAAQ;EAoBL,WAAW;EA6CX,SAAS;EAWf;UAIQ;;;;MASJ,eAAe,QAAQ;;;;MAOvB;;;;MAOA;;;;UC3IY;EAChB,iBAAiB,QAAQ,QAAQ;;qBAGrB,kBAAkB,iBAAiB,4CACpC,eAAe;UAGjB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,kBAAkB;EAOjD,QAAQ,UAAU,aAAa;EAiC/B,SAAS;;;;UC1DC;EAChB;EACA,eAAe,QAAQ,QAAQ;EAC/B,iBAAiB,QAAQ,QAAQ;EACjC;;qBAGY,mBACZ,iBAAiB,4CACL,gBAAgB;UAGnB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,mBAAmB;EAkBlD,UACL,UAAU,oBACV,WAAW,SAAS,aAAa,gBAC/B"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/rabbitmq/driver.ts","../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"mappings":";;;;;;;;qBAWa,sBAAsB;;;;qBCNtB,mCAAmC;EAC/C;;;;UCFgB;EAChB;EACA;EACA;EACA,kBAAkB,QAAQ,QAAQ;EAClC;;qBAGY,8BAA8B;WACjC,OAAI,mBAAA;UACL;UACA;UACA;UACA;EAKR,YAAY,QAAQ;;;;;SAiBP,qBACZ,2BACE,QAAQ;EAoBL,WAAW;EA6CX,SAAS;EAWf;UAIQ;;;;MASJ,eAAe,QAAQ;;;;MAOvB;;;;MAOA;;;;UC3IY;EAChB,iBAAiB,QAAQ,QAAQ;;qBAGrB,kBAAkB,iBAAiB,4CACpC,eAAe;UAGjB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,kBAAkB;EAOjD,QAAQ,UAAU,aAAa;EAiC/B,SAAS;;;;UC1DC;EAChB;EACA,eAAe,QAAQ,QAAQ;EAC/B,iBAAiB,QAAQ,QAAQ;EACjC;;qBAGY,mBACZ,iBAAiB,4CACL,gBAAgB;UAGnB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,mBAAmB;EAkBlD,UACL,UAAU,oBACV,WAAW,SAAS,aAAa,gBAC/B"}
@@ -1,5 +1,13 @@
1
- import { i as EventSubscriber, n as EventPublisher, r as EventPublisherType, s as PublishableMessage, t as EventConnection } from "../types-gGaoT8qc.mjs";
1
+ import { d as EventPublisher, f as EventPublisherType, g as PublishableMessage, p as EventSubscriber, t as EventsDriver, u as EventConnection } from "../registry-DIx25Q5s.mjs";
2
2
  import amqplib from "amqplib";
3
+ //#region src/rabbitmq/driver.d.ts
4
+ /**
5
+ * `rabbitmq://` — an AMQP exchange. Register it with
6
+ * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one
7
+ * that imports `amqplib`.
8
+ */
9
+ export declare const rabbitmqEventsDriver: EventsDriver;
10
+ //#endregion
3
11
  //#region src/rabbitmq/errors.d.ts
4
12
  /** The connection opened but has no channel to publish or consume on. */
5
13
  export declare class RabbitMQChannelUnavailable extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"mappings":";;;;qBAKa,mCAAmC;EAC/C;;;;UCFgB;EAChB;EACA;EACA;EACA,kBAAkB,QAAQ,QAAQ;EAClC;;qBAGY,8BAA8B;WACjC,OAAI,mBAAA;UACL;UACA;UACA;UACA;EAKR,YAAY,QAAQ;;;;;SAiBP,qBACZ,2BACE,QAAQ;EAoBL,WAAW;EA6CX,SAAS;EAWf;UAIQ;;;;MASJ,eAAe,QAAQ;;;;MAOvB;;;;MAOA;;;;UC3IY;EAChB,iBAAiB,QAAQ,QAAQ;;qBAGrB,kBAAkB,iBAAiB,4CACpC,eAAe;UAGjB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,kBAAkB;EAOjD,QAAQ,UAAU,aAAa;EAiC/B,SAAS;;;;UC1DC;EAChB;EACA,eAAe,QAAQ,QAAQ;EAC/B,iBAAiB,QAAQ,QAAQ;EACjC;;qBAGY,mBACZ,iBAAiB,4CACL,gBAAgB;UAGnB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,mBAAmB;EAkBlD,UACL,UAAU,oBACV,WAAW,SAAS,aAAa,gBAC/B"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/rabbitmq/driver.ts","../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"mappings":";;;;;;;;qBAWa,sBAAsB;;;;qBCNtB,mCAAmC;EAC/C;;;;UCFgB;EAChB;EACA;EACA;EACA,kBAAkB,QAAQ,QAAQ;EAClC;;qBAGY,8BAA8B;WACjC,OAAI,mBAAA;UACL;UACA;UACA;UACA;EAKR,YAAY,QAAQ;;;;;SAiBP,qBACZ,2BACE,QAAQ;EAoBL,WAAW;EA6CX,SAAS;EAWf;UAIQ;;;;MASJ,eAAe,QAAQ;;;;MAOvB;;;;MAOA;;;;UC3IY;EAChB,iBAAiB,QAAQ,QAAQ;;qBAGrB,kBAAkB,iBAAiB,4CACpC,eAAe;UAGjB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,kBAAkB;EAOjD,QAAQ,UAAU,aAAa;EAiC/B,SAAS;;;;UC1DC;EAChB;EACA,eAAe,QAAQ,QAAQ;EAC/B,iBAAiB,QAAQ,QAAQ;EACjC;;qBAGY,mBACZ,iBAAiB,4CACL,gBAAgB;UAGnB;UACA;EAFT,YACS,YAAY,oBACZ,UAAS;;;;;SAOL,qBACZ,iBAAiB,iCAChB,2BAA2B,QAAQ,mBAAmB;EAkBlD,UACL,UAAU,oBACV,WAAW,SAAS,aAAa,gBAC/B"}
@@ -1,15 +1,8 @@
1
+ import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
1
2
  import "../types-Bk5JM6MP.mjs";
2
3
  import amqplib from "amqplib";
3
- //#region src/rabbitmq/errors.ts
4
- /** The connection opened but has no channel to publish or consume on. */
5
- var RabbitMQChannelUnavailable = class extends Error {
6
- constructor() {
7
- super("RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.");
8
- this.name = "RabbitMQChannelUnavailable";
9
- }
10
- };
11
- //#endregion
12
4
  //#region src/rabbitmq/RabbitMQConnection.ts
5
+ var RabbitMQConnection_exports = /* @__PURE__ */ __exportAll({ RabbitMQConnection: () => RabbitMQConnection });
13
6
  var RabbitMQConnection = class RabbitMQConnection {
14
7
  type = "rabbitmq";
15
8
  connection;
@@ -110,6 +103,15 @@ var RabbitMQConnection = class RabbitMQConnection {
110
103
  }
111
104
  };
112
105
  //#endregion
106
+ //#region src/rabbitmq/errors.ts
107
+ /** The connection opened but has no channel to publish or consume on. */
108
+ var RabbitMQChannelUnavailable = class extends Error {
109
+ constructor() {
110
+ super("RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.");
111
+ this.name = "RabbitMQChannelUnavailable";
112
+ }
113
+ };
114
+ //#endregion
113
115
  //#region src/rabbitmq/RabbitMQPublisher.ts
114
116
  var RabbitMQPublisher = class RabbitMQPublisher {
115
117
  connection;
@@ -123,7 +125,7 @@ var RabbitMQPublisher = class RabbitMQPublisher {
123
125
  * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000
124
126
  */
125
127
  static async fromConnectionString(connectionString) {
126
- const { RabbitMQConnection } = await import("../RabbitMQConnection-CAp7VqyT.mjs");
128
+ const { RabbitMQConnection } = await Promise.resolve().then(() => RabbitMQConnection_exports);
127
129
  const connection = await RabbitMQConnection.fromConnectionString(connectionString);
128
130
  return new RabbitMQPublisher(connection);
129
131
  }
@@ -161,7 +163,7 @@ var RabbitMQSubscriber = class RabbitMQSubscriber {
161
163
  */
162
164
  static async fromConnectionString(connectionString) {
163
165
  const params = new URL(connectionString).searchParams;
164
- const { RabbitMQConnection } = await import("../RabbitMQConnection-CAp7VqyT.mjs");
166
+ const { RabbitMQConnection } = await Promise.resolve().then(() => RabbitMQConnection_exports);
165
167
  const connection = await RabbitMQConnection.fromConnectionString(connectionString);
166
168
  const options = {
167
169
  queueName: params.get("queueName") || void 0,
@@ -199,6 +201,21 @@ var RabbitMQSubscriber = class RabbitMQSubscriber {
199
201
  }
200
202
  };
201
203
  //#endregion
202
- export { RabbitMQChannelUnavailable, RabbitMQConnection, RabbitMQPublisher, RabbitMQSubscriber };
204
+ //#region src/rabbitmq/driver.ts
205
+ /**
206
+ * `rabbitmq://` — an AMQP exchange. Register it with
207
+ * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one
208
+ * that imports `amqplib`.
209
+ */
210
+ const rabbitmqEventsDriver = {
211
+ scheme: "rabbitmq",
212
+ connect: (url) => RabbitMQConnection.fromConnectionString(url),
213
+ publisher: (url) => RabbitMQPublisher.fromConnectionString(url),
214
+ publisherFor: (connection) => new RabbitMQPublisher(connection),
215
+ subscriber: (url) => RabbitMQSubscriber.fromConnectionString(url),
216
+ subscriberFor: (connection) => new RabbitMQSubscriber(connection)
217
+ };
218
+ //#endregion
219
+ export { RabbitMQChannelUnavailable, RabbitMQConnection, RabbitMQPublisher, RabbitMQSubscriber, rabbitmqEventsDriver };
203
220
 
204
221
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts"],"sourcesContent":["// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** The connection opened but has no channel to publish or consume on. */\nexport class RabbitMQChannelUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.',\n\t\t);\n\t\tthis.name = 'RabbitMQChannelUnavailable';\n\t}\n}\n","import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n\turl: string;\n\texchange?: string;\n\texchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n\texchangeOptions?: amqplib.Options.AssertExchange;\n\ttimeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n\treadonly type = EventPublisherType.RabbitMQ;\n\tprivate connection?: amqplib.ChannelModel;\n\tprivate channel?: amqplib.Channel;\n\tprivate connecting?: Promise<void>;\n\tprivate config: Required<\n\t\tPick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n\t> &\n\t\tRabbitMQConnectionConfig;\n\n\tconstructor(config: RabbitMQConnectionConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\texchange: config.exchange || 'geekmidas.events',\n\t\t\texchangeType: config.exchangeType || 'topic',\n\t\t\ttimeout: config.timeout ?? 5000,\n\t\t\texchangeOptions: {\n\t\t\t\tdurable: true,\n\t\t\t\t...config.exchangeOptions,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Create a RabbitMQConnection from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<RabbitMQConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\t// Extract connection URL without query params\n\t\tconst baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst timeoutParam = params.get('timeout');\n\t\tconst config: RabbitMQConnectionConfig = {\n\t\t\turl: baseUrl,\n\t\t\texchange: params.get('exchange') || 'geekmidas.events',\n\t\t\texchangeType: (params.get('type') as any) || 'topic',\n\t\t\ttimeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n\t\t};\n\n\t\tconst connection = new RabbitMQConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.channel) return;\n\n\t\t// Prevent multiple simultaneous connection attempts\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst connection = await amqplib.connect(this.config.url, {\n\t\t\t\t\ttimeout: this.config.timeout,\n\t\t\t\t});\n\t\t\t\tconst channel = await connection.createChannel();\n\n\t\t\t\t// Assert the exchange exists\n\t\t\t\tawait channel.assertExchange(\n\t\t\t\t\tthis.config.exchange!,\n\t\t\t\t\tthis.config.exchangeType!,\n\t\t\t\t\tthis.config.exchangeOptions,\n\t\t\t\t);\n\n\t\t\t\t// Handle connection errors\n\t\t\t\tconnection.on('error', (_err: Error) => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\tconnection.on('close', () => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\t// Only set after successful setup\n\t\t\t\tthis.connection = connection;\n\t\t\t\tthis.channel = channel;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.channel?.close();\n\t\t\tawait this.connection?.close();\n\t\t} catch (_error) {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.channel;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.channel = undefined;\n\t\tthis.connection = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying channel for publishing/subscribing\n\t */\n\tget amqpChannel(): amqplib.Channel | undefined {\n\t\treturn this.channel;\n\t}\n\n\t/**\n\t * Get the exchange name for this connection\n\t */\n\tget exchangeName(): string {\n\t\treturn this.config.exchange;\n\t}\n\n\t/**\n\t * Get the exchange type for this connection\n\t */\n\tget exchangeType(): string {\n\t\treturn this.config.exchangeType;\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQPublisherOptions {\n\tpublishOptions?: amqplib.Options.Publish;\n}\n\nexport class RabbitMQPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQPublisher from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQPublisher<TMessage>> {\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\t\treturn new RabbitMQPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\tfor (const message of messages) {\n\t\t\tconst content = Buffer.from(JSON.stringify(message.payload));\n\n\t\t\t// Use message type as routing key for topic exchanges\n\t\t\tconst routingKey = message.type;\n\n\t\t\tconst published = channel.publish(exchange, routingKey, content, {\n\t\t\t\tcontentType: 'application/json',\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\ttype: message.type,\n\t\t\t\tpersistent: true,\n\t\t\t\t...this.options.publishOptions,\n\t\t\t});\n\n\t\t\t// Handle backpressure\n\t\t\tif (!published) {\n\t\t\t\tawait new Promise((resolve) => channel.once('drain', resolve));\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n\tqueueName?: string; // If not provided, a unique queue will be generated\n\tqueueOptions?: amqplib.Options.AssertQueue;\n\tconsumeOptions?: amqplib.Options.Consume;\n\tprefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n\tTMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQSubscriber from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\n\t\tconst options: RabbitMQSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tprefetch: params.get('prefetch')\n\t\t\t\t? Number.parseInt(params.get('prefetch')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new RabbitMQSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\t// Set prefetch if specified\n\t\tif (this.options.prefetch) {\n\t\t\tawait channel.prefetch(this.options.prefetch);\n\t\t}\n\n\t\t// Assert queue\n\t\tconst queueName = this.options.queueName || '';\n\t\tconst queueOptions: amqplib.Options.AssertQueue = {\n\t\t\tdurable: true,\n\t\t\t...this.options.queueOptions,\n\t\t};\n\n\t\tconst { queue } = await channel.assertQueue(queueName, queueOptions);\n\n\t\t// Bind queue to exchange for each message type\n\t\tfor (const messageType of messages) {\n\t\t\tawait channel.bindQueue(queue, exchange, messageType);\n\t\t}\n\n\t\t// Consume messages\n\t\tawait channel.consume(\n\t\t\tqueue,\n\t\t\tasync (msg) => {\n\t\t\t\tif (!msg) return;\n\n\t\t\t\ttry {\n\t\t\t\t\t// Parse message payload\n\t\t\t\t\tconst content = msg.content.toString();\n\t\t\t\t\tconst payload = JSON.parse(content);\n\n\t\t\t\t\t// Get message type from properties\n\t\t\t\t\tconst messageType = msg.properties.type;\n\n\t\t\t\t\t// Reconstruct full message\n\t\t\t\t\tconst fullMessage: TMessage = {\n\t\t\t\t\t\ttype: messageType,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\t// Call listener\n\t\t\t\t\tawait listener(fullMessage);\n\n\t\t\t\t\t// Ack message\n\t\t\t\t\tchannel.ack(msg);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tchannel.nack(msg, false, true);\n\t\t\t\t}\n\t\t\t},\n\t\t\tthis.options.consumeOptions,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/rabbitmq/RabbitMQConnection.ts","../../src/rabbitmq/errors.ts","../../src/rabbitmq/RabbitMQPublisher.ts","../../src/rabbitmq/RabbitMQSubscriber.ts","../../src/rabbitmq/driver.ts"],"sourcesContent":["import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n\turl: string;\n\texchange?: string;\n\texchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n\texchangeOptions?: amqplib.Options.AssertExchange;\n\ttimeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n\treadonly type = EventPublisherType.RabbitMQ;\n\tprivate connection?: amqplib.ChannelModel;\n\tprivate channel?: amqplib.Channel;\n\tprivate connecting?: Promise<void>;\n\tprivate config: Required<\n\t\tPick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n\t> &\n\t\tRabbitMQConnectionConfig;\n\n\tconstructor(config: RabbitMQConnectionConfig) {\n\t\tthis.config = {\n\t\t\t...config,\n\t\t\texchange: config.exchange || 'geekmidas.events',\n\t\t\texchangeType: config.exchangeType || 'topic',\n\t\t\ttimeout: config.timeout ?? 5000,\n\t\t\texchangeOptions: {\n\t\t\t\tdurable: true,\n\t\t\t\t...config.exchangeOptions,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Create a RabbitMQConnection from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString(\n\t\tconnectionString: string,\n\t): Promise<RabbitMQConnection> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\t// Extract connection URL without query params\n\t\tconst baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n\t\tconst timeoutParam = params.get('timeout');\n\t\tconst config: RabbitMQConnectionConfig = {\n\t\t\turl: baseUrl,\n\t\t\texchange: params.get('exchange') || 'geekmidas.events',\n\t\t\texchangeType: (params.get('type') as any) || 'topic',\n\t\t\ttimeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n\t\t};\n\n\t\tconst connection = new RabbitMQConnection(config);\n\t\tawait connection.connect();\n\t\treturn connection;\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.channel) return;\n\n\t\t// Prevent multiple simultaneous connection attempts\n\t\tif (this.connecting) {\n\t\t\tawait this.connecting;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.connecting = (async () => {\n\t\t\ttry {\n\t\t\t\tconst connection = await amqplib.connect(this.config.url, {\n\t\t\t\t\ttimeout: this.config.timeout,\n\t\t\t\t});\n\t\t\t\tconst channel = await connection.createChannel();\n\n\t\t\t\t// Assert the exchange exists\n\t\t\t\tawait channel.assertExchange(\n\t\t\t\t\tthis.config.exchange!,\n\t\t\t\t\tthis.config.exchangeType!,\n\t\t\t\t\tthis.config.exchangeOptions,\n\t\t\t\t);\n\n\t\t\t\t// Handle connection errors\n\t\t\t\tconnection.on('error', (_err: Error) => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\tconnection.on('close', () => {\n\t\t\t\t\tthis.cleanup();\n\t\t\t\t});\n\n\t\t\t\t// Only set after successful setup\n\t\t\t\tthis.connection = connection;\n\t\t\t\tthis.channel = channel;\n\t\t\t} catch (error) {\n\t\t\t\tthis.cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\n\t\tawait this.connecting;\n\t\tthis.connecting = undefined;\n\t}\n\n\tasync close(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.channel?.close();\n\t\t\tawait this.connection?.close();\n\t\t} catch (_error) {\n\t\t\t// Ignore errors during close\n\t\t} finally {\n\t\t\tthis.cleanup();\n\t\t}\n\t}\n\n\tisConnected(): boolean {\n\t\treturn !!this.channel;\n\t}\n\n\tprivate cleanup(): void {\n\t\tthis.channel = undefined;\n\t\tthis.connection = undefined;\n\t\tthis.connecting = undefined;\n\t}\n\n\t/**\n\t * Get the underlying channel for publishing/subscribing\n\t */\n\tget amqpChannel(): amqplib.Channel | undefined {\n\t\treturn this.channel;\n\t}\n\n\t/**\n\t * Get the exchange name for this connection\n\t */\n\tget exchangeName(): string {\n\t\treturn this.config.exchange;\n\t}\n\n\t/**\n\t * Get the exchange type for this connection\n\t */\n\tget exchangeType(): string {\n\t\treturn this.config.exchangeType;\n\t}\n}\n","// Beside the adapter but apart from its connection module, which imports\n// the broker's client: the publisher and subscriber load that lazily, and\n// importing an error class from it would load it eagerly.\n\n/** The connection opened but has no channel to publish or consume on. */\nexport class RabbitMQChannelUnavailable extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'RabbitMQ connected without a channel. Check the broker is reachable and the connection string names a vhost the user can open channels on.',\n\t\t);\n\t\tthis.name = 'RabbitMQChannelUnavailable';\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQPublisherOptions {\n\tpublishOptions?: amqplib.Options.Publish;\n}\n\nexport class RabbitMQPublisher<TMessage extends PublishableMessage<string, any>>\n\timplements EventPublisher<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQPublisherOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQPublisher from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQPublisher<TMessage>> {\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\t\treturn new RabbitMQPublisher<TMessage>(connection);\n\t}\n\n\tasync publish(messages: TMessage[]): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\tfor (const message of messages) {\n\t\t\tconst content = Buffer.from(JSON.stringify(message.payload));\n\n\t\t\t// Use message type as routing key for topic exchanges\n\t\t\tconst routingKey = message.type;\n\n\t\t\tconst published = channel.publish(exchange, routingKey, content, {\n\t\t\t\tcontentType: 'application/json',\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\ttype: message.type,\n\t\t\t\tpersistent: true,\n\t\t\t\t...this.options.publishOptions,\n\t\t\t});\n\n\t\t\t// Handle backpressure\n\t\t\tif (!published) {\n\t\t\t\tawait new Promise((resolve) => channel.once('drain', resolve));\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// Publisher doesn't own the connection\n\t\t// Connection should be closed by whoever created it\n\t}\n}\n","import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport { RabbitMQChannelUnavailable } from './errors';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n\tqueueName?: string; // If not provided, a unique queue will be generated\n\tqueueOptions?: amqplib.Options.AssertQueue;\n\tconsumeOptions?: amqplib.Options.Consume;\n\tprefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n\tTMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n\tconstructor(\n\t\tprivate connection: RabbitMQConnection,\n\t\tprivate options: RabbitMQSubscriberOptions = {},\n\t) {}\n\n\t/**\n\t * Create a RabbitMQSubscriber from a connection string\n\t * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n\t */\n\tstatic async fromConnectionString<\n\t\tTMessage extends PublishableMessage<string, any>,\n\t>(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n\t\tconst url = new URL(connectionString);\n\t\tconst params = url.searchParams;\n\n\t\tconst { RabbitMQConnection } = await import('./RabbitMQConnection');\n\t\tconst connection =\n\t\t\tawait RabbitMQConnection.fromConnectionString(connectionString);\n\n\t\tconst options: RabbitMQSubscriberOptions = {\n\t\t\tqueueName: params.get('queueName') || undefined,\n\t\t\tprefetch: params.get('prefetch')\n\t\t\t\t? Number.parseInt(params.get('prefetch')!, 10)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\treturn new RabbitMQSubscriber<TMessage>(connection, options);\n\t}\n\n\tasync subscribe(\n\t\tmessages: TMessage['type'][],\n\t\tlistener: (payload: TMessage) => Promise<void>,\n\t): Promise<void> {\n\t\tif (!this.connection.isConnected()) {\n\t\t\tawait this.connection.connect();\n\t\t}\n\n\t\tconst channel = this.connection.amqpChannel;\n\t\tif (!channel) {\n\t\t\tthrow new RabbitMQChannelUnavailable();\n\t\t}\n\n\t\tconst exchange = this.connection.exchangeName;\n\n\t\t// Set prefetch if specified\n\t\tif (this.options.prefetch) {\n\t\t\tawait channel.prefetch(this.options.prefetch);\n\t\t}\n\n\t\t// Assert queue\n\t\tconst queueName = this.options.queueName || '';\n\t\tconst queueOptions: amqplib.Options.AssertQueue = {\n\t\t\tdurable: true,\n\t\t\t...this.options.queueOptions,\n\t\t};\n\n\t\tconst { queue } = await channel.assertQueue(queueName, queueOptions);\n\n\t\t// Bind queue to exchange for each message type\n\t\tfor (const messageType of messages) {\n\t\t\tawait channel.bindQueue(queue, exchange, messageType);\n\t\t}\n\n\t\t// Consume messages\n\t\tawait channel.consume(\n\t\t\tqueue,\n\t\t\tasync (msg) => {\n\t\t\t\tif (!msg) return;\n\n\t\t\t\ttry {\n\t\t\t\t\t// Parse message payload\n\t\t\t\t\tconst content = msg.content.toString();\n\t\t\t\t\tconst payload = JSON.parse(content);\n\n\t\t\t\t\t// Get message type from properties\n\t\t\t\t\tconst messageType = msg.properties.type;\n\n\t\t\t\t\t// Reconstruct full message\n\t\t\t\t\tconst fullMessage: TMessage = {\n\t\t\t\t\t\ttype: messageType,\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t} as TMessage;\n\n\t\t\t\t\t// Call listener\n\t\t\t\t\tawait listener(fullMessage);\n\n\t\t\t\t\t// Ack message\n\t\t\t\t\tchannel.ack(msg);\n\t\t\t\t} catch (_error) {\n\t\t\t\t\tchannel.nack(msg, false, true);\n\t\t\t\t}\n\t\t\t},\n\t\t\tthis.options.consumeOptions,\n\t\t);\n\t}\n}\n","import type { EventsDriver } from '../registry';\nimport { EventPublisherType } from '../types';\nimport { RabbitMQConnection } from './RabbitMQConnection';\nimport { RabbitMQPublisher } from './RabbitMQPublisher';\nimport { RabbitMQSubscriber } from './RabbitMQSubscriber';\n\n/**\n * `rabbitmq://` — an AMQP exchange. Register it with\n * `registerEventsDriver(rabbitmqEventsDriver)`; this subpath is the only one\n * that imports `amqplib`.\n */\nexport const rabbitmqEventsDriver: EventsDriver = {\n\tscheme: EventPublisherType.RabbitMQ,\n\tconnect: (url) => RabbitMQConnection.fromConnectionString(url),\n\tpublisher: (url) => RabbitMQPublisher.fromConnectionString(url),\n\tpublisherFor: (connection) =>\n\t\tnew RabbitMQPublisher(connection as RabbitMQConnection),\n\tsubscriber: (url) => RabbitMQSubscriber.fromConnectionString(url),\n\tsubscriberFor: (connection) =>\n\t\tnew RabbitMQSubscriber(connection as RabbitMQConnection),\n};\n"],"mappings":"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"}