@flowcore/pathways 0.2.1

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 (113) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +420 -0
  3. package/esm/common/flowcore.type.d.ts +11 -0
  4. package/esm/common/flowcore.type.d.ts.map +1 -0
  5. package/esm/common/flowcore.type.js +1 -0
  6. package/esm/common/index.d.ts +7 -0
  7. package/esm/common/index.d.ts.map +1 -0
  8. package/esm/common/index.js +6 -0
  9. package/esm/compatibility/flowcore-transformer-core.sdk.d.ts +16 -0
  10. package/esm/compatibility/flowcore-transformer-core.sdk.d.ts.map +1 -0
  11. package/esm/compatibility/flowcore-transformer-core.sdk.js +11 -0
  12. package/esm/contracts/event.d.ts +20 -0
  13. package/esm/contracts/event.d.ts.map +1 -0
  14. package/esm/contracts/event.js +15 -0
  15. package/esm/contracts/index.d.ts +5 -0
  16. package/esm/contracts/index.d.ts.map +1 -0
  17. package/esm/contracts/index.js +4 -0
  18. package/esm/mod.d.ts +14 -0
  19. package/esm/mod.d.ts.map +1 -0
  20. package/esm/mod.js +13 -0
  21. package/esm/package.json +3 -0
  22. package/esm/pathways/builder.d.ts +91 -0
  23. package/esm/pathways/builder.d.ts.map +1 -0
  24. package/esm/pathways/builder.js +530 -0
  25. package/esm/pathways/index.d.ts +17 -0
  26. package/esm/pathways/index.d.ts.map +1 -0
  27. package/esm/pathways/index.js +16 -0
  28. package/esm/pathways/internal-pathway.state.d.ts +41 -0
  29. package/esm/pathways/internal-pathway.state.d.ts.map +1 -0
  30. package/esm/pathways/internal-pathway.state.js +64 -0
  31. package/esm/pathways/kv/bun-kv-adapter.d.ts +36 -0
  32. package/esm/pathways/kv/bun-kv-adapter.d.ts.map +1 -0
  33. package/esm/pathways/kv/bun-kv-adapter.js +47 -0
  34. package/esm/pathways/kv/kv-adapter.d.ts +34 -0
  35. package/esm/pathways/kv/kv-adapter.d.ts.map +1 -0
  36. package/esm/pathways/kv/kv-adapter.js +19 -0
  37. package/esm/pathways/kv/node-kv-adapter.d.ts +33 -0
  38. package/esm/pathways/kv/node-kv-adapter.d.ts.map +1 -0
  39. package/esm/pathways/kv/node-kv-adapter.js +44 -0
  40. package/esm/pathways/logger.d.ts +48 -0
  41. package/esm/pathways/logger.d.ts.map +1 -0
  42. package/esm/pathways/logger.js +26 -0
  43. package/esm/pathways/postgres/index.d.ts +9 -0
  44. package/esm/pathways/postgres/index.d.ts.map +1 -0
  45. package/esm/pathways/postgres/index.js +8 -0
  46. package/esm/pathways/postgres/postgres-adapter.d.ts +112 -0
  47. package/esm/pathways/postgres/postgres-adapter.d.ts.map +1 -0
  48. package/esm/pathways/postgres/postgres-adapter.js +113 -0
  49. package/esm/pathways/postgres/postgres-pathway-state.d.ts +113 -0
  50. package/esm/pathways/postgres/postgres-pathway-state.d.ts.map +1 -0
  51. package/esm/pathways/postgres/postgres-pathway-state.js +188 -0
  52. package/esm/pathways/types.d.ts +87 -0
  53. package/esm/pathways/types.d.ts.map +1 -0
  54. package/esm/pathways/types.js +1 -0
  55. package/esm/router/index.d.ts +35 -0
  56. package/esm/router/index.d.ts.map +1 -0
  57. package/esm/router/index.js +96 -0
  58. package/package.json +38 -0
  59. package/script/common/flowcore.type.d.ts +11 -0
  60. package/script/common/flowcore.type.d.ts.map +1 -0
  61. package/script/common/flowcore.type.js +2 -0
  62. package/script/common/index.d.ts +7 -0
  63. package/script/common/index.d.ts.map +1 -0
  64. package/script/common/index.js +22 -0
  65. package/script/compatibility/flowcore-transformer-core.sdk.d.ts +16 -0
  66. package/script/compatibility/flowcore-transformer-core.sdk.d.ts.map +1 -0
  67. package/script/compatibility/flowcore-transformer-core.sdk.js +17 -0
  68. package/script/contracts/event.d.ts +20 -0
  69. package/script/contracts/event.d.ts.map +1 -0
  70. package/script/contracts/event.js +18 -0
  71. package/script/contracts/index.d.ts +5 -0
  72. package/script/contracts/index.d.ts.map +1 -0
  73. package/script/contracts/index.js +20 -0
  74. package/script/mod.d.ts +14 -0
  75. package/script/mod.d.ts.map +1 -0
  76. package/script/mod.js +29 -0
  77. package/script/package.json +3 -0
  78. package/script/pathways/builder.d.ts +91 -0
  79. package/script/pathways/builder.d.ts.map +1 -0
  80. package/script/pathways/builder.js +534 -0
  81. package/script/pathways/index.d.ts +17 -0
  82. package/script/pathways/index.d.ts.map +1 -0
  83. package/script/pathways/index.js +32 -0
  84. package/script/pathways/internal-pathway.state.d.ts +41 -0
  85. package/script/pathways/internal-pathway.state.d.ts.map +1 -0
  86. package/script/pathways/internal-pathway.state.js +68 -0
  87. package/script/pathways/kv/bun-kv-adapter.d.ts +36 -0
  88. package/script/pathways/kv/bun-kv-adapter.d.ts.map +1 -0
  89. package/script/pathways/kv/bun-kv-adapter.js +51 -0
  90. package/script/pathways/kv/kv-adapter.d.ts +34 -0
  91. package/script/pathways/kv/kv-adapter.d.ts.map +1 -0
  92. package/script/pathways/kv/kv-adapter.js +45 -0
  93. package/script/pathways/kv/node-kv-adapter.d.ts +33 -0
  94. package/script/pathways/kv/node-kv-adapter.d.ts.map +1 -0
  95. package/script/pathways/kv/node-kv-adapter.js +51 -0
  96. package/script/pathways/logger.d.ts +48 -0
  97. package/script/pathways/logger.d.ts.map +1 -0
  98. package/script/pathways/logger.js +31 -0
  99. package/script/pathways/postgres/index.d.ts +9 -0
  100. package/script/pathways/postgres/index.d.ts.map +1 -0
  101. package/script/pathways/postgres/index.js +24 -0
  102. package/script/pathways/postgres/postgres-adapter.d.ts +112 -0
  103. package/script/pathways/postgres/postgres-adapter.d.ts.map +1 -0
  104. package/script/pathways/postgres/postgres-adapter.js +141 -0
  105. package/script/pathways/postgres/postgres-pathway-state.d.ts +113 -0
  106. package/script/pathways/postgres/postgres-pathway-state.d.ts.map +1 -0
  107. package/script/pathways/postgres/postgres-pathway-state.js +193 -0
  108. package/script/pathways/types.d.ts +87 -0
  109. package/script/pathways/types.d.ts.map +1 -0
  110. package/script/pathways/types.js +2 -0
  111. package/script/router/index.d.ts +35 -0
  112. package/script/router/index.d.ts.map +1 -0
  113. package/script/router/index.js +100 -0
