@glowlabs-org/events-sdk 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Glow Events SDK
2
2
 
3
- A TypeScript-first SDK for consuming and emitting typed events on the Glow platform, powered by RabbitMQ (fanout exchange). Provides runtime validation and type inference using Zod schemas.
3
+ A TypeScript-first SDK for consuming and emitting typed events on the Glow platform, powered by RabbitMQ (topic exchange). Provides runtime validation and type inference using Zod schemas.
4
4
 
5
5
  ---
6
6
 
@@ -12,190 +12,285 @@ A TypeScript-first SDK for consuming and emitting typed events on the Glow platf
12
12
  pnpm install @glowlabs-org/events-sdk
13
13
  ```
14
14
 
15
- ### 2. Available Events
15
+ ---
16
+
17
+ ## 📚 Zones
18
+
19
+ The following zones are currently available:
20
+
21
+ | Zone ID | Zone Name |
22
+ | ------- | ------------------ |
23
+ | 0 | All Zones |
24
+ | 1 | Clean Grid Project |
25
+ | 2 | Coming Soon Zone |
26
+
27
+ - Use `zoneId: 0` (with `zoneName: "All Zones"`) to emit to or listen to all zones.
28
+ - The SDK types and runtime validation now officially support `zoneId: 0` and `zoneName: "All Zones"` everywhere (emitter, listener, event types).
29
+
30
+ ---
31
+
32
+ ## 📦 Event Types & Versions
33
+
34
+ Currently supported event types and versions:
35
+
36
+ | Event Name | Version | Payload Type | Description |
37
+ | ------------------ | ------- | ------------------------- | ----------------------------------- |
38
+ | `audit.pushed` | 1 | `AuditPushedV1Payload` | Emitted when an audit is pushed |
39
+ | `audit.slashed` | 1 | `AuditSlashedV1Payload` | Emitted when a farm is slashed |
40
+ | `audit.pfees.paid` | 1 | `AuditPfeesPaidV1Payload` | Emitted when protocol fees are paid |
41
+
42
+ ---
43
+
44
+ ## 📝 Event Payload Schemas
45
+
46
+ ### `audit.pushed` v1
16
47
 
17
- | Event Name | Payload Type | Description |
18
- | -------------- | ------------------ | -------------------------------- |
19
- | `AuditPushed` | `AuditPushedEvent` | Emitted when an audit is pushed |
20
- | `AuditSlashed` | `AuditSlashedId` | Emitted when an audit is slashed |
48
+ ```ts
49
+ export interface AuditPushedV1Payload {
50
+ farmId: string; // bytes32 hex string (0x...)
51
+ protocolFeeUSDPrice_12Decimals: string; // uint256 (decimal) 12 implied decimals
52
+ expectedProduction_12Decimals: string; // uint256 (decimal) − 12 implied decimals
53
+ }
54
+ ```
55
+
56
+ **Validation:**
57
+
58
+ - `farmId` must be a 32-byte hex string (e.g., `0x...`).
59
+ - `protocolFeeUSDPrice_12Decimals` and `expectedProduction_12Decimals` must be decimal strings representing unsigned big integers.
60
+
61
+ ### `audit.slashed` v1
62
+
63
+ ```ts
64
+ export interface AuditSlashedV1Payload {
65
+ farmId: string; // bytes32 hex string (0x...)
66
+ slasher: string; // Ethereum address (0x...)
67
+ }
68
+ ```
69
+
70
+ **Validation:**
21
71
 
22
- #### Event Payload Types
72
+ - `farmId` must be a 32-byte hex string (e.g., `0x...`).
73
+ - `slasher` must be a valid Ethereum address (0x...40 hex chars).
74
+
75
+ ### `audit.pfees.paid` v1
23
76
 
24
77
  ```ts
