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