@@ -0,0 +1,534 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PathwaysBuilder = void 0;
4
+ const value_1 = require("@sinclair/typebox/value");
5
+ const rxjs_1 = require("rxjs");
6
+ const flowcore_transformer_core_sdk_js_1 = require("../compatibility/flowcore-transformer-core.sdk.js");
7
+ const internal_pathway_state_js_1 = require("./internal-pathway.state.js");
8
+ const logger_js_1 = require("./logger.js");
9
+ const DEFAULT_PATHWAY_TIMEOUT_MS = 10000;
10
+ const DEFAULT_MAX_RETRIES = 3;
11
+ const DEFAULT_RETRY_DELAY_MS = 500;
12
+ class PathwaysBuilder {
13
+ constructor({ baseUrl, tenant, dataCore, apiKey, pathwayTimeoutMs, logger, }) {
14
+ Object.defineProperty(this, "pathways", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: {}
19
+ });
20
+ Object.defineProperty(this, "handlers", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: {}
25
+ });
26
+ Object.defineProperty(this, "beforeObservable", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: {}
31
+ });
32
+ Object.defineProperty(this, "afterObservers", {
33
+ enumerable: true,
34
+ configurable: true,
35
+ writable: true,
36
+ value: {}
37
+ });
38
+ Object.defineProperty(this, "errorObservers", {
39
+ enumerable: true,
40
+ configurable: true,
41
+ writable: true,
42
+ value: {}
43
+ });
44
+ Object.defineProperty(this, "globalErrorSubject", {
45
+ enumerable: true,
46
+ configurable: true,
47
+ writable: true,
48
+ value: new rxjs_1.Subject()
49
+ });
50
+ Object.defineProperty(this, "writers", {
51
+ enumerable: true,
52
+ configurable: true,
53
+ writable: true,
54
+ value: {}
55
+ });
56
+ Object.defineProperty(this, "schemas", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: {}
61
+ });
62
+ Object.defineProperty(this, "writable", {
63
+ enumerable: true,
64
+ configurable: true,
65
+ writable: true,
66
+ value: {}
67
+ });
68
+ Object.defineProperty(this, "timeouts", {
69
+ enumerable: true,
70
+ configurable: true,
71
+ writable: true,
72
+ value: {}
73
+ });
74
+ Object.defineProperty(this, "maxRetries", {
75
+ enumerable: true,
76
+ configurable: true,
77
+ writable: true,
78
+ value: {}
79
+ });
80
+ Object.defineProperty(this, "retryDelays", {
81
+ enumerable: true,
82
+ configurable: true,
83
+ writable: true,
84
+ value: {}
85
+ });
86
+ Object.defineProperty(this, "filePathways", {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value: new Set()
91
+ });
92
+ Object.defineProperty(this, "webhookBuilderFactory", {
93
+ enumerable: true,
94
+ configurable: true,
95
+ writable: true,
96
+ value: void 0
97
+ });
98
+ Object.defineProperty(this, "pathwayState", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: new internal_pathway_state_js_1.InternalPathwayState()
103
+ });
104
+ Object.defineProperty(this, "pathwayTimeoutMs", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: DEFAULT_PATHWAY_TIMEOUT_MS
109
+ });
110
+ // Audit-related properties
111
+ Object.defineProperty(this, "auditHandler", {
112
+ enumerable: true,
113
+ configurable: true,
114
+ writable: true,
115
+ value: void 0
116
+ });
117
+ Object.defineProperty(this, "userIdResolver", {
118
+ enumerable: true,
119
+ configurable: true,
120
+ writable: true,
121
+ value: void 0
122
+ });
123
+ // Logger instance (but not using it yet due to TypeScript errors)
124
+ Object.defineProperty(this, "logger", {
125
+ enumerable: true,
126
+ configurable: true,
127
+ writable: true,
128
+ value: void 0
129
+ });
130
+ // Initialize logger (use NoopLogger if none provided)
131
+ this.logger = logger ?? new logger_js_1.NoopLogger();
132
+ this.logger.debug('Initializing PathwaysBuilder', {
133
+ baseUrl,
134
+ tenant,
135
+ dataCore,
136
+ pathwayTimeoutMs
137
+ });
138
+ this.webhookBuilderFactory = new flowcore_transformer_core_sdk_js_1.WebhookBuilder({
139
+ baseUrl,
140
+ tenant,
141
+ dataCore,
142
+ apiKey,
143
+ })
144
+ .withRetry({
145
+ maxAttempts: 5,
146
+ attemptDelayMs: 250,
147
+ })
148
+ .factory();
149
+ if (pathwayTimeoutMs) {
150
+ this.pathwayTimeoutMs = pathwayTimeoutMs;
151
+ }
152
+ }
153
+ withPathwayState(state) {
154
+ this.logger.debug('Setting custom pathway state');
155
+ this.pathwayState = state;
156
+ return this;
157
+ }
158
+ /**
159
+ * Configures the PathwaysBuilder to use audit functionality
160
+ * @param handler The handler function that receives pathway and event information
161
+ * @param userIdResolver An async function that resolves to the current user ID
162
+ * @returns The PathwaysBuilder instance with audit configured
163
+ */
164
+ withAudit(handler, userIdResolver) {
165
+ this.logger.debug('Configuring audit functionality');
166
+ this.auditHandler = handler;
167
+ this.userIdResolver = userIdResolver;
168
+ return this;
169
+ }
170
+ /**
171
+ * Process a pathway event with error handling and retries
172
+ * @param pathway The pathway to process
173
+ * @param data The event data to process
174
+ * @returns Promise that resolves when processing is complete
175
+ */
176
+ async process(pathway, data) {
177
+ const pathwayStr = String(pathway);
178
+ this.logger.debug(`Processing pathway event`, {
179
+ pathway: pathwayStr,
180
+ eventId: data.eventId
181
+ });
182
+ if (!this.pathways[pathway]) {
183
+ const error = `Pathway ${pathwayStr} not found`;
184
+ this.logger.error(error);
185
+ throw new Error(error);
186
+ }
187
+ // Call audit handler if configured
188
+ if (this.auditHandler) {
189
+ this.logger.debug(`Calling audit handler for pathway`, {
190
+ pathway: pathwayStr,
191
+ eventId: data.eventId
192
+ });
193
+ this.auditHandler(pathwayStr, data);
194
+ }
195
+ if (this.handlers[pathway]) {
196
+ let retryCount = 0;
197
+ const maxRetries = this.maxRetries[pathway] ?? DEFAULT_MAX_RETRIES;
198
+ const retryDelayMs = this.retryDelays[pathway] ?? DEFAULT_RETRY_DELAY_MS;
199
+ this.logger.debug(`Emitting 'before' event`, {
200
+ pathway: pathwayStr,
201
+ eventId: data.eventId
202
+ });
203
+ this.beforeObservable[pathway].next(data);
204
+ while (true) {
205
+ try {
206
+ this.logger.debug(`Executing handler for pathway`, {
207
+ pathway: pathwayStr,
208
+ eventId: data.eventId,
209
+ attempt: retryCount + 1
210
+ });
211
+ // Execute the handler
212
+ const handle = this.handlers[pathway](data);
213
+ await handle;
214
+ // If successful, emit success event and mark as processed
215
+ this.logger.debug(`Handler executed successfully, emitting 'after' event`, {
216
+ pathway: pathwayStr,
217
+ eventId: data.eventId
218
+ });
219
+ this.afterObservers[pathway].next(data);
220
+ await this.pathwayState.setProcessed(data.eventId);
221
+ this.logger.info(`Successfully processed pathway event`, {
222
+ pathway: pathwayStr,
223
+ eventId: data.eventId
224
+ });
225
+ return;
226
+ }
227
+ catch (error) {
228
+ // Create error object if needed
229
+ const errorObj = error instanceof Error ? error : new Error(String(error));
230
+ this.logger.error(`Error processing pathway event`, {
231
+ pathway: pathwayStr,
232
+ eventId: data.eventId,
233
+ error: errorObj.message,
234
+ retryCount,
235
+ maxRetries
236
+ });
237
+ // Emit error event with both error and event data
238
+ this.errorObservers[pathway].next({ event: data, error: errorObj });
239
+ // Also emit to global error subject
240
+ this.globalErrorSubject.next({
241
+ pathway: pathwayStr,
242
+ event: data,
243
+ error: errorObj
244
+ });
245
+ // Check if we should retry
246
+ if (retryCount < maxRetries) {
247
+ retryCount++;
248
+ const nextDelay = retryDelayMs * retryCount;
249
+ this.logger.debug(`Retrying pathway event processing`, {
250
+ pathway: pathwayStr,
251
+ eventId: data.eventId,
252
+ attempt: retryCount,
253
+ maxRetries,
254
+ nextDelay
255
+ });
256
+ // Wait for delay before retrying
257
+ await new Promise(resolve => setTimeout(resolve, nextDelay));
258
+ continue;
259
+ }
260
+ // If we've exhausted retries, mark as processed to avoid hanging
261
+ this.logger.warn(`Max retries exceeded for pathway event, marking as processed`, {
262
+ pathway: pathwayStr,
263
+ eventId: data.eventId,
264
+ retryCount,
265
+ maxRetries
266
+ });
267
+ await this.pathwayState.setProcessed(data.eventId);
268
+ throw error;
269
+ }
270
+ }
271
+ }
272
+ else {
273
+ // No handler, just emit events and mark as processed
274
+ this.logger.debug(`No handler for pathway, emitting events and marking as processed`, {
275
+ pathway: pathwayStr,
276
+ eventId: data.eventId
277
+ });
278
+ this.beforeObservable[pathway].next(data);
279
+ this.afterObservers[pathway].next(data);
280
+ await this.pathwayState.setProcessed(data.eventId);
281
+ }
282
+ }
283
+ register(contract) {
284
+ const path = `${contract.flowType}/${contract.eventType}`;
285
+ const writable = contract.writable ?? true;
286
+ this.logger.debug(`Registering pathway`, {
287
+ pathway: path,
288
+ flowType: contract.flowType,
289
+ eventType: contract.eventType,
290
+ writable,
291
+ isFilePathway: contract.isFilePathway,
292
+ timeoutMs: contract.timeoutMs,
293
+ maxRetries: contract.maxRetries,
294
+ retryDelayMs: contract.retryDelayMs
295
+ });
296
+ // deno-lint-ignore no-explicit-any
297
+ this.pathways[path] = true;
298
+ this.beforeObservable[path] = new rxjs_1.Subject();
299
+ this.afterObservers[path] = new rxjs_1.Subject();
300
+ this.errorObservers[path] = new rxjs_1.Subject();
301
+ if (writable) {
302
+ if (contract.isFilePathway) {
303
+ this.filePathways.add(path);
304
+ this.writers[path] = this.webhookBuilderFactory()
305
+ .buildFileWebhook(contract.flowType, contract.eventType).send;
306
+ }
307
+ else {
308
+ this.writers[path] = this.webhookBuilderFactory()
309
+ .buildWebhook(contract.flowType, contract.eventType).send;
310
+ }
311
+ }
312
+ if (contract.timeoutMs) {
313
+ this.timeouts[path] = contract.timeoutMs;
314
+ }
315
+ if (contract.maxRetries !== undefined) {
316
+ this.maxRetries[path] = contract.maxRetries;
317
+ }
318
+ if (contract.retryDelayMs !== undefined) {
319
+ this.retryDelays[path] = contract.retryDelayMs;
320
+ }
321
+ this.schemas[path] = contract.schema;
322
+ this.writable[path] = writable;
323
+ this.logger.info(`Pathway registered successfully`, {
324
+ pathway: path,
325
+ flowType: contract.flowType,
326
+ eventType: contract.eventType,
327
+ writable
328
+ });
329
+ return this;
330
+ }
331
+ get(path) {
332
+ this.logger.debug(`Getting pathway`, { pathway: String(path) });
333
+ return this.pathways[path];
334
+ }
335
+ handle(path, handler) {
336
+ const pathStr = String(path);
337
+ this.logger.debug(`Setting handler for pathway`, { pathway: pathStr });
338
+ const pathway = this.pathways[path];
339
+ if (!pathway) {
340
+ const error = `Pathway ${pathStr} not found`;
341
+ this.logger.error(error);
342
+ throw new Error(error);
343
+ }
344
+ if (this.handlers[path]) {
345
+ const error = `Someone is already handling pathway ${pathStr} in this instance`;
346
+ this.logger.error(error);
347
+ throw new Error(error);
348
+ }
349
+ this.handlers[path] = handler;
350
+ this.logger.info(`Handler set for pathway`, { pathway: pathStr });
351
+ }
352
+ /**
353
+ * Subscribe to pathway events (before or after processing)
354
+ * @param path The pathway to subscribe to
355
+ * @param handler The handler function for the events
356
+ * @param type The event type to subscribe to (before, after, or all)
357
+ */
358
+ subscribe(path, handler, type = "before") {
359
+ const pathStr = String(path);
360
+ this.logger.debug(`Subscribing to pathway events`, {
361
+ pathway: pathStr,
362
+ type
363
+ });
364
+ if (!this.pathways[path]) {
365
+ const error = `Pathway ${pathStr} not found`;
366
+ this.logger.error(error);
367
+ throw new Error(error);
368
+ }
369
+ if (type === "before") {
370
+ this.beforeObservable[path].subscribe(handler);
371
+ }
372
+ else if (type === "after") {
373
+ this.afterObservers[path].subscribe(handler);
374
+ }
375
+ else if (type === "all") {
376
+ // Subscribe to both before and after events
377
+ this.beforeObservable[path].subscribe(handler);
378
+ this.afterObservers[path].subscribe(handler);
379
+ }
380
+ this.logger.debug(`Subscribed to pathway events`, {
381
+ pathway: pathStr,
382
+ type
383
+ });
384
+ }
385
+ /**
386
+ * Subscribe to errors for a specific pathway
387
+ * @param path The pathway to subscribe to errors for
388
+ * @param handler The handler function that receives the error and event
389
+ */
390
+ onError(path, handler) {
391
+ const pathStr = String(path);
392
+ this.logger.debug(`Subscribing to pathway errors`, { pathway: pathStr });
393
+ if (!this.pathways[path]) {
394
+ const error = `Pathway ${pathStr} not found`;
395
+ this.logger.error(error);
396
+ throw new Error(error);
397
+ }
398
+ this.errorObservers[path].subscribe(({ event, error }) => handler(error, event));
399
+ this.logger.debug(`Subscribed to pathway errors`, { pathway: pathStr });
400
+ }
401
+ /**
402
+ * Subscribe to errors for all pathways
403
+ * @param handler The handler function that receives the error, event, and pathway name
404
+ */
405
+ onAnyError(handler) {
406
+ this.logger.debug(`Subscribing to all pathway errors`);
407
+ this.globalErrorSubject.subscribe(({ pathway, event, error }) => handler(error, event, pathway));
408
+ this.logger.debug(`Subscribed to all pathway errors`);
409
+ }
410
+ /**
411
+ * Writes data to a pathway with optional audit metadata
412
+ * @param path The pathway to write to
413
+ * @param data The data to write
414
+ * @param metadata Optional metadata to include with the event
415
+ * @param options Optional write options
416
+ * @returns A promise that resolves to the event ID(s)
417
+ */
418
+ async write(path, data, metadata, options) {
419
+ const pathStr = String(path);
420
+ this.logger.debug(`Writing to pathway`, {
421
+ pathway: pathStr,
422
+ metadata,
423
+ options: {
424
+ fireAndForget: options?.fireAndForget
425
+ }
426
+ });
427
+ if (!this.pathways[path]) {
428
+ const error = `Pathway ${pathStr} not found`;
429
+ this.logger.error(error);
430
+ throw new Error(error);
431
+ }
432
+ if (!this.writable[path]) {
433
+ const error = `Pathway ${pathStr} is not writable`;
434
+ this.logger.error(error);
435
+ throw new Error(error);
436
+ }
437
+ const schema = this.schemas[path];
438
+ if (!value_1.Value.Check(schema, data)) {
439
+ const error = `Invalid data for pathway ${pathStr}`;
440
+ this.logger.error(error, {
441
+ pathway: pathStr,
442
+ schema: schema.toString()
443
+ });
444
+ throw new Error(error);
445
+ }
446
+ // Create a copy of the metadata to avoid modifying the original
447
+ const finalMetadata = metadata ? { ...metadata } : {};
448
+ // Process audit metadata if audit is configured
449
+ if (this.userIdResolver) {
450
+ this.logger.debug(`Resolving user ID for audit metadata`, { pathway: pathStr });
451
+ const userId = await this.userIdResolver();
452
+ // Determine the audit mode: default is "user" unless explicitly specified as "system"
453
+ const auditMode = finalMetadata?.["audit/mode"] || "user";
454
+ this.logger.debug(`Adding audit metadata`, {
455
+ pathway: pathStr,
456
+ auditMode,
457
+ userId
458
+ });
459
+ // Add appropriate audit metadata based on mode
460
+ if (auditMode === "system") {
461
+ finalMetadata["audit/user-id"] = "system";
462
+ finalMetadata["audit/on-behalf-of"] = userId;
463
+ finalMetadata["audit/mode"] = "system";
464
+ }
465
+ else {
466
+ finalMetadata["audit/user-id"] = userId;
467
+ finalMetadata["audit/mode"] = "user"; // Always set mode for user
468
+ }
469
+ }
470
+ let eventIds = [];
471
+ if (this.filePathways.has(path)) {
472
+ this.logger.debug(`Writing file data to pathway`, { pathway: pathStr });
473
+ const fileData = data;
474
+ eventIds = await this.writers[path](fileData, finalMetadata, options);
475
+ }
476
+ else {
477
+ this.logger.debug(`Writing webhook data to pathway`, { pathway: pathStr });
478
+ eventIds = await this.writers[path](data, finalMetadata, options);
479
+ }
480
+ this.logger.info(`Successfully wrote to pathway`, {
481
+ pathway: pathStr,
482
+ eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
483
+ fireAndForget: options?.fireAndForget
484
+ });
485
+ if (!options?.fireAndForget) {
486
+ this.logger.debug(`Waiting for pathway to be processed`, {
487
+ pathway: pathStr,
488
+ eventIds: Array.isArray(eventIds) ? eventIds : [eventIds]
489
+ });
490
+ await Promise.all(Array.isArray(eventIds)
491
+ ? eventIds.map(id => this.waitForPathwayToBeProcessed(id))
492
+ : [this.waitForPathwayToBeProcessed(eventIds)]);
493
+ }
494
+ return eventIds;
495
+ }
496
+ async waitForPathwayToBeProcessed(eventId) {
497
+ const startTime = Date.now();
498
+ const timeoutMs = this.timeouts[eventId] ?? this.pathwayTimeoutMs;
499
+ this.logger.debug(`Waiting for event to be processed`, {
500
+ eventId,
501
+ timeoutMs
502
+ });
503
+ let attempts = 0;
504
+ while (!(await this.pathwayState.isProcessed(eventId))) {
505
+ attempts++;
506
+ const elapsedTime = Date.now() - startTime;
507
+ if (elapsedTime > timeoutMs) {
508
+ const error = `Pathway processing timed out after ${timeoutMs}ms for event ${eventId}`;
509
+ this.logger.error(error, {
510
+ eventId,
511
+ timeoutMs,
512
+ elapsedTime,
513
+ attempts
514
+ });
515
+ throw new Error(error);
516
+ }
517
+ if (attempts % 10 === 0) { // Log every 10 attempts (1 second)
518
+ this.logger.debug(`Still waiting for event to be processed`, {
519
+ eventId,
520
+ elapsedTime,
521
+ attempts,
522
+ timeoutMs
523
+ });
524
+ }
525
+ await new Promise((resolve) => setTimeout(resolve, 100));
526
+ }
527
+ this.logger.debug(`Event has been processed`, {
528
+ eventId,
529
+ elapsedTime: Date.now() - startTime,
530
+ attempts
531
+ });
532
+ }
533
+ }
534
+ exports.PathwaysBuilder = PathwaysBuilder;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Main export module for the pathways functionality
3
+ *
4
+ * Exports all components needed to build and manage pathways including:
5
+ * - Pathway builder
6
+ * - State management
7
+ * - Storage adapters (KV, Postgres)
8
+ * - Logging
9
+ * - Type definitions
10
+ */
11
+ export * from "./builder.js";
12
+ export * from "./internal-pathway.state.js";
13
+ export * from "./kv/kv-adapter.js";
14
+ export * from "./logger.js";
15
+ export * from "./postgres/index.js";
16
+ export * from "./types.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pathways/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Main export module for the pathways functionality
19
+ *
20
+ * Exports all components needed to build and manage pathways including:
21
+ * - Pathway builder
22
+ * - State management
23
+ * - Storage adapters (KV, Postgres)
24
+ * - Logging
25
+ * - Type definitions
26
+ */
27
+ __exportStar(require("./builder.js"), exports);
28
+ __exportStar(require("./internal-pathway.state.js"), exports);
29
+ __exportStar(require("./kv/kv-adapter.js"), exports);
30
+ __exportStar(require("./logger.js"), exports);
31
+ __exportStar(require("./postgres/index.js"), exports);
32
+ __exportStar(require("./types.js"), exports);
@@ -0,0 +1,41 @@
1
+ import type { PathwayState } from "./types.js";
2
+ /**
3
+ * Internal implementation of PathwayState interface that uses KV storage
4
+ * for tracking processed events to prevent duplicate processing
5
+ *
6
+ * @implements {PathwayState}
7
+ */
8
+ export declare class InternalPathwayState implements PathwayState {
9
+ /**
10
+ * Default time-to-live for processed event records (5 minutes)
11
+ * @private
12
+ */
13
+ private static readonly DEFAULT_TTL_MS;
14
+ /**
15
+ * The KV adapter instance for storage
16
+ * @private
17
+ */
18
+ private kv;
19
+ /**
20
+ * Gets or initializes the KV adapter
21
+ *
22
+ * @private
23
+ * @returns {Promise<KvAdapter>} The KV adapter instance
24
+ */
25
+ private getKv;
26
+ /**
27
+ * Checks if an event has already been processed
28
+ *
29
+ * @param {string} eventId - The ID of the event to check
30
+ * @returns {Promise<boolean>} True if the event has been processed, false otherwise
31
+ */
32
+ isProcessed(eventId: string): Promise<boolean>;
33
+ /**
34
+ * Marks an event as processed
35
+ *
36
+ * @param {string} eventId - The ID of the event to mark as processed
37
+ * @returns {Promise<void>}
38
+ */
39
+ setProcessed(eventId: string): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=internal-pathway.state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-pathway.state.d.ts","sourceRoot":"","sources":["../../src/pathways/internal-pathway.state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAEvD;;;OAGG;IACH,OAAO,CAAC,EAAE,CAA0B;IAEpC;;;;;OAKG;YACW,KAAK;IAOnB;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpD;;;;;OAKG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAInD"}