25
- // AuditPushedEvent
26
- import type { AuditPushedEvent } from "@glowlabs-org/events-sdk";
27
- // type AuditPushedEvent = {
28
- // farmId: string;
29
- // protocolFeeUSDPrice_12Decimals: string;
30
- // tokenPrices: { token: string; priceWAD_usd12Decimals: string }[];
31
- // expectedProduction_12Decimals: string;
32
- // glowRewardSplits: { receiver: string; percent: number }[];
33
- // cashRewardSplits: { receiver: string; percent: number }[];
34
- // }
35
-
36
- // AuditSlashedId
37
- // type AuditSlashedId = `0x${string}`;
78
+ export interface AuditPfeesPaidV1Payload {
79
+ farmId: string; // bytes32 hex string (0x...)
80
+ payer: string; // Ethereum address (0x...)
81
+ amount_12Decimals: string; // uint256 (decimal) − 12 implied decimals
82
+ }
38
83
  ```
39
84
 
85
+ **Validation:**
86
+
87
+ - `farmId` must be a 32-byte hex string (e.g., `0x...`).
88
+ - `payer` must be a valid Ethereum address (0x...40 hex chars).
89
+ - `amount_12Decimals` must be a decimal string representing an unsigned big integer (12 implied decimals).
90
+
40
91
  ---
41
92
 
42
93
  ## ✨ Usage Example
43
94
 
44
- ### Listen to Events
95
+ ### Listen to Specific Event Types/Versions
45
96
 
46
97
  ```ts
47
- import { createGlowListener } from "@glowlabs-org/events-sdk";
48
-
49
- async function main() {
50
- const sdk = await createGlowListener({
51
- username: "listener", // or "admin"
52
- password: "your-password-here",
53
- queueName: "my.precreated.queue", // REQUIRED: must be pre-created and bound by an admin
54
- // Optionally specify a custom exchange:
55
- // exchange: "glow.audit.v2.exchange",
56
- });
98
+ import { createGlowEventListener } from "@glowlabs-org/events-sdk";
57
99
 
58
- sdk.on("AuditPushed", (event) => {
59
- console.log("Received AuditPushed:", event.farmId);
60
- });
100
+ const listener = createGlowEventListener({
101
+ username: "listener",
102
+ password: "your-password-here",
103
+ zoneId: 1,
104
+ queueName: "my.precreated.queue",
105
+ });
61
106
 
62
- sdk.on("AuditSlashed", (id) => {
63
- console.log("Received AuditSlashed:", id);
64
- });
107
+ listener.onEvent("audit.pushed", 1, (event) => {
108
+ console.log("Received audit.pushed v1:", event.farmId);
109
+ });
65
110
 
66
- await sdk.startListener();
111
+ listener.onEvent("audit.slashed", 1, (event) => {
112
+ console.log("Received audit.slashed v1:", event.farmId, event.slasher);
113
+ });
67
114
 
68
- // To stop listening:
69
- // await sdk.stopListener();
70
- }
115
+ listener.onEvent("audit.pfees.paid", 1, (event) => {
116
+ console.log(
117
+ "Received audit.pfees.paid v1:",
118
+ event.farmId,
119
+ event.payer,
120
+ event.amount_12Decimals
121
+ );
122
+ });
71
123
 
72
- main();
124
+ await listener.start();
125
+ // To stop listening:
126
+ // await listener.stop();
73
127
  ```
74
128
 
75
129
  ### Emit Events (Admin Only)
76
130
 
77
131
  ```ts
78
- import { createGlowListener } from "@glowlabs-org/events-sdk";
79
-
80
- async function main() {
81
- const sdk = await createGlowListener({
82
- username: "admin",
83
- password: "your-password-here",
84
- queueName: "my.precreated.queue", // REQUIRED: must be pre-created and bound by an admin
85
- // Optionally specify a custom exchange:
86
- // exchange: "glow.audit.v2.exchange",
87
- });
88
-
89
- await sdk.emitAuditPushed?.({
132
+ import { createGlowEventEmitter } from "@glowlabs-org/events-sdk";
133
+
134
+ const emitter = createGlowEventEmitter({
135
+ username: "admin",
136
+ password: "your-password-here",
137
+ zoneId: 1,
138
+ });
139
+
140
+ await emitter.emit({
141
+ eventType: "audit.pushed",
142
+ schemaVersion: 1,
143
+ payload: {
90
144
  farmId: "0x...",
91
145
  protocolFeeUSDPrice_12Decimals: "...",
92
- tokenPrices: [],
93
146
  expectedProduction_12Decimals: "...",
94
- glowRewardSplits: [],
95
- cashRewardSplits: [],
96
- });
147
+ },
148
+ });
97
149
 
98
- sdk.emitAuditSlashed?.("0x...");
99
- }
150
+ await emitter.emit({
151
+ eventType: "audit.slashed",
152
+ schemaVersion: 1,
153
+ payload: {
154
+ farmId: "0x...",
155
+ slasher: "0x...",
156
+ },
157
+ });
158
+
159
+ await emitter.emit({
160
+ eventType: "audit.pfees.paid",
161
+ schemaVersion: 1,
162
+ payload: {
163
+ farmId: "0x...",
164
+ payer: "0x...",
165
+ amount_12Decimals: "1000000000000",
166
+ },
167
+ });
100
168
 
