@flowcore/pathways 0.10.0 → 0.11.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/CHANGELOG.md +8 -0
- package/esm/pathways/builder.d.ts +7 -5
- package/esm/pathways/builder.d.ts.map +1 -1
- package/esm/pathways/builder.js +144 -37
- package/esm/pathways/types.d.ts +7 -2
- package/esm/pathways/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/script/pathways/builder.d.ts +7 -5
- package/script/pathways/builder.d.ts.map +1 -1
- package/script/pathways/builder.js +144 -37
- package/script/pathways/types.d.ts +7 -2
- package/script/pathways/types.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.0](https://github.com/flowcore-io/flowcore-pathways/compare/v0.10.0...v0.11.0) (2025-04-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* batch support ([32b641e](https://github.com/flowcore-io/flowcore-pathways/commit/32b641e4f181d9ff747a1f0b2bab85a9aea48504))
|
|
9
|
+
* batch support ([4ccf19b](https://github.com/flowcore-io/flowcore-pathways/commit/4ccf19b73419589ddea56dfa13533c4e73947287))
|
|
10
|
+
|
|
3
11
|
## [0.10.0](https://github.com/flowcore-io/flowcore-pathways/compare/v0.9.1...v0.10.0) (2025-04-09)
|
|
4
12
|
|
|
5
13
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Static, type TSchema } from "@sinclair/typebox";
|
|
2
2
|
import type { WebhookSendOptions } from "@flowcore/sdk-transformer-core";
|
|
3
3
|
import type { FlowcoreEvent } from "../contracts/event.js";
|
|
4
4
|
import type { KvAdapter } from "./kv/kv-adapter.js";
|
|
@@ -52,6 +52,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
52
52
|
private readonly errorObservers;
|
|
53
53
|
private readonly globalErrorSubject;
|
|
54
54
|
private readonly writers;
|
|
55
|
+
private readonly batchWriters;
|
|
55
56
|
private readonly schemas;
|
|
56
57
|
private readonly writable;
|
|
57
58
|
private readonly timeouts;
|
|
@@ -187,16 +188,16 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
187
188
|
* @param handler The function that will process events for this pathway
|
|
188
189
|
* @throws Error if the pathway doesn't exist or already has a handler
|
|
189
190
|
*/
|
|
190
|
-
handle<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent,
|
|
191
|
+
handle<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent, "payload"> & {
|
|
191
192
|
payload: TPathway[TPath];
|
|
192
|
-
}) =>
|
|
193
|
+
}) => Promise<void> | void): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
193
194
|
/**
|
|
194
195
|
* Subscribe to pathway events (before or after processing)
|
|
195
196
|
* @param path The pathway to subscribe to
|
|
196
197
|
* @param handler The handler function for the events
|
|
197
198
|
* @param type The event type to subscribe to (before, after, or all)
|
|
198
199
|
*/
|
|
199
|
-
subscribe<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent,
|
|
200
|
+
subscribe<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent, "payload"> & {
|
|
200
201
|
payload: TPathway[TPath];
|
|
201
202
|
}) => void, type?: "before" | "after" | "all"): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
202
203
|
/**
|
|
@@ -204,7 +205,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
204
205
|
* @param path The pathway to subscribe to errors for
|
|
205
206
|
* @param handler The handler function that receives the error and event
|
|
206
207
|
*/
|
|
207
|
-
onError<TPath extends keyof TPathway>(path: TPath, handler: (error: Error, event: Omit<FlowcoreEvent,
|
|
208
|
+
onError<TPath extends keyof TPathway>(path: TPath, handler: (error: Error, event: Omit<FlowcoreEvent, "payload"> & {
|
|
208
209
|
payload: TPathway[TPath];
|
|
209
210
|
}) => void): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
210
211
|
/**
|
|
@@ -221,6 +222,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
221
222
|
* @returns A promise that resolves to the event ID(s)
|
|
222
223
|
*/
|
|
223
224
|
write<TPath extends TWritablePaths>(path: TPath, data: TPathway[TPath], metadata?: EventMetadata, options?: PathwayWriteOptions): Promise<string | string[]>;
|
|
225
|
+
writeBatch<TPath extends TWritablePaths>(path: TPath, data: TPathway[TPath][], metadata?: EventMetadata, options?: PathwayWriteOptions): Promise<string | string[]>;
|
|
224
226
|
/**
|
|
225
227
|
* Waits for a specific event to be processed
|
|
226
228
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/pathways/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/pathways/builder.ts"],"names":[],"mappings":"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"}
|
package/esm/pathways/builder.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
1
2
|
import { Value } from "@sinclair/typebox/value";
|
|
2
3
|
import { Subject } from "rxjs";
|
|
3
4
|
import { WebhookBuilder } from "../compatibility/flowcore-transformer-core.sdk.js";
|
|
@@ -88,6 +89,12 @@ export class PathwaysBuilder {
|
|
|
88
89
|
writable: true,
|
|
89
90
|
value: {}
|
|
90
91
|
});
|
|
92
|
+
Object.defineProperty(this, "batchWriters", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
configurable: true,
|
|
95
|
+
writable: true,
|
|
96
|
+
value: {}
|
|
97
|
+
});
|
|
91
98
|
Object.defineProperty(this, "schemas", {
|
|
92
99
|
enumerable: true,
|
|
93
100
|
configurable: true,
|
|
@@ -204,11 +211,11 @@ export class PathwaysBuilder {
|
|
|
204
211
|
if (sessionUserResolvers) {
|
|
205
212
|
this.sessionUserResolvers = sessionUserResolvers;
|
|
206
213
|
}
|
|
207
|
-
this.logger.debug(
|
|
214
|
+
this.logger.debug("Initializing PathwaysBuilder", {
|
|
208
215
|
baseUrl,
|
|
209
216
|
tenant,
|
|
210
217
|
dataCore,
|
|
211
|
-
pathwayTimeoutMs
|
|
218
|
+
pathwayTimeoutMs,
|
|
212
219
|
});
|
|
213
220
|
this.webhookBuilderFactory = new WebhookBuilder({
|
|
214
221
|
baseUrl,
|
|
@@ -231,7 +238,7 @@ export class PathwaysBuilder {
|
|
|
231
238
|
* @returns The PathwaysBuilder instance with custom state configured
|
|
232
239
|
*/
|
|
233
240
|
withPathwayState(state) {
|
|
234
|
-
this.logger.debug(
|
|
241
|
+
this.logger.debug("Setting custom pathway state");
|
|
235
242
|
this.pathwayState = state;
|
|
236
243
|
return this;
|
|
237
244
|
}
|
|
@@ -241,7 +248,7 @@ export class PathwaysBuilder {
|
|
|
241
248
|
* @returns The PathwaysBuilder instance with audit configured
|
|
242
249
|
*/
|
|
243
250
|
withAudit(handler) {
|
|
244
|
-
this.logger.debug(
|
|
251
|
+
this.logger.debug("Configuring audit functionality");
|
|
245
252
|
this.auditHandler = handler;
|
|
246
253
|
return this;
|
|
247
254
|
}
|
|
@@ -251,7 +258,7 @@ export class PathwaysBuilder {
|
|
|
251
258
|
* @returns The PathwaysBuilder instance with custom user ID resolver configured
|
|
252
259
|
*/
|
|
253
260
|
withUserResolver(resolver) {
|
|
254
|
-
this.logger.debug(
|
|
261
|
+
this.logger.debug("Configuring user resolver");
|
|
255
262
|
this.userIdResolver = resolver;
|
|
256
263
|
return this;
|
|
257
264
|
}
|
|
@@ -290,9 +297,9 @@ export class PathwaysBuilder {
|
|
|
290
297
|
*/
|
|
291
298
|
withSessionUserResolver(sessionId, resolver) {
|
|
292
299
|
if (!this.sessionUserResolvers) {
|
|
293
|
-
throw new Error(
|
|
300
|
+
throw new Error("Session user resolvers not configured");
|
|
294
301
|
}
|
|
295
|
-
this.logger.debug(
|
|
302
|
+
this.logger.debug("Configuring session-specific user resolver", { sessionId });
|
|
296
303
|
this.sessionUserResolvers.set(sessionId, resolver, DEFAULT_SESSION_USER_RESOLVER_TTL_MS);
|
|
297
304
|
return this;
|
|
298
305
|
}
|
|
@@ -318,7 +325,7 @@ export class PathwaysBuilder {
|
|
|
318
325
|
const pathwayStr = String(pathway);
|
|
319
326
|
this.logger.debug(`Processing pathway event`, {
|
|
320
327
|
pathway: pathwayStr,
|
|
321
|
-
eventId: data.eventId
|
|
328
|
+
eventId: data.eventId,
|
|
322
329
|
});
|
|
323
330
|
if (!this.pathways[pathway]) {
|
|
324
331
|
const error = `Pathway ${pathwayStr} not found`;
|
|
@@ -345,7 +352,7 @@ export class PathwaysBuilder {
|
|
|
345
352
|
if (this.auditHandler) {
|
|
346
353
|
this.logger.debug(`Calling audit handler for pathway`, {
|
|
347
354
|
pathway: pathwayStr,
|
|
348
|
-
eventId: data.eventId
|
|
355
|
+
eventId: data.eventId,
|
|
349
356
|
});
|
|
350
357
|
this.auditHandler(pathwayStr, data);
|
|
351
358
|
}
|
|
@@ -355,7 +362,7 @@ export class PathwaysBuilder {
|
|
|
355
362
|
const retryDelayMs = this.retryDelays[pathway] ?? DEFAULT_RETRY_DELAY_MS;
|
|
356
363
|
this.logger.debug(`Emitting 'before' event`, {
|
|
357
364
|
pathway: pathwayStr,
|
|
358
|
-
eventId: data.eventId
|
|
365
|
+
eventId: data.eventId,
|
|
359
366
|
});
|
|
360
367
|
this.beforeObservable[pathway].next(data);
|
|
361
368
|
while (true) {
|
|
@@ -363,7 +370,7 @@ export class PathwaysBuilder {
|
|
|
363
370
|
this.logger.debug(`Executing handler for pathway`, {
|
|
364
371
|
pathway: pathwayStr,
|
|
365
372
|
eventId: data.eventId,
|
|
366
|
-
attempt: retryCount + 1
|
|
373
|
+
attempt: retryCount + 1,
|
|
367
374
|
});
|
|
368
375
|
// Execute the handler
|
|
369
376
|
const handle = this.handlers[pathway](data);
|
|
@@ -371,13 +378,13 @@ export class PathwaysBuilder {
|
|
|
371
378
|
// If successful, emit success event and mark as processed
|
|
372
379
|
this.logger.debug(`Handler executed successfully, emitting 'after' event`, {
|
|
373
380
|
pathway: pathwayStr,
|
|
374
|
-
eventId: data.eventId
|
|
381
|
+
eventId: data.eventId,
|
|
375
382
|
});
|
|
376
383
|
this.afterObservers[pathway].next(data);
|
|
377
384
|
await this.pathwayState.setProcessed(data.eventId);
|
|
378
385
|
this.logger.info(`Successfully processed pathway event`, {
|
|
379
386
|
pathway: pathwayStr,
|
|
380
|
-
eventId: data.eventId
|
|
387
|
+
eventId: data.eventId,
|
|
381
388
|
});
|
|
382
389
|
return;
|
|
383
390
|
}
|
|
@@ -388,7 +395,7 @@ export class PathwaysBuilder {
|
|
|
388
395
|
pathway: pathwayStr,
|
|
389
396
|
eventId: data.eventId,
|
|
390
397
|
retryCount,
|
|
391
|
-
maxRetries
|
|
398
|
+
maxRetries,
|
|
392
399
|
});
|
|
393
400
|
// Emit error event with both error and event data
|
|
394
401
|
this.errorObservers[pathway].next({ event: data, error: errorObj });
|
|
@@ -396,7 +403,7 @@ export class PathwaysBuilder {
|
|
|
396
403
|
this.globalErrorSubject.next({
|
|
397
404
|
pathway: pathwayStr,
|
|
398
405
|
event: data,
|
|
399
|
-
error: errorObj
|
|
406
|
+
error: errorObj,
|
|
400
407
|
});
|
|
401
408
|
// Check if we should retry
|
|
402
409
|
if (retryCount < maxRetries) {
|
|
@@ -407,10 +414,10 @@ export class PathwaysBuilder {
|
|
|
407
414
|
eventId: data.eventId,
|
|
408
415
|
attempt: retryCount,
|
|
409
416
|
maxRetries,
|
|
410
|
-
nextDelay
|
|
417
|
+
nextDelay,
|
|
411
418
|
});
|
|
412
419
|
// Wait for delay before retrying
|
|
413
|
-
await new Promise(resolve => setTimeout(resolve, nextDelay));
|
|
420
|
+
await new Promise((resolve) => setTimeout(resolve, nextDelay));
|
|
414
421
|
continue;
|
|
415
422
|
}
|
|
416
423
|
// If we've exhausted retries, mark as processed to avoid hanging
|
|
@@ -418,7 +425,7 @@ export class PathwaysBuilder {
|
|
|
418
425
|
pathway: pathwayStr,
|
|
419
426
|
eventId: data.eventId,
|
|
420
427
|
retryCount,
|
|
421
|
-
maxRetries
|
|
428
|
+
maxRetries,
|
|
422
429
|
});
|
|
423
430
|
await this.pathwayState.setProcessed(data.eventId);
|
|
424
431
|
throw error;
|
|
@@ -429,7 +436,7 @@ export class PathwaysBuilder {
|
|
|
429
436
|
// No handler, just emit events and mark as processed
|
|
430
437
|
this.logger.debug(`No handler for pathway, emitting events and marking as processed`, {
|
|
431
438
|
pathway: pathwayStr,
|
|
432
|
-
eventId: data.eventId
|
|
439
|
+
eventId: data.eventId,
|
|
433
440
|
});
|
|
434
441
|
this.beforeObservable[pathway].next(data);
|
|
435
442
|
this.afterObservers[pathway].next(data);
|
|
@@ -456,9 +463,9 @@ export class PathwaysBuilder {
|
|
|
456
463
|
isFilePathway: contract.isFilePathway,
|
|
457
464
|
timeoutMs: contract.timeoutMs,
|
|
458
465
|
maxRetries: contract.maxRetries,
|
|
459
|
-
retryDelayMs: contract.retryDelayMs
|
|
460
|
-
})
|
|
461
|
-
|
|
466
|
+
retryDelayMs: contract.retryDelayMs,
|
|
467
|
+
}) // deno-lint-ignore no-explicit-any
|
|
468
|
+
;
|
|
462
469
|
this.pathways[path] = true;
|
|
463
470
|
this.beforeObservable[path] = new Subject();
|
|
464
471
|
this.afterObservers[path] = new Subject();
|
|
@@ -472,6 +479,8 @@ export class PathwaysBuilder {
|
|
|
472
479
|
else {
|
|
473
480
|
this.writers[path] = this.webhookBuilderFactory()
|
|
474
481
|
.buildWebhook(contract.flowType, contract.eventType).send;
|
|
482
|
+
this.batchWriters[path] = this.webhookBuilderFactory()
|
|
483
|
+
.buildWebhook(contract.flowType, contract.eventType).sendBatch;
|
|
475
484
|
}
|
|
476
485
|
}
|
|
477
486
|
if (contract.timeoutMs) {
|
|
@@ -489,7 +498,7 @@ export class PathwaysBuilder {
|
|
|
489
498
|
pathway: path,
|
|
490
499
|
flowType: contract.flowType,
|
|
491
500
|
eventType: contract.eventType,
|
|
492
|
-
writable
|
|
501
|
+
writable,
|
|
493
502
|
});
|
|
494
503
|
return this;
|
|
495
504
|
}
|
|
@@ -558,7 +567,7 @@ export class PathwaysBuilder {
|
|
|
558
567
|
}
|
|
559
568
|
this.logger.info(`Subscription to pathway events set up`, {
|
|
560
569
|
pathway: pathStr,
|
|
561
|
-
type
|
|
570
|
+
type,
|
|
562
571
|
});
|
|
563
572
|
return this;
|
|
564
573
|
}
|
|
@@ -607,8 +616,8 @@ export class PathwaysBuilder {
|
|
|
607
616
|
metadata,
|
|
608
617
|
options: {
|
|
609
618
|
fireAndForget: options?.fireAndForget,
|
|
610
|
-
sessionId: options?.sessionId
|
|
611
|
-
}
|
|
619
|
+
sessionId: options?.sessionId,
|
|
620
|
+
},
|
|
612
621
|
});
|
|
613
622
|
if (!this.pathways[path]) {
|
|
614
623
|
const error = `Pathway ${pathStr} not found`;
|
|
@@ -625,7 +634,7 @@ export class PathwaysBuilder {
|
|
|
625
634
|
const errorMessage = `Invalid data for pathway ${pathStr}`;
|
|
626
635
|
this.logger.error(errorMessage, new Error(errorMessage), {
|
|
627
636
|
pathway: pathStr,
|
|
628
|
-
schema: schema.toString()
|
|
637
|
+
schema: schema.toString(),
|
|
629
638
|
});
|
|
630
639
|
throw new Error(errorMessage);
|
|
631
640
|
}
|
|
@@ -641,13 +650,13 @@ export class PathwaysBuilder {
|
|
|
641
650
|
this.logger.debug(`Using session-specific user resolver`, {
|
|
642
651
|
pathway: pathStr,
|
|
643
652
|
sessionId: options.sessionId,
|
|
644
|
-
userId
|
|
653
|
+
userId,
|
|
645
654
|
});
|
|
646
655
|
}
|
|
647
656
|
catch (error) {
|
|
648
657
|
this.logger.error(`Error resolving session user ID`, error instanceof Error ? error : new Error(String(error)), {
|
|
649
658
|
pathway: pathStr,
|
|
650
|
-
sessionId: options.sessionId
|
|
659
|
+
sessionId: options.sessionId,
|
|
651
660
|
});
|
|
652
661
|
}
|
|
653
662
|
}
|
|
@@ -665,7 +674,7 @@ export class PathwaysBuilder {
|
|
|
665
674
|
this.logger.debug(`Adding audit metadata`, {
|
|
666
675
|
pathway: pathStr,
|
|
667
676
|
auditMode,
|
|
668
|
-
userId
|
|
677
|
+
userId,
|
|
669
678
|
});
|
|
670
679
|
if (userId) {
|
|
671
680
|
// Add appropriate audit metadata based on mode
|
|
@@ -692,15 +701,113 @@ export class PathwaysBuilder {
|
|
|
692
701
|
this.logger.info(`Successfully wrote to pathway`, {
|
|
693
702
|
pathway: pathStr,
|
|
694
703
|
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
695
|
-
fireAndForget: options?.fireAndForget
|
|
704
|
+
fireAndForget: options?.fireAndForget,
|
|
696
705
|
});
|
|
697
706
|
if (!options?.fireAndForget) {
|
|
698
707
|
this.logger.debug(`Waiting for pathway to be processed`, {
|
|
699
708
|
pathway: pathStr,
|
|
700
|
-
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds]
|
|
709
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
701
710
|
});
|
|
702
711
|
await Promise.all(Array.isArray(eventIds)
|
|
703
|
-
? eventIds.map(id => this.waitForPathwayToBeProcessed(id))
|
|
712
|
+
? eventIds.map((id) => this.waitForPathwayToBeProcessed(id))
|
|
713
|
+
: [this.waitForPathwayToBeProcessed(eventIds)]);
|
|
714
|
+
}
|
|
715
|
+
return eventIds;
|
|
716
|
+
}
|
|
717
|
+
async writeBatch(path, data, metadata, options) {
|
|
718
|
+
const pathStr = String(path);
|
|
719
|
+
this.logger.debug(`Writing batch to pathway`, {
|
|
720
|
+
pathway: pathStr,
|
|
721
|
+
metadata,
|
|
722
|
+
options: {
|
|
723
|
+
fireAndForget: options?.fireAndForget,
|
|
724
|
+
sessionId: options?.sessionId,
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
if (!this.pathways[path]) {
|
|
728
|
+
const error = `Pathway ${pathStr} not found`;
|
|
729
|
+
this.logger.error(error);
|
|
730
|
+
throw new Error(error);
|
|
731
|
+
}
|
|
732
|
+
if (!this.writable[path]) {
|
|
733
|
+
const error = `Pathway ${pathStr} is not writable`;
|
|
734
|
+
this.logger.error(error);
|
|
735
|
+
throw new Error(error);
|
|
736
|
+
}
|
|
737
|
+
const schema = this.schemas[path];
|
|
738
|
+
if (!Value.Check(Type.Array(schema), data)) {
|
|
739
|
+
const errorMessage = `Invalid batch data for pathway ${pathStr}`;
|
|
740
|
+
this.logger.error(errorMessage, new Error(errorMessage), {
|
|
741
|
+
pathway: pathStr,
|
|
742
|
+
schema: schema.toString(),
|
|
743
|
+
});
|
|
744
|
+
throw new Error(errorMessage);
|
|
745
|
+
}
|
|
746
|
+
// Create a copy of the metadata to avoid modifying the original
|
|
747
|
+
const finalMetadata = metadata ? { ...metadata } : {};
|
|
748
|
+
// Check for session-specific user resolver
|
|
749
|
+
let userId;
|
|
750
|
+
if (options?.sessionId) {
|
|
751
|
+
const sessionUserResolver = this.getSessionUserResolver(options.sessionId);
|
|
752
|
+
if (sessionUserResolver) {
|
|
753
|
+
try {
|
|
754
|
+
userId = await sessionUserResolver();
|
|
755
|
+
this.logger.debug(`Using session-specific user resolver`, {
|
|
756
|
+
pathway: pathStr,
|
|
757
|
+
sessionId: options.sessionId,
|
|
758
|
+
userId,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
catch (error) {
|
|
762
|
+
this.logger.error(`Error resolving session user ID`, error instanceof Error ? error : new Error(String(error)), {
|
|
763
|
+
pathway: pathStr,
|
|
764
|
+
sessionId: options.sessionId,
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
// Process audit metadata if audit is configured
|
|
770
|
+
if (this.userIdResolver) {
|
|
771
|
+
// Only use global resolver if we don't already have a user ID from a session resolver
|
|
772
|
+
if (!userId) {
|
|
773
|
+
this.logger.debug(`Resolving user ID for audit metadata`, { pathway: pathStr });
|
|
774
|
+
userId = await this.userIdResolver();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
// Determine the audit mode: default is "user" unless explicitly specified as "system"
|
|
778
|
+
const auditMode = options?.auditMode ?? "user";
|
|
779
|
+
this.logger.debug(`Adding audit metadata`, {
|
|
780
|
+
pathway: pathStr,
|
|
781
|
+
auditMode,
|
|
782
|
+
userId,
|
|
783
|
+
});
|
|
784
|
+
if (userId) {
|
|
785
|
+
// Add appropriate audit metadata based on mode
|
|
786
|
+
if (auditMode === "system") {
|
|
787
|
+
finalMetadata["audit/user-id"] = "system";
|
|
788
|
+
finalMetadata["audit/on-behalf-of"] = userId;
|
|
789
|
+
finalMetadata["audit/mode"] = "system";
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
finalMetadata["audit/user-id"] = userId;
|
|
793
|
+
finalMetadata["audit/mode"] = "user"; // Always set mode for user
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
let eventIds = [];
|
|
797
|
+
this.logger.debug(`Writing batch webhook data to pathway`, { pathway: pathStr });
|
|
798
|
+
eventIds = await this.batchWriters[path](data, finalMetadata, options);
|
|
799
|
+
this.logger.info(`Successfully wrote to pathway`, {
|
|
800
|
+
pathway: pathStr,
|
|
801
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
802
|
+
fireAndForget: options?.fireAndForget,
|
|
803
|
+
});
|
|
804
|
+
if (!options?.fireAndForget) {
|
|
805
|
+
this.logger.debug(`Waiting for pathway to be processed`, {
|
|
806
|
+
pathway: pathStr,
|
|
807
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
808
|
+
});
|
|
809
|
+
await Promise.all(Array.isArray(eventIds)
|
|
810
|
+
? eventIds.map((id) => this.waitForPathwayToBeProcessed(id))
|
|
704
811
|
: [this.waitForPathwayToBeProcessed(eventIds)]);
|
|
705
812
|
}
|
|
706
813
|
return eventIds;
|
|
@@ -721,7 +828,7 @@ export class PathwaysBuilder {
|
|
|
721
828
|
const timeoutMs = this.timeouts[eventId] ?? this.pathwayTimeoutMs;
|
|
722
829
|
this.logger.debug(`Waiting for event to be processed`, {
|
|
723
830
|
eventId,
|
|
724
|
-
timeoutMs
|
|
831
|
+
timeoutMs,
|
|
725
832
|
});
|
|
726
833
|
let attempts = 0;
|
|
727
834
|
while (!(await this.pathwayState.isProcessed(eventId))) {
|
|
@@ -733,7 +840,7 @@ export class PathwaysBuilder {
|
|
|
733
840
|
eventId,
|
|
734
841
|
timeoutMs,
|
|
735
842
|
elapsedTime,
|
|
736
|
-
attempts
|
|
843
|
+
attempts,
|
|
737
844
|
});
|
|
738
845
|
throw new Error(errorMessage);
|
|
739
846
|
}
|
|
@@ -742,7 +849,7 @@ export class PathwaysBuilder {
|
|
|
742
849
|
eventId,
|
|
743
850
|
elapsedTime,
|
|
744
851
|
attempts,
|
|
745
|
-
timeoutMs
|
|
852
|
+
timeoutMs,
|
|
746
853
|
});
|
|
747
854
|
}
|
|
748
855
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -750,7 +857,7 @@ export class PathwaysBuilder {
|
|
|
750
857
|
this.logger.debug(`Event has been processed`, {
|
|
751
858
|
eventId,
|
|
752
859
|
elapsedTime: Date.now() - startTime,
|
|
753
|
-
attempts
|
|
860
|
+
attempts,
|
|
754
861
|
});
|
|
755
862
|
}
|
|
756
863
|
}
|
package/esm/pathways/types.d.ts
CHANGED
|
@@ -89,6 +89,11 @@ export interface EventMetadata extends Record<string, unknown> {
|
|
|
89
89
|
* @template EventPayload The type of the event payload
|
|
90
90
|
*/
|
|
91
91
|
export type SendWebhook<EventPayload> = (payload: EventPayload, metadata?: EventMetadata, options?: WebhookSendOptions) => Promise<string>;
|
|
92
|
+
/**
|
|
93
|
+
* Function type for sending batch events to a webhook
|
|
94
|
+
* @template EventPayload The type of the event payload
|
|
95
|
+
*/
|
|
96
|
+
export type SendWebhookBatch<EventPayload> = (payload: EventPayload[], metadata?: EventMetadata, options?: WebhookSendOptions) => Promise<string[]>;
|
|
92
97
|
/**
|
|
93
98
|
* Function type for sending a file to a webhook
|
|
94
99
|
*/
|
|
@@ -108,12 +113,12 @@ export type PathwayState = {
|
|
|
108
113
|
* @param eventId The ID of the event to check
|
|
109
114
|
* @returns Boolean indicating if the event has been processed
|
|
110
115
|
*/
|
|
111
|
-
isProcessed: (eventId: string) =>
|
|
116
|
+
isProcessed: (eventId: string) => boolean | Promise<boolean>;
|
|
112
117
|
/**
|
|
113
118
|
* Marks an event as processed
|
|
114
119
|
* @param eventId The ID of the event to mark as processed
|
|
115
120
|
*/
|
|
116
|
-
setProcessed: (eventId: string) =>
|
|
121
|
+
setProcessed: (eventId: string) => void | Promise<void>;
|
|
117
122
|
};
|
|
118
123
|
/**
|
|
119
124
|
* Options for pathway writes, extending WebhookSendOptions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pathways/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEzF;;;GAGG;AACH,KAAK,uBAAuB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG;IACnD,QAAQ,CAAC,yBAAyB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pathways/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEzF;;;GAGG;AACH,KAAK,uBAAuB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG;IACnD,QAAQ,CAAC,yBAAyB,EAChC,wGAAwG,CAAA;CAC3G,CAAA;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO;IACpF;;OAEG;IACH,QAAQ,EAAE,CAAC,CAAA;IAEX;;OAEG;IACH,SAAS,EAAE,CAAC,CAAA;IAEZ;;OAEG;IACH,MAAM,EAAE,CAAC,CAAA;IAET;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAA;AAExE;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAAG;AAEjE;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,YAAY,IAAI,CACtC,OAAO,EAAE,YAAY,EACrB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAA;AAEpB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,YAAY,IAAI,CAC3C,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AAEtB;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,EAAE,eAAe,EACxB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AAEtB;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,KAAK,GAChG,uBAAuB,CAAC,CAAC,CAAC,GAC1B,CAAC,CAAA;AAEL;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE5D;;;OAGG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACxD,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG;IACrD;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAE7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowcore/pathways",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "A TypeScript Library for creating Flowcore Pathways, simplifying the integration with the flowcore platform",
|
|
5
5
|
"homepage": "https://github.com/flowcore-io/flowcore-pathways#readme",
|
|
6
6
|
"repository": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Static, type TSchema } from "@sinclair/typebox";
|
|
2
2
|
import type { WebhookSendOptions } from "@flowcore/sdk-transformer-core";
|
|
3
3
|
import type { FlowcoreEvent } from "../contracts/event.js";
|
|
4
4
|
import type { KvAdapter } from "./kv/kv-adapter.js";
|
|
@@ -52,6 +52,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
52
52
|
private readonly errorObservers;
|
|
53
53
|
private readonly globalErrorSubject;
|
|
54
54
|
private readonly writers;
|
|
55
|
+
private readonly batchWriters;
|
|
55
56
|
private readonly schemas;
|
|
56
57
|
private readonly writable;
|
|
57
58
|
private readonly timeouts;
|
|
@@ -187,16 +188,16 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
187
188
|
* @param handler The function that will process events for this pathway
|
|
188
189
|
* @throws Error if the pathway doesn't exist or already has a handler
|
|
189
190
|
*/
|
|
190
|
-
handle<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent,
|
|
191
|
+
handle<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent, "payload"> & {
|
|
191
192
|
payload: TPathway[TPath];
|
|
192
|
-
}) =>
|
|
193
|
+
}) => Promise<void> | void): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
193
194
|
/**
|
|
194
195
|
* Subscribe to pathway events (before or after processing)
|
|
195
196
|
* @param path The pathway to subscribe to
|
|
196
197
|
* @param handler The handler function for the events
|
|
197
198
|
* @param type The event type to subscribe to (before, after, or all)
|
|
198
199
|
*/
|
|
199
|
-
subscribe<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent,
|
|
200
|
+
subscribe<TPath extends keyof TPathway>(path: TPath, handler: (event: Omit<FlowcoreEvent, "payload"> & {
|
|
200
201
|
payload: TPathway[TPath];
|
|
201
202
|
}) => void, type?: "before" | "after" | "all"): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
202
203
|
/**
|
|
@@ -204,7 +205,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
204
205
|
* @param path The pathway to subscribe to errors for
|
|
205
206
|
* @param handler The handler function that receives the error and event
|
|
206
207
|
*/
|
|
207
|
-
onError<TPath extends keyof TPathway>(path: TPath, handler: (error: Error, event: Omit<FlowcoreEvent,
|
|
208
|
+
onError<TPath extends keyof TPathway>(path: TPath, handler: (error: Error, event: Omit<FlowcoreEvent, "payload"> & {
|
|
208
209
|
payload: TPathway[TPath];
|
|
209
210
|
}) => void): PathwaysBuilder<TPathway, TWritablePaths>;
|
|
210
211
|
/**
|
|
@@ -221,6 +222,7 @@ export declare class PathwaysBuilder<TPathway extends Record<string, unknown> =
|
|
|
221
222
|
* @returns A promise that resolves to the event ID(s)
|
|
222
223
|
*/
|
|
223
224
|
write<TPath extends TWritablePaths>(path: TPath, data: TPathway[TPath], metadata?: EventMetadata, options?: PathwayWriteOptions): Promise<string | string[]>;
|
|
225
|
+
writeBatch<TPath extends TWritablePaths>(path: TPath, data: TPathway[TPath][], metadata?: EventMetadata, options?: PathwayWriteOptions): Promise<string | string[]>;
|
|
224
226
|
/**
|
|
225
227
|
* Waits for a specific event to be processed
|
|
226
228
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/pathways/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/pathways/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAQ,MAAM,mBAAmB,CAAA;AAEnE,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,gCAAgC,CAAA;AAGvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,UAAU,EACV,YAAY,EACZ,mBAAmB,EAInB,eAAe,EAChB,MAAM,YAAY,CAAA;AAsBnB;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEzC;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;AAEvE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe,CAE1B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,EAC7C,cAAc,SAAS,MAAM,QAAQ,GAAG,KAAK;IAE7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAGxB;IACD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAGhC;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAG9B;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAI5B;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAyE;IAC5G,OAAO,CAAC,QAAQ,CAAC,OAAO,CAIrB;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAG5B;IACD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyE;IACjG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyE;IAClG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuE;IAChG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuE;IAClG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuE;IACnG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA0B;IAChE,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,gBAAgB,CAAqC;IAG7D,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAyB;IAG9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAG/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAE/B;;;;;;;;;;OAUG;gBACS,EACV,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,EACN,gBAAgB,EAChB,MAAM,EACN,oBAAoB,GACrB,EAAE;QACD,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,oBAAoB,CAAC,EAAE,SAAS,CAAA;KACjC;IAsCD;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAMhF;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAM3E;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAMrF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAU/G;;;;OAIG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAQrE;;;;;OAKG;IACU,OAAO,CAAC,OAAO,EAAE,MAAM,QAAQ,EAAE,IAAI,EAAE,aAAa;IA+IjE;;;;;;;;OAQG;IACH,QAAQ,CACN,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,OAAO,EACjB,CAAC,SAAS,OAAO,GAAG,IAAI,EAExB,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAChG,eAAe,CAChB,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAC9C,cAAc,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CACtD;IAgED;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,SAAS,MAAM,QAAQ,EAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAK/D;;;;;;;;;;OAUG;IACH,MAAM,CAAC,KAAK,SAAS,MAAM,QAAQ,EACjC,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GACtG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAsB5C;;;;;OAKG;IACH,SAAS,CAAC,KAAK,SAAS,MAAM,QAAQ,EACpC,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;KAAE,KAAK,IAAI,EACvF,IAAI,GAAE,QAAQ,GAAG,OAAO,GAAG,KAAgB,GAC1C,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IA8B5C;;;;OAIG;IACH,OAAO,CAAC,KAAK,SAAS,MAAM,QAAQ,EAClC,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;KAAE,KAAK,IAAI,GACpG,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAqB5C;;;OAGG;IACH,UAAU,CACR,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GACrE,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC;IAQ5C;;;;;;;OAOG;IACG,KAAK,CAAC,KAAK,SAAS,cAAc,EACtC,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EACrB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;IA4HvB,UAAU,CAAC,KAAK,SAAS,cAAc,EAC3C,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,EACvB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;IAsH7B;;;;;;;;;;OAUG;YACW,2BAA2B;CA4C1C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PathwaysBuilder = void 0;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
4
5
|
const value_1 = require("@sinclair/typebox/value");
|
|
5
6
|
const rxjs_1 = require("rxjs");
|
|
6
7
|
const flowcore_transformer_core_sdk_js_1 = require("../compatibility/flowcore-transformer-core.sdk.js");
|
|
@@ -91,6 +92,12 @@ class PathwaysBuilder {
|
|
|
91
92
|
writable: true,
|
|
92
93
|
value: {}
|
|
93
94
|
});
|
|
95
|
+
Object.defineProperty(this, "batchWriters", {
|
|
96
|
+
enumerable: true,
|
|
97
|
+
configurable: true,
|
|
98
|
+
writable: true,
|
|
99
|
+
value: {}
|
|
100
|
+
});
|
|
94
101
|
Object.defineProperty(this, "schemas", {
|
|
95
102
|
enumerable: true,
|
|
96
103
|
configurable: true,
|
|
@@ -207,11 +214,11 @@ class PathwaysBuilder {
|
|
|
207
214
|
if (sessionUserResolvers) {
|
|
208
215
|
this.sessionUserResolvers = sessionUserResolvers;
|
|
209
216
|
}
|
|
210
|
-
this.logger.debug(
|
|
217
|
+
this.logger.debug("Initializing PathwaysBuilder", {
|
|
211
218
|
baseUrl,
|
|
212
219
|
tenant,
|
|
213
220
|
dataCore,
|
|
214
|
-
pathwayTimeoutMs
|
|
221
|
+
pathwayTimeoutMs,
|
|
215
222
|
});
|
|
216
223
|
this.webhookBuilderFactory = new flowcore_transformer_core_sdk_js_1.WebhookBuilder({
|
|
217
224
|
baseUrl,
|
|
@@ -234,7 +241,7 @@ class PathwaysBuilder {
|
|
|
234
241
|
* @returns The PathwaysBuilder instance with custom state configured
|
|
235
242
|
*/
|
|
236
243
|
withPathwayState(state) {
|
|
237
|
-
this.logger.debug(
|
|
244
|
+
this.logger.debug("Setting custom pathway state");
|
|
238
245
|
this.pathwayState = state;
|
|
239
246
|
return this;
|
|
240
247
|
}
|
|
@@ -244,7 +251,7 @@ class PathwaysBuilder {
|
|
|
244
251
|
* @returns The PathwaysBuilder instance with audit configured
|
|
245
252
|
*/
|
|
246
253
|
withAudit(handler) {
|
|
247
|
-
this.logger.debug(
|
|
254
|
+
this.logger.debug("Configuring audit functionality");
|
|
248
255
|
this.auditHandler = handler;
|
|
249
256
|
return this;
|
|
250
257
|
}
|
|
@@ -254,7 +261,7 @@ class PathwaysBuilder {
|
|
|
254
261
|
* @returns The PathwaysBuilder instance with custom user ID resolver configured
|
|
255
262
|
*/
|
|
256
263
|
withUserResolver(resolver) {
|
|
257
|
-
this.logger.debug(
|
|
264
|
+
this.logger.debug("Configuring user resolver");
|
|
258
265
|
this.userIdResolver = resolver;
|
|
259
266
|
return this;
|
|
260
267
|
}
|
|
@@ -293,9 +300,9 @@ class PathwaysBuilder {
|
|
|
293
300
|
*/
|
|
294
301
|
withSessionUserResolver(sessionId, resolver) {
|
|
295
302
|
if (!this.sessionUserResolvers) {
|
|
296
|
-
throw new Error(
|
|
303
|
+
throw new Error("Session user resolvers not configured");
|
|
297
304
|
}
|
|
298
|
-
this.logger.debug(
|
|
305
|
+
this.logger.debug("Configuring session-specific user resolver", { sessionId });
|
|
299
306
|
this.sessionUserResolvers.set(sessionId, resolver, DEFAULT_SESSION_USER_RESOLVER_TTL_MS);
|
|
300
307
|
return this;
|
|
301
308
|
}
|
|
@@ -321,7 +328,7 @@ class PathwaysBuilder {
|
|
|
321
328
|
const pathwayStr = String(pathway);
|
|
322
329
|
this.logger.debug(`Processing pathway event`, {
|
|
323
330
|
pathway: pathwayStr,
|
|
324
|
-
eventId: data.eventId
|
|
331
|
+
eventId: data.eventId,
|
|
325
332
|
});
|
|
326
333
|
if (!this.pathways[pathway]) {
|
|
327
334
|
const error = `Pathway ${pathwayStr} not found`;
|
|
@@ -348,7 +355,7 @@ class PathwaysBuilder {
|
|
|
348
355
|
if (this.auditHandler) {
|
|
349
356
|
this.logger.debug(`Calling audit handler for pathway`, {
|
|
350
357
|
pathway: pathwayStr,
|
|
351
|
-
eventId: data.eventId
|
|
358
|
+
eventId: data.eventId,
|
|
352
359
|
});
|
|
353
360
|
this.auditHandler(pathwayStr, data);
|
|
354
361
|
}
|
|
@@ -358,7 +365,7 @@ class PathwaysBuilder {
|
|
|
358
365
|
const retryDelayMs = this.retryDelays[pathway] ?? DEFAULT_RETRY_DELAY_MS;
|
|
359
366
|
this.logger.debug(`Emitting 'before' event`, {
|
|
360
367
|
pathway: pathwayStr,
|
|
361
|
-
eventId: data.eventId
|
|
368
|
+
eventId: data.eventId,
|
|
362
369
|
});
|
|
363
370
|
this.beforeObservable[pathway].next(data);
|
|
364
371
|
while (true) {
|
|
@@ -366,7 +373,7 @@ class PathwaysBuilder {
|
|
|
366
373
|
this.logger.debug(`Executing handler for pathway`, {
|
|
367
374
|
pathway: pathwayStr,
|
|
368
375
|
eventId: data.eventId,
|
|
369
|
-
attempt: retryCount + 1
|
|
376
|
+
attempt: retryCount + 1,
|
|
370
377
|
});
|
|
371
378
|
// Execute the handler
|
|
372
379
|
const handle = this.handlers[pathway](data);
|
|
@@ -374,13 +381,13 @@ class PathwaysBuilder {
|
|
|
374
381
|
// If successful, emit success event and mark as processed
|
|
375
382
|
this.logger.debug(`Handler executed successfully, emitting 'after' event`, {
|
|
376
383
|
pathway: pathwayStr,
|
|
377
|
-
eventId: data.eventId
|
|
384
|
+
eventId: data.eventId,
|
|
378
385
|
});
|
|
379
386
|
this.afterObservers[pathway].next(data);
|
|
380
387
|
await this.pathwayState.setProcessed(data.eventId);
|
|
381
388
|
this.logger.info(`Successfully processed pathway event`, {
|
|
382
389
|
pathway: pathwayStr,
|
|
383
|
-
eventId: data.eventId
|
|
390
|
+
eventId: data.eventId,
|
|
384
391
|
});
|
|
385
392
|
return;
|
|
386
393
|
}
|
|
@@ -391,7 +398,7 @@ class PathwaysBuilder {
|
|
|
391
398
|
pathway: pathwayStr,
|
|
392
399
|
eventId: data.eventId,
|
|
393
400
|
retryCount,
|
|
394
|
-
maxRetries
|
|
401
|
+
maxRetries,
|
|
395
402
|
});
|
|
396
403
|
// Emit error event with both error and event data
|
|
397
404
|
this.errorObservers[pathway].next({ event: data, error: errorObj });
|
|
@@ -399,7 +406,7 @@ class PathwaysBuilder {
|
|
|
399
406
|
this.globalErrorSubject.next({
|
|
400
407
|
pathway: pathwayStr,
|
|
401
408
|
event: data,
|
|
402
|
-
error: errorObj
|
|
409
|
+
error: errorObj,
|
|
403
410
|
});
|
|
404
411
|
// Check if we should retry
|
|
405
412
|
if (retryCount < maxRetries) {
|
|
@@ -410,10 +417,10 @@ class PathwaysBuilder {
|
|
|
410
417
|
eventId: data.eventId,
|
|
411
418
|
attempt: retryCount,
|
|
412
419
|
maxRetries,
|
|
413
|
-
nextDelay
|
|
420
|
+
nextDelay,
|
|
414
421
|
});
|
|
415
422
|
// Wait for delay before retrying
|
|
416
|
-
await new Promise(resolve => setTimeout(resolve, nextDelay));
|
|
423
|
+
await new Promise((resolve) => setTimeout(resolve, nextDelay));
|
|
417
424
|
continue;
|
|
418
425
|
}
|
|
419
426
|
// If we've exhausted retries, mark as processed to avoid hanging
|
|
@@ -421,7 +428,7 @@ class PathwaysBuilder {
|
|
|
421
428
|
pathway: pathwayStr,
|
|
422
429
|
eventId: data.eventId,
|
|
423
430
|
retryCount,
|
|
424
|
-
maxRetries
|
|
431
|
+
maxRetries,
|
|
425
432
|
});
|
|
426
433
|
await this.pathwayState.setProcessed(data.eventId);
|
|
427
434
|
throw error;
|
|
@@ -432,7 +439,7 @@ class PathwaysBuilder {
|
|
|
432
439
|
// No handler, just emit events and mark as processed
|
|
433
440
|
this.logger.debug(`No handler for pathway, emitting events and marking as processed`, {
|
|
434
441
|
pathway: pathwayStr,
|
|
435
|
-
eventId: data.eventId
|
|
442
|
+
eventId: data.eventId,
|
|
436
443
|
});
|
|
437
444
|
this.beforeObservable[pathway].next(data);
|
|
438
445
|
this.afterObservers[pathway].next(data);
|
|
@@ -459,9 +466,9 @@ class PathwaysBuilder {
|
|
|
459
466
|
isFilePathway: contract.isFilePathway,
|
|
460
467
|
timeoutMs: contract.timeoutMs,
|
|
461
468
|
maxRetries: contract.maxRetries,
|
|
462
|
-
retryDelayMs: contract.retryDelayMs
|
|
463
|
-
})
|
|
464
|
-
|
|
469
|
+
retryDelayMs: contract.retryDelayMs,
|
|
470
|
+
}) // deno-lint-ignore no-explicit-any
|
|
471
|
+
;
|
|
465
472
|
this.pathways[path] = true;
|
|
466
473
|
this.beforeObservable[path] = new rxjs_1.Subject();
|
|
467
474
|
this.afterObservers[path] = new rxjs_1.Subject();
|
|
@@ -475,6 +482,8 @@ class PathwaysBuilder {
|
|
|
475
482
|
else {
|
|
476
483
|
this.writers[path] = this.webhookBuilderFactory()
|
|
477
484
|
.buildWebhook(contract.flowType, contract.eventType).send;
|
|
485
|
+
this.batchWriters[path] = this.webhookBuilderFactory()
|
|
486
|
+
.buildWebhook(contract.flowType, contract.eventType).sendBatch;
|
|
478
487
|
}
|
|
479
488
|
}
|
|
480
489
|
if (contract.timeoutMs) {
|
|
@@ -492,7 +501,7 @@ class PathwaysBuilder {
|
|
|
492
501
|
pathway: path,
|
|
493
502
|
flowType: contract.flowType,
|
|
494
503
|
eventType: contract.eventType,
|
|
495
|
-
writable
|
|
504
|
+
writable,
|
|
496
505
|
});
|
|
497
506
|
return this;
|
|
498
507
|
}
|
|
@@ -561,7 +570,7 @@ class PathwaysBuilder {
|
|
|
561
570
|
}
|
|
562
571
|
this.logger.info(`Subscription to pathway events set up`, {
|
|
563
572
|
pathway: pathStr,
|
|
564
|
-
type
|
|
573
|
+
type,
|
|
565
574
|
});
|
|
566
575
|
return this;
|
|
567
576
|
}
|
|
@@ -610,8 +619,8 @@ class PathwaysBuilder {
|
|
|
610
619
|
metadata,
|
|
611
620
|
options: {
|
|
612
621
|
fireAndForget: options?.fireAndForget,
|
|
613
|
-
sessionId: options?.sessionId
|
|
614
|
-
}
|
|
622
|
+
sessionId: options?.sessionId,
|
|
623
|
+
},
|
|
615
624
|
});
|
|
616
625
|
if (!this.pathways[path]) {
|
|
617
626
|
const error = `Pathway ${pathStr} not found`;
|
|
@@ -628,7 +637,7 @@ class PathwaysBuilder {
|
|
|
628
637
|
const errorMessage = `Invalid data for pathway ${pathStr}`;
|
|
629
638
|
this.logger.error(errorMessage, new Error(errorMessage), {
|
|
630
639
|
pathway: pathStr,
|
|
631
|
-
schema: schema.toString()
|
|
640
|
+
schema: schema.toString(),
|
|
632
641
|
});
|
|
633
642
|
throw new Error(errorMessage);
|
|
634
643
|
}
|
|
@@ -644,13 +653,13 @@ class PathwaysBuilder {
|
|
|
644
653
|
this.logger.debug(`Using session-specific user resolver`, {
|
|
645
654
|
pathway: pathStr,
|
|
646
655
|
sessionId: options.sessionId,
|
|
647
|
-
userId
|
|
656
|
+
userId,
|
|
648
657
|
});
|
|
649
658
|
}
|
|
650
659
|
catch (error) {
|
|
651
660
|
this.logger.error(`Error resolving session user ID`, error instanceof Error ? error : new Error(String(error)), {
|
|
652
661
|
pathway: pathStr,
|
|
653
|
-
sessionId: options.sessionId
|
|
662
|
+
sessionId: options.sessionId,
|
|
654
663
|
});
|
|
655
664
|
}
|
|
656
665
|
}
|
|
@@ -668,7 +677,7 @@ class PathwaysBuilder {
|
|
|
668
677
|
this.logger.debug(`Adding audit metadata`, {
|
|
669
678
|
pathway: pathStr,
|
|
670
679
|
auditMode,
|
|
671
|
-
userId
|
|
680
|
+
userId,
|
|
672
681
|
});
|
|
673
682
|
if (userId) {
|
|
674
683
|
// Add appropriate audit metadata based on mode
|
|
@@ -695,15 +704,113 @@ class PathwaysBuilder {
|
|
|
695
704
|
this.logger.info(`Successfully wrote to pathway`, {
|
|
696
705
|
pathway: pathStr,
|
|
697
706
|
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
698
|
-
fireAndForget: options?.fireAndForget
|
|
707
|
+
fireAndForget: options?.fireAndForget,
|
|
699
708
|
});
|
|
700
709
|
if (!options?.fireAndForget) {
|
|
701
710
|
this.logger.debug(`Waiting for pathway to be processed`, {
|
|
702
711
|
pathway: pathStr,
|
|
703
|
-
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds]
|
|
712
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
704
713
|
});
|
|
705
714
|
await Promise.all(Array.isArray(eventIds)
|
|
706
|
-
? eventIds.map(id => this.waitForPathwayToBeProcessed(id))
|
|
715
|
+
? eventIds.map((id) => this.waitForPathwayToBeProcessed(id))
|
|
716
|
+
: [this.waitForPathwayToBeProcessed(eventIds)]);
|
|
717
|
+
}
|
|
718
|
+
return eventIds;
|
|
719
|
+
}
|
|
720
|
+
async writeBatch(path, data, metadata, options) {
|
|
721
|
+
const pathStr = String(path);
|
|
722
|
+
this.logger.debug(`Writing batch to pathway`, {
|
|
723
|
+
pathway: pathStr,
|
|
724
|
+
metadata,
|
|
725
|
+
options: {
|
|
726
|
+
fireAndForget: options?.fireAndForget,
|
|
727
|
+
sessionId: options?.sessionId,
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
if (!this.pathways[path]) {
|
|
731
|
+
const error = `Pathway ${pathStr} not found`;
|
|
732
|
+
this.logger.error(error);
|
|
733
|
+
throw new Error(error);
|
|
734
|
+
}
|
|
735
|
+
if (!this.writable[path]) {
|
|
736
|
+
const error = `Pathway ${pathStr} is not writable`;
|
|
737
|
+
this.logger.error(error);
|
|
738
|
+
throw new Error(error);
|
|
739
|
+
}
|
|
740
|
+
const schema = this.schemas[path];
|
|
741
|
+
if (!value_1.Value.Check(typebox_1.Type.Array(schema), data)) {
|
|
742
|
+
const errorMessage = `Invalid batch data for pathway ${pathStr}`;
|
|
743
|
+
this.logger.error(errorMessage, new Error(errorMessage), {
|
|
744
|
+
pathway: pathStr,
|
|
745
|
+
schema: schema.toString(),
|
|
746
|
+
});
|
|
747
|
+
throw new Error(errorMessage);
|
|
748
|
+
}
|
|
749
|
+
// Create a copy of the metadata to avoid modifying the original
|
|
750
|
+
const finalMetadata = metadata ? { ...metadata } : {};
|
|
751
|
+
// Check for session-specific user resolver
|
|
752
|
+
let userId;
|
|
753
|
+
if (options?.sessionId) {
|
|
754
|
+
const sessionUserResolver = this.getSessionUserResolver(options.sessionId);
|
|
755
|
+
if (sessionUserResolver) {
|
|
756
|
+
try {
|
|
757
|
+
userId = await sessionUserResolver();
|
|
758
|
+
this.logger.debug(`Using session-specific user resolver`, {
|
|
759
|
+
pathway: pathStr,
|
|
760
|
+
sessionId: options.sessionId,
|
|
761
|
+
userId,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
this.logger.error(`Error resolving session user ID`, error instanceof Error ? error : new Error(String(error)), {
|
|
766
|
+
pathway: pathStr,
|
|
767
|
+
sessionId: options.sessionId,
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// Process audit metadata if audit is configured
|
|
773
|
+
if (this.userIdResolver) {
|
|
774
|
+
// Only use global resolver if we don't already have a user ID from a session resolver
|
|
775
|
+
if (!userId) {
|
|
776
|
+
this.logger.debug(`Resolving user ID for audit metadata`, { pathway: pathStr });
|
|
777
|
+
userId = await this.userIdResolver();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// Determine the audit mode: default is "user" unless explicitly specified as "system"
|
|
781
|
+
const auditMode = options?.auditMode ?? "user";
|
|
782
|
+
this.logger.debug(`Adding audit metadata`, {
|
|
783
|
+
pathway: pathStr,
|
|
784
|
+
auditMode,
|
|
785
|
+
userId,
|
|
786
|
+
});
|
|
787
|
+
if (userId) {
|
|
788
|
+
// Add appropriate audit metadata based on mode
|
|
789
|
+
if (auditMode === "system") {
|
|
790
|
+
finalMetadata["audit/user-id"] = "system";
|
|
791
|
+
finalMetadata["audit/on-behalf-of"] = userId;
|
|
792
|
+
finalMetadata["audit/mode"] = "system";
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
finalMetadata["audit/user-id"] = userId;
|
|
796
|
+
finalMetadata["audit/mode"] = "user"; // Always set mode for user
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
let eventIds = [];
|
|
800
|
+
this.logger.debug(`Writing batch webhook data to pathway`, { pathway: pathStr });
|
|
801
|
+
eventIds = await this.batchWriters[path](data, finalMetadata, options);
|
|
802
|
+
this.logger.info(`Successfully wrote to pathway`, {
|
|
803
|
+
pathway: pathStr,
|
|
804
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
805
|
+
fireAndForget: options?.fireAndForget,
|
|
806
|
+
});
|
|
807
|
+
if (!options?.fireAndForget) {
|
|
808
|
+
this.logger.debug(`Waiting for pathway to be processed`, {
|
|
809
|
+
pathway: pathStr,
|
|
810
|
+
eventIds: Array.isArray(eventIds) ? eventIds : [eventIds],
|
|
811
|
+
});
|
|
812
|
+
await Promise.all(Array.isArray(eventIds)
|
|
813
|
+
? eventIds.map((id) => this.waitForPathwayToBeProcessed(id))
|
|
707
814
|
: [this.waitForPathwayToBeProcessed(eventIds)]);
|
|
708
815
|
}
|
|
709
816
|
return eventIds;
|
|
@@ -724,7 +831,7 @@ class PathwaysBuilder {
|
|
|
724
831
|
const timeoutMs = this.timeouts[eventId] ?? this.pathwayTimeoutMs;
|
|
725
832
|
this.logger.debug(`Waiting for event to be processed`, {
|
|
726
833
|
eventId,
|
|
727
|
-
timeoutMs
|
|
834
|
+
timeoutMs,
|
|
728
835
|
});
|
|
729
836
|
let attempts = 0;
|
|
730
837
|
while (!(await this.pathwayState.isProcessed(eventId))) {
|
|
@@ -736,7 +843,7 @@ class PathwaysBuilder {
|
|
|
736
843
|
eventId,
|
|
737
844
|
timeoutMs,
|
|
738
845
|
elapsedTime,
|
|
739
|
-
attempts
|
|
846
|
+
attempts,
|
|
740
847
|
});
|
|
741
848
|
throw new Error(errorMessage);
|
|
742
849
|
}
|
|
@@ -745,7 +852,7 @@ class PathwaysBuilder {
|
|
|
745
852
|
eventId,
|
|
746
853
|
elapsedTime,
|
|
747
854
|
attempts,
|
|
748
|
-
timeoutMs
|
|
855
|
+
timeoutMs,
|
|
749
856
|
});
|
|
750
857
|
}
|
|
751
858
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -753,7 +860,7 @@ class PathwaysBuilder {
|
|
|
753
860
|
this.logger.debug(`Event has been processed`, {
|
|
754
861
|
eventId,
|
|
755
862
|
elapsedTime: Date.now() - startTime,
|
|
756
|
-
attempts
|
|
863
|
+
attempts,
|
|
757
864
|
});
|
|
758
865
|
}
|
|
759
866
|
}
|
|
@@ -89,6 +89,11 @@ export interface EventMetadata extends Record<string, unknown> {
|
|
|
89
89
|
* @template EventPayload The type of the event payload
|
|
90
90
|
*/
|
|
91
91
|
export type SendWebhook<EventPayload> = (payload: EventPayload, metadata?: EventMetadata, options?: WebhookSendOptions) => Promise<string>;
|
|
92
|
+
/**
|
|
93
|
+
* Function type for sending batch events to a webhook
|
|
94
|
+
* @template EventPayload The type of the event payload
|
|
95
|
+
*/
|
|
96
|
+
export type SendWebhookBatch<EventPayload> = (payload: EventPayload[], metadata?: EventMetadata, options?: WebhookSendOptions) => Promise<string[]>;
|
|
92
97
|
/**
|
|
93
98
|
* Function type for sending a file to a webhook
|
|
94
99
|
*/
|
|
@@ -108,12 +113,12 @@ export type PathwayState = {
|
|
|
108
113
|
* @param eventId The ID of the event to check
|
|
109
114
|
* @returns Boolean indicating if the event has been processed
|
|
110
115
|
*/
|
|
111
|
-
isProcessed: (eventId: string) =>
|
|
116
|
+
isProcessed: (eventId: string) => boolean | Promise<boolean>;
|
|
112
117
|
/**
|
|
113
118
|
* Marks an event as processed
|
|
114
119
|
* @param eventId The ID of the event to mark as processed
|
|
115
120
|
*/
|
|
116
|
-
setProcessed: (eventId: string) =>
|
|
121
|
+
setProcessed: (eventId: string) => void | Promise<void>;
|
|
117
122
|
};
|
|
118
123
|
/**
|
|
119
124
|
* Options for pathway writes, extending WebhookSendOptions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pathways/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEzF;;;GAGG;AACH,KAAK,uBAAuB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG;IACnD,QAAQ,CAAC,yBAAyB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pathways/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEzF;;;GAGG;AACH,KAAK,uBAAuB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG;IACnD,QAAQ,CAAC,yBAAyB,EAChC,wGAAwG,CAAA;CAC3G,CAAA;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO;IACpF;;OAEG;IACH,QAAQ,EAAE,CAAC,CAAA;IAEX;;OAEG;IACH,SAAS,EAAE,CAAC,CAAA;IAEZ;;OAEG;IACH,MAAM,EAAE,CAAC,CAAA;IAET;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAA;AAExE;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAAG;AAEjE;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,YAAY,IAAI,CACtC,OAAO,EAAE,YAAY,EACrB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAA;AAEpB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,YAAY,IAAI,CAC3C,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AAEtB;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,EAAE,eAAe,EACxB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AAEtB;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,UAAU,SAAS,OAAO,IAAI,UAAU,SAAS,KAAK,GAChG,uBAAuB,CAAC,CAAC,CAAC,GAC1B,CAAC,CAAA;AAEL;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE5D;;;OAGG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACxD,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG;IACrD;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAE7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA"}
|