101
- main();
169
+ await emitter.disconnect();
102
170
  ```
103
171
 
104
- ---
172
+ ### 🌐 Emitting or Listening to All Zones
105
173
 
106
- ## 📝 API Reference
174
+ You can emit to or listen to **all zones at once** by passing `zoneId: 0` to the emitter or listener.
107
175
 
108
- ### `createGlowListener({ username, password, exchange?, queueName })`
176
+ #### Emit to All Zones
109
177
 
110
- Returns a Promise resolving to an object with:
178
+ ```ts
179
+ import { createGlowEventEmitter } from "@glowlabs-org/events-sdk";
111
180
 
112
- - `.on(event, listener)` — Listen to typed events
113
- - `.off(event, listener)` — Remove a listener
114
- - `.emitAuditPushed(payload)` — Emit an AuditPushed event (if permitted)
115
- - `.emitAuditSlashed(id)` Emit an AuditSlashed event (if permitted)
116
- - `.startListener()` — Start listening to events
117
- - `.stopListener()` — Stop listening to events
181
+ const emitter = createGlowEventEmitter({
182
+ username: "admin",
183
+ password: "your-password-here",
184
+ zoneId: 0, // special value for all zones
185
+ });
118
186
 
119
- #### Options
187
+ await emitter.emit({
188
+ eventType: "audit.pushed",
189
+ schemaVersion: 1,
190
+ payload: {
191
+ farmId: "0x...",
192
+ protocolFeeUSDPrice_12Decimals: "...",
193
+ expectedProduction_12Decimals: "...",
194
+ },
195
+ });
120
196
 
121
- - `username` (string, required)
122
- - `password` (string, required)
123
- - `exchange` (string, optional): RabbitMQ exchange name (default: `glow.audit.v1.exchange`)
124
- - `queueName` (string, required): Use a pre-created queue (must be set up by an admin)
125
- - **Naming Requirement:** Both `queueName` and `exchange` must be dot-separated (e.g., 'glow.audit.v1.exchange').
197
+ await emitter.emit({
198
+ eventType: "audit.slashed",
199
+ schemaVersion: 1,
200
+ payload: {
201
+ farmId: "0x...",
202
+ slasher: "0x...",
203
+ },
204
+ });
126
205
 
127
- ---
206
+ await emitter.emit({
207
+ eventType: "audit.pfees.paid",
208
+ schemaVersion: 1,
209
+ payload: {
210
+ farmId: "0x...",
211
+ payer: "0x...",
212
+ amount_12Decimals: "1000000000000",
213
+ },
214
+ });
128
215
 
129
- ## 🔐 Permissions & Credentials
216
+ await emitter.disconnect();
217
+ ```
130
218
 
131
- - **Listener credentials:** Can only subscribe to events. Cannot emit events or create new queues.
132
- - **Admin credentials:** Can subscribe, emit events, and create/bind new queues and exchanges.
219
+ #### Listen to All Zones
133
220
 
134
- If you try to emit with listener credentials, the SDK will throw an error.
221
+ ```ts
222
+ import { createGlowEventListener } from "@glowlabs-org/events-sdk";
135
223
 
136
- ---
224
+ const listener = createGlowEventListener({
225
+ username: "listener",
226
+ password: "your-password-here",
227
+ zoneId: 0, // special value for all zones
228
+ queueName: "my.precreated.queue",
229
+ });
137
230
 
138
- ## 🛠️ Advanced: Admin & Queue Management
231
+ listener.onEvent("audit.pushed", 1, (event) => {
232
+ console.log("Received audit.pushed v1 from any zone:", event.farmId);
233
+ });
139
234
 
140
- The SDK exposes helpers for programmatically creating, binding, and deleting exchanges and queues (admin credentials required). Use these for pre-creating queues for listeners, bootstrapping environments, or advanced queue management.
235
+ listener.onEvent("audit.slashed", 1, (event) => {
236
+ console.log(
237
+ "Received audit.slashed v1 from any zone:",
238
+ event.farmId,
239
+ event.slasher
240
+ );
241
+ });
141
242
 
142
- ### `createExchange(options)`
243
+ listener.onEvent("audit.pfees.paid", 1, (event) => {
244
+ console.log(
245
+ "Received audit.pfees.paid v1 from any zone:",
246
+ event.farmId,
247
+ event.payer,
248
+ event.amount_12Decimals
249
+ );
250
+ });
143
251
 
144
- ### `bindQueueToExchange(options)`
252
+ await listener.start();
253
+ // To stop listening:
254
+ // await listener.stop();
255
+ ```
145
256
 
146
- ### `deleteExchange(options)`
257
+ ---
147
258
 
148
- ### `deleteQueue(options)`
259
+ ## 🧪 Validation & Error Handling
149
260
 
150
- See the end of this README for full admin/queue management usage examples.
261
+ - All events are validated at runtime using Zod schemas.
262
+ - If you emit or process an event with a `zoneName` that does not match the `zoneId`, an error is thrown. `zoneId: 0` and `zoneName: "All Zones"` are a valid pairing.
263
+ - If you emit or process an event with a `schemaVersion` for which no schema exists (e.g., `audit.pushed` v2), an error is thrown.
264
+ - If the payload does not match the schema, an error is thrown.
151
265
 
152
266
  ---
153
267
 
154
- ## 📚 More Details
268
+ ## 🔐 Permissions & Credentials
155
269
 
156
- ### Event Payload Zod Schema
270
+ - **Listener credentials:** Can only subscribe to events. Cannot emit events or create new queues.
271
+ - **Admin credentials:** Can subscribe, emit events, and create/bind new queues and exchanges.
157
272
 
158
- ```ts
159
- import { z } from "zod";
160
-
161
- export const AuditPushedDataZ = z
162
- .object({
163
- farmId: z.string().regex(/^0x[0-9a-fA-F]{64}$/, "bytes32 hex string"),
164
- protocolFeeUSDPrice_12Decimals: z
165
- .string()
166
- .regex(/^[0-9]+$/, "uint256 (decimal) − 12 implied decimals"),
167
- tokenPrices: z.array(
168
- z.object({
169
- token: z.string().regex(/^0x[0-9a-fA-F]{40}$/, "ERC‑20 address"),
170
- priceWAD_usd12Decimals: z.string().regex(/^[0-9]+$/),
171
- })
172
- ),
173
- expectedProduction_12Decimals: z.string().regex(/^[0-9]+$/),
174
- glowRewardSplits: z.array(
175
- z.object({
176
- receiver: z.string().regex(/^0x[0-9a-fA-F]{40}$/),
177
- percent: z.number().min(0).max(100),
178
- })
179
- ),
180
- cashRewardSplits: z.array(
181
- z.object({
182
- receiver: z.string().regex(/^0x[0-9a-fA-F]{40}$/),
183
- percent: z.number().min(0).max(100),
184
- })
185
- ),
186
- })
187
- .strict();
188
-
189
- export type AuditPushedData = z.infer<typeof AuditPushedDataZ>;
190
- ```
273
+ If you try to emit with listener credentials, the SDK will throw an error.
191
274
 
192
275
  ---
193
276
 
194
- ## 🏗️ Admin: Exchange and Queue Management
277
+ ## 🛠️ Admin & Queue Management
195
278
 
196
279
  The SDK exposes helpers for programmatically creating, binding, and deleting exchanges and queues (admin credentials required). Use these for pre-creating queues for listeners, bootstrapping environments, or advanced queue management.
197
280
 
198
- ### Usage Example
281
+ ### `createExchange(options)`
282
+
283
+ Creates a topic exchange (default: `exchangeType = "topic"`).
284
+
285
+ ### `bindQueueToExchange(options)`
286
+
287
+ Binds a queue to a topic exchange. You can specify a `routingKey` for fine-grained event filtering:
288
+
289
+ - `routingKey = "#"` (default): all events
290
+ - `routingKey = "audit.pushed.v1"`: only audit.pushed v1 events
291
+ - `routingKey = "audit.pushed.*"`: all versions of audit.pushed
292
+
293
+ #### Example
199
294
 
200
295
  ```ts
201
296
  import {
@@ -208,26 +303,15 @@ import {
208
303
  await createExchange({
209
304
  username: "admin",
210
305
  password: "your-password-here",
211
- exchange: "glow.audit.v1.exchange",
306
+ exchange: "glow.zone-1.events",
212
307
  });
213
308
 
214
309
  await bindQueueToExchange({
215
310
  username: "admin",
216
311
  password: "your-password-here",
217
- exchange: "glow.audit.v1.exchange",
218
- queue: "glow-listener-queue",
219
- });
220
-
221
- await deleteExchange({
222
- username: "admin",
223
- password: "your-password-here",
224
- exchange: "glow.audit.v1.exchange",
225
- });
226
-
227
- await deleteQueue({
228
- username: "admin",
229
- password: "your-password-here",
312
+ exchange: "glow.zone-1.events",
230
313
  queue: "glow-listener-queue",
314
+ routingKey: "audit.pushed.v1", // only audit.pushed v1 events
231
315
  });
232
316
  ```
233
317
 
@@ -240,27 +324,27 @@ If your listener credentials only have `read` permission (no `configure`), you m
240
324
  ### 1. Admin: Pre-create and bind the queue
241
325
 
242
326
  ```ts
243
- import { createAndBindQueue } from "@glowlabs-org/events-sdk";
327
+ import { bindQueueToExchange } from "@glowlabs-org/events-sdk";
244
328
 
245
- await createAndBindQueue({
329
+ await bindQueueToExchange({
246
330
  username: "admin",
247
331
  password: "your-admin-password",
248
- exchange: "glow.audit.v1.exchange",
332
+ exchange: "glow.zone-1.events",
249
333
  queue: "my.precreated.queue",
334
+ routingKey: "audit.pushed.v1", // only audit.pushed v1 events
250
335
  });
251
336
  ```
252
337
 
253
338
  ### 2. Listener: Consume from the pre-created queue
254
339
 
255
340
  ```ts
256
- import { createGlowListener } from "@glowlabs-org/events-sdk";
341
+ import { createGlowEventListener } from "@glowlabs-org/events-sdk";
257
342
 
258
- const sdk = await createGlowListener({
343
+ const listener = createGlowEventListener({
259
344
  username: "listener",
260
345
  password: "your-listener-password",
346
+ zoneId: 1,
261
347
  queueName: "my.precreated.queue",
262
- // Optionally specify a custom exchange:
263
- // exchange: "glow.audit.v1.exchange",
264
348
  });
265
349
  ```
266
350
 
@@ -269,9 +353,19 @@ const sdk = await createGlowListener({
269
353
 
270
354
  ---
271
355
 
272
- ## 🧩 Advanced: Multiple Listeners/Producers
356
+ ## 🧩 Advanced: Multiple Listeners/Emitters
357
+
358
+ You can create multiple listeners or emitters in the same process, each with its own configuration (e.g., for different credentials, exchanges, or RabbitMQ URLs). This is useful for multi-tenant, multi-topic, or advanced scenarios. **Every listener receives every event for the bound routing key(s).**
359
+
360
+ ---
361
+
362
+ ## 🧪 Extending Event Types
363
+
364
+ To add new event types or versions:
273
365
 
274
- You can create multiple listeners or producers in the same process, each with its own configuration (e.g., for different credentials, exchanges, or RabbitMQ URLs). This is useful for multi-tenant, multi-topic, or advanced scenarios. **Every listener receives every event for the bound exchange.**
366
+ 1. Create a new schema in `src/schemas/`.
367
+ 2. Add the event type and version to `eventTypeRegistry` in `src/event-registry.ts`.
368
+ 3. Update the base event type in `src/base-event.ts` if needed.
275
369
 
276
370
  ---
277
371
 
package/dist/admin.d.ts CHANGED
@@ -7,32 +7,33 @@ export interface CreateAndBindQueueOptions {
7
7
  exchangeType?: string;
8
8
  queueOptions?: amqp.Options.AssertQueue;
9
9
  exchangeOptions?: amqp.Options.AssertExchange;
10
+ routingKey?: string;
10
11
  }
11
12
  /**
12
- * Create a RabbitMQ exchange (admin credentials required).
13
+ * Create a RabbitMQ topic exchange (admin credentials required).
13
14
  *
14
15
  * @param options - Connection and exchange options
15
16
  * @returns Promise<void>
16
17
  */
17
- export declare function createExchange({ username, password, exchange, exchangeType, exchangeOptions, }: Omit<CreateAndBindQueueOptions, "queue" | "queueOptions">): Promise<void>;
18
+ export declare function createExchange({ username, password, exchange, exchangeType, exchangeOptions, }: Omit<CreateAndBindQueueOptions, "queue" | "queueOptions" | "routingKey">): Promise<void>;
18
19
  /**
19
- * Create a RabbitMQ queue and bind it to an exchange (admin credentials required).
20
+ * Create a RabbitMQ queue and bind it to a topic exchange (admin credentials required).
20
21
  *
21
22
  * @param options - Connection, queue, and exchange options
22
23
  * @returns Promise<void>
23
24
  */
24
- export declare function bindQueueToExchange({ username, password, exchange, queue, exchangeType, queueOptions, exchangeOptions, }: CreateAndBindQueueOptions): Promise<void>;
25
+ export declare function bindQueueToExchange({ username, password, exchange, queue, exchangeType, queueOptions, exchangeOptions, routingKey, }: CreateAndBindQueueOptions): Promise<void>;
25
26
  /**
26
27
  * Delete a RabbitMQ exchange (admin credentials required).
27
28
  *
28
29
  * @param options - Connection and exchange options
29
30
  * @returns Promise<void>
30
31
  */
31
- export declare function deleteExchange({ username, password, exchange, }: Omit<CreateAndBindQueueOptions, "queue" | "queueOptions" | "exchangeType" | "exchangeOptions">): Promise<void>;
32
+ export declare function deleteExchange({ username, password, exchange, }: Omit<CreateAndBindQueueOptions, "queue" | "queueOptions" | "exchangeType" | "exchangeOptions" | "routingKey">): Promise<void>;
32
33
  /**
33
34
  * Delete a RabbitMQ queue (admin credentials required).
34
35
  *
35
36
  * @param options - Connection and queue options
36
37
  * @returns Promise<void>
37
38
  */
38
- export declare function deleteQueue({ username, password, queue, }: Omit<CreateAndBindQueueOptions, "exchange" | "exchangeType" | "exchangeOptions" | "queueOptions">): Promise<void>;
39
+ export declare function deleteQueue({ username, password, queue, }: Omit<CreateAndBindQueueOptions, "exchange" | "exchangeType" | "exchangeOptions" | "queueOptions" | "routingKey">): Promise<void>;
package/dist/admin.js CHANGED
@@ -12,16 +12,16 @@ function validateName(name, type) {
12
12
  // Require at least two segments separated by dots, only alphanumerics, dashes, underscores, and dots
13
13
  const pattern = /^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
14
14
  if (!pattern.test(name)) {
15
- throw new Error(`${type} name '${name}' is invalid. Must be dot-separated (e.g., 'glow.audit.v1.exchange').`);
15
+ throw new Error(`${type} name '${name}' is invalid. Must be dot-separated (e.g., 'glow.zone-1.events').`);
16
16
  }
17
17
  }
18
18
  /**
19
- * Create a RabbitMQ exchange (admin credentials required).
19
+ * Create a RabbitMQ topic exchange (admin credentials required).
20
20
  *
21
21
  * @param options - Connection and exchange options
22
22
  * @returns Promise<void>
23
23
  */
24
- async function createExchange({ username, password, exchange, exchangeType = "fanout", exchangeOptions = { durable: true }, }) {
24
+ async function createExchange({ username, password, exchange, exchangeType = "topic", exchangeOptions = { durable: true }, }) {
25
25
  validateName(exchange, "exchange");
26
26
  const url = new URL(`amqp://${username}:${password}@turntable.proxy.rlwy.net:50784`);
27
27
  const conn = await amqplib_1.default.connect(url.toString());
@@ -31,12 +31,12 @@ async function createExchange({ username, password, exchange, exchangeType = "fa
31
31
  await conn.close();
32
32
  }
33
33
  /**
34
- * Create a RabbitMQ queue and bind it to an exchange (admin credentials required).
34
+ * Create a RabbitMQ queue and bind it to a topic exchange (admin credentials required).
35
35
  *
36
36
  * @param options - Connection, queue, and exchange options
37
37
  * @returns Promise<void>
38
38
  */
39
- async function bindQueueToExchange({ username, password, exchange, queue, exchangeType = "fanout", queueOptions = { durable: false }, exchangeOptions = { durable: true }, }) {
39
+ async function bindQueueToExchange({ username, password, exchange, queue, exchangeType = "topic", queueOptions = { durable: false }, exchangeOptions = { durable: true }, routingKey = "#", }) {
40
40
  validateName(exchange, "exchange");
41
41
  validateName(queue, "queue");
42
42
  const url = new URL(`amqp://${username}:${password}@turntable.proxy.rlwy.net:50784`);
@@ -44,7 +44,7 @@ async function bindQueueToExchange({ username, password, exchange, queue, exchan
44
44
  const channel = await conn.createChannel();
45
45
  await channel.assertExchange(exchange, exchangeType, exchangeOptions);
46
46
  await channel.assertQueue(queue, queueOptions);
47
- await channel.bindQueue(queue, exchange, "");
47
+ await channel.bindQueue(queue, exchange, routingKey);
48
48
  await channel.close();
49
49
  await conn.close();
50
50
  }
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ import { ZoneName } from "./zones";
3
+ export declare const baseEventZ: z.ZodObject<{
4
+ id: z.ZodString;
5
+ zoneId: z.ZodEffects<z.ZodNumber, number, number>;
6
+ zoneName: z.ZodEnum<[string, ...string[]]>;
7
+ schemaVersion: z.ZodLiteral<1>;
8
+ eventType: z.ZodEnum<["audit.pushed", "audit.slashed", "audit.pfees.paid"]>;
9
+ timeStamp: z.ZodNumber;
10
+ }, "strip", z.ZodTypeAny, {
11
+ id: string;
12
+ zoneId: number;
13
+ zoneName: string;
14
+ schemaVersion: 1;
15
+ eventType: "audit.pushed" | "audit.slashed" | "audit.pfees.paid";
16
+ timeStamp: number;
17
+ }, {
18
+ id: string;
19
+ zoneId: number;
20
+ zoneName: string;
21
+ schemaVersion: 1;
22
+ eventType: "audit.pushed" | "audit.slashed" | "audit.pfees.paid";
23
+ timeStamp: number;
24
+ }>;
25
+ export interface BaseEvent {
26
+ id: string;
27
+ zoneId: number;
28
+ zoneName: ZoneName;
29
+ schemaVersion: 1;
30
+ eventType: "audit.pushed" | "audit.slashed" | "audit.pfees.paid";
31
+ timeStamp: number;
32
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.baseEventZ = void 0;
4
+ const zod_1 = require("zod");
5
+ const zones_1 = require("./zones");
6
+ const zoneIdNumbers = Object.keys(zones_1.zoneMap).map(Number);
7
+ const zoneNames = Object.values(zones_1.zoneMap);
8
+ exports.baseEventZ = zod_1.z.object({
9
+ id: zod_1.z.string().uuid(),
10
+ zoneId: zod_1.z.number().refine((id) => zoneIdNumbers.includes(id), {
11
+ message: "Invalid zoneId",
12
+ }),
13
+ zoneName: zod_1.z.enum(zoneNames),
14
+ schemaVersion: zod_1.z.literal(1),
15
+ eventType: zod_1.z.enum(["audit.pushed", "audit.slashed", "audit.pfees.paid"]),
16
+ timeStamp: zod_1.z.number().int(),
17
+ });
@@ -0,0 +1,18 @@
1
+ import { EventPayload, EventType, EventVersion } from "./types";
2
+ interface CreateGlowEventEmitterOptions {
3
+ username: string;
4
+ password: string;
5
+ zoneId: number;
6
+ exchangePrefix?: string;
7
+ }
8
+ interface EmitEventArgs<T extends EventType, V extends EventVersion<T>> {
9
+ eventType: T;
10
+ schemaVersion: V;
11
+ zoneId: number;
12
+ payload: EventPayload<T, V>;
13
+ }
14
+ export declare function createGlowEventEmitter({ username, password, zoneId, exchangePrefix, }: CreateGlowEventEmitterOptions): {
15
+ emit: <T extends EventType, V extends EventVersion<T>>(args: EmitEventArgs<T, V>) => Promise<void>;
16
+ disconnect: () => Promise<void>;
17
+ };
18
+ export {};