@pgflow/client 0.11.0 → 0.12.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 +20 -0
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/pgflow-client.browser.js +1 -1
- package/dist/pgflow-client.browser.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @pgflow/client
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 37402eb: BREAKING: Asymmetric handler signatures - remove `run` key from step inputs
|
|
8
|
+
|
|
9
|
+
- Root steps: `(flowInput, ctx) => ...` - flow input directly as first param
|
|
10
|
+
- Dependent steps: `(deps, ctx) => ...` - only dependency outputs as first param
|
|
11
|
+
- Access flow input in dependent steps via `await ctx.flowInput` (async/lazy-loaded)
|
|
12
|
+
- Lazy loading prevents data duplication for map steps processing large arrays
|
|
13
|
+
- Enables functional composition and simplifies types for future subflows
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- d7e77fd: Fix setTimeout context binding issue in SupabaseBroadcastAdapter for browser compatibility
|
|
18
|
+
- Updated dependencies [37402eb]
|
|
19
|
+
- Updated dependencies [5dc5cfc]
|
|
20
|
+
- @pgflow/core@0.12.0
|
|
21
|
+
- @pgflow/dsl@0.12.0
|
|
22
|
+
|
|
3
23
|
## 0.11.0
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ class rt {
|
|
|
56
56
|
d(this, M);
|
|
57
57
|
// Store unsubscribe functions per run ID for reference equality
|
|
58
58
|
d(this, k, /* @__PURE__ */ new Map());
|
|
59
|
-
f(this, S, t), f(this, I, r.reconnectDelayMs ?? 2e3), f(this, W, r.stabilizationDelayMs ?? 300), f(this, M, r.schedule ?? setTimeout);
|
|
59
|
+
f(this, S, t), f(this, I, r.reconnectDelayMs ?? 2e3), f(this, W, r.stabilizationDelayMs ?? 300), f(this, M, r.schedule ?? setTimeout.bind(globalThis));
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Fetches flow definition metadata from the database
|
|
@@ -335,21 +335,21 @@ class it {
|
|
|
335
335
|
return this.status === t ? Promise.resolve(this) : new Promise((g, c) => {
|
|
336
336
|
let u, l = !1;
|
|
337
337
|
i > 0 && (u = setTimeout(() => {
|
|
338
|
-
l || (l = !0,
|
|
338
|
+
l || (l = !0, T(), c(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${t}'`)));
|
|
339
339
|
}, i));
|
|
340
340
|
let b;
|
|
341
341
|
if (n) {
|
|
342
342
|
const E = () => {
|
|
343
|
-
l || (l = !0, u && clearTimeout(u),
|
|
343
|
+
l || (l = !0, u && clearTimeout(u), T(), c(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${t}'`)));
|
|
344
344
|
};
|
|
345
345
|
n.addEventListener("abort", E), b = () => {
|
|
346
346
|
n.removeEventListener("abort", E);
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
|
-
const
|
|
349
|
+
const T = this.on("*", (E) => {
|
|
350
350
|
if (E.status === t) {
|
|
351
351
|
if (l) return;
|
|
352
|
-
l = !0, u && clearTimeout(u), b && b(),
|
|
352
|
+
l = !0, u && clearTimeout(u), b && b(), T(), g(this);
|
|
353
353
|
}
|
|
354
354
|
});
|
|
355
355
|
});
|
|
@@ -421,7 +421,7 @@ tt = function(t, r) {
|
|
|
421
421
|
const i = e(this, x)[t];
|
|
422
422
|
return e(this, x)[r] > i;
|
|
423
423
|
};
|
|
424
|
-
var a, R,
|
|
424
|
+
var a, R, P, q, U, A, D, B, et;
|
|
425
425
|
class V {
|
|
426
426
|
/**
|
|
427
427
|
* Creates a new FlowRun instance
|
|
@@ -432,7 +432,7 @@ class V {
|
|
|
432
432
|
d(this, D);
|
|
433
433
|
d(this, a);
|
|
434
434
|
d(this, R, L());
|
|
435
|
-
d(this,
|
|
435
|
+
d(this, P, /* @__PURE__ */ new Map());
|
|
436
436
|
d(this, q, {
|
|
437
437
|
[p.Started]: 0,
|
|
438
438
|
[p.Completed]: 1,
|
|
@@ -530,7 +530,7 @@ class V {
|
|
|
530
530
|
* @returns FlowStep instance for the specified step
|
|
531
531
|
*/
|
|
532
532
|
step(t) {
|
|
533
|
-
const r = e(this,
|
|
533
|
+
const r = e(this, P).get(t);
|
|
534
534
|
if (r)
|
|
535
535
|
return r;
|
|
536
536
|
const i = new it({
|
|
@@ -544,7 +544,7 @@ class V {
|
|
|
544
544
|
completed_at: null,
|
|
545
545
|
failed_at: null
|
|
546
546
|
});
|
|
547
|
-
return e(this,
|
|
547
|
+
return e(this, P).set(
|
|
548
548
|
t,
|
|
549
549
|
i
|
|
550
550
|
), i;
|
|
@@ -556,7 +556,7 @@ class V {
|
|
|
556
556
|
* @returns true if the step exists, false otherwise
|
|
557
557
|
*/
|
|
558
558
|
hasStep(t) {
|
|
559
|
-
return e(this,
|
|
559
|
+
return e(this, P).has(t);
|
|
560
560
|
}
|
|
561
561
|
/**
|
|
562
562
|
* Wait for the run to reach a specific status
|
|
@@ -570,7 +570,7 @@ class V {
|
|
|
570
570
|
return this.status === t ? Promise.resolve(this) : new Promise((g, c) => {
|
|
571
571
|
let u, l = !1;
|
|
572
572
|
i > 0 && (u = setTimeout(() => {
|
|
573
|
-
l || (l = !0,
|
|
573
|
+
l || (l = !0, T(), c(
|
|
574
574
|
new Error(
|
|
575
575
|
`Timeout waiting for run ${this.run_id} to reach status '${t}'`
|
|
576
576
|
)
|
|
@@ -579,7 +579,7 @@ class V {
|
|
|
579
579
|
let b;
|
|
580
580
|
if (n) {
|
|
581
581
|
const E = () => {
|
|
582
|
-
l || (l = !0, u && clearTimeout(u),
|
|
582
|
+
l || (l = !0, u && clearTimeout(u), T(), c(
|
|
583
583
|
new Error(
|
|
584
584
|
`Aborted waiting for run ${this.run_id} to reach status '${t}'`
|
|
585
585
|
)
|
|
@@ -589,10 +589,10 @@ class V {
|
|
|
589
589
|
n.removeEventListener("abort", E);
|
|
590
590
|
};
|
|
591
591
|
}
|
|
592
|
-
const
|
|
592
|
+
const T = this.on("*", (E) => {
|
|
593
593
|
if (E.status === t) {
|
|
594
594
|
if (l) return;
|
|
595
|
-
l = !0, u && clearTimeout(u), b && b(),
|
|
595
|
+
l = !0, u && clearTimeout(u), b && b(), T(), g(this);
|
|
596
596
|
}
|
|
597
597
|
});
|
|
598
598
|
});
|
|
@@ -668,10 +668,10 @@ class V {
|
|
|
668
668
|
* Clean up all resources held by this run
|
|
669
669
|
*/
|
|
670
670
|
dispose() {
|
|
671
|
-
e(this, U) || (e(this,
|
|
671
|
+
e(this, U) || (e(this, P).clear(), f(this, R, L()), f(this, A, 0), f(this, U, !0));
|
|
672
672
|
}
|
|
673
673
|
}
|
|
674
|
-
a = new WeakMap(), R = new WeakMap(),
|
|
674
|
+
a = new WeakMap(), R = new WeakMap(), P = new WeakMap(), q = new WeakMap(), U = new WeakMap(), A = new WeakMap(), D = new WeakSet(), /**
|
|
675
675
|
* Checks if auto-dispose should be triggered (when in terminal state with no listeners)
|
|
676
676
|
*/
|
|
677
677
|
B = function() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/lib/types.ts","../src/lib/SupabaseBroadcastAdapter.ts","../src/lib/FlowStep.ts","../src/lib/FlowRun.ts","../src/lib/eventAdapters.ts","../src/lib/PgflowClient.ts"],"sourcesContent":["import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type {\n Json,\n RunRow,\n StepStateRow,\n FlowRow,\n StepRow,\n} from '@pgflow/core';\nimport type { FlowRun } from './FlowRun.js';\n\n/**\n * Flow run status enum\n */\nexport enum FlowRunStatus {\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Flow run event data types - individual event shapes (no circular reference)\n */\nexport type FlowRunEventData<TFlow extends AnyFlow> = {\n started: {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n input: ExtractFlowInput<TFlow>;\n status: FlowRunStatus.Started;\n started_at: string;\n remaining_steps: number;\n };\n completed: {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n output: ExtractFlowOutput<TFlow>;\n status: FlowRunStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n error_message: string;\n status: FlowRunStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all flow run events (no circular reference)\n */\nexport type FlowRunEvent<TFlow extends AnyFlow> =\n FlowRunEventData<TFlow>[keyof FlowRunEventData<TFlow>];\n\n/**\n * Type guard to check if an unknown value is a valid FlowRunEvent\n */\nexport function isFlowRunEvent<TFlow extends AnyFlow>(\n value: unknown\n): value is FlowRunEvent<TFlow> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'flow_slug' in value &&\n !('step_slug' in value) &&\n 'status' in value &&\n (value.status === FlowRunStatus.Started ||\n value.status === FlowRunStatus.Completed ||\n value.status === FlowRunStatus.Failed)\n );\n}\n\n/**\n * Type guard for started events\n */\nexport function isFlowRunStartedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['started'] {\n return event.status === FlowRunStatus.Started;\n}\n\n/**\n * Type guard for completed events\n */\nexport function isFlowRunCompletedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['completed'] {\n return event.status === FlowRunStatus.Completed;\n}\n\n/**\n * Type guard for failed events\n */\nexport function isFlowRunFailedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['failed'] {\n return event.status === FlowRunStatus.Failed;\n}\n\n/**\n * Flow run event types matching nanoevents expectations (wildcard added separately)\n */\nexport type FlowRunEvents<TFlow extends AnyFlow> = {\n [K in keyof FlowRunEventData<TFlow>]: (\n event: FlowRunEventData<TFlow>[K]\n ) => void;\n} & {\n '*': (event: FlowRunEvent<TFlow>) => void;\n};\n\n/**\n * Flow step status enum\n */\nexport enum FlowStepStatus {\n Created = 'created',\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Step event data types (no circular reference)\n */\nexport type StepEventData<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n started: {\n event_type: 'step:started';\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus.Started;\n started_at: string;\n };\n completed: {\n event_type: 'step:completed';\n run_id: string;\n step_slug: TStepSlug;\n output: StepOutput<TFlow, TStepSlug>;\n status: FlowStepStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'step:failed';\n run_id: string;\n step_slug: TStepSlug;\n error_message: string;\n status: FlowStepStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all step events (no circular reference)\n */\nexport type StepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = StepEventData<TFlow, TStepSlug>[keyof StepEventData<TFlow, TStepSlug>];\n\n/**\n * Type guard to check if an unknown value is a valid StepEvent\n */\nexport function isStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(value: unknown): value is StepEvent<TFlow, TStepSlug> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'step_slug' in value &&\n 'status' in value &&\n (value.status === FlowStepStatus.Started ||\n value.status === FlowStepStatus.Completed ||\n value.status === FlowStepStatus.Failed)\n );\n}\n\n/**\n * Type guard for started step events\n */\nexport function isStepStartedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['started'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Started &&\n 'event_type' in event &&\n event.event_type === 'step:started'\n );\n}\n\n/**\n * Type guard for completed step events\n */\nexport function isStepCompletedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['completed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Completed &&\n 'event_type' in event &&\n event.event_type === 'step:completed'\n );\n}\n\n/**\n * Type guard for failed step events\n */\nexport function isStepFailedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['failed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Failed &&\n 'event_type' in event &&\n event.event_type === 'step:failed'\n );\n}\n\n/**\n * Step event types matching nanoevents expectations (wildcard added separately)\n */\nexport type StepEvents<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n [K in keyof StepEventData<TFlow, TStepSlug>]: (\n event: StepEventData<TFlow, TStepSlug>[K]\n ) => void;\n} & {\n '*': (event: StepEvent<TFlow, TStepSlug>) => void;\n};\n\n/**\n * Function returned by event subscriptions to remove the listener\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Broadcast run event types for Supabase realtime\n */\nexport type BroadcastRunStartedEvent = {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Started;\n input: Json;\n started_at: string;\n remaining_steps: number;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunCompletedEvent = {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunFailedEvent = {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Failed;\n error_message: string;\n failed_at: string;\n};\n\nexport type BroadcastRunEvent =\n | BroadcastRunStartedEvent\n | BroadcastRunCompletedEvent\n | BroadcastRunFailedEvent;\n\n/**\n * Broadcast step event types for Supabase realtime\n */\nexport type BroadcastStepStartedEvent = {\n event_type: 'step:started';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Started;\n started_at: string;\n remaining_tasks: number;\n remaining_deps: number;\n error_message?: string; // Adding for type compatibility\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepCompletedEvent = {\n event_type: 'step:completed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastStepFailedEvent = {\n event_type: 'step:failed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Failed;\n error_message: string;\n failed_at: string;\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepEvent =\n | BroadcastStepStartedEvent\n | BroadcastStepCompletedEvent\n | BroadcastStepFailedEvent;\n\n/**\n * Flow run state\n */\nexport type FlowRunState<TFlow extends AnyFlow> = {\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus;\n input: ExtractFlowInput<TFlow>;\n output: ExtractFlowOutput<TFlow> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n remaining_steps: number;\n};\n\n/**\n * Flow step state\n */\nexport type FlowStepState<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus;\n output: StepOutput<TFlow, TStepSlug> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n};\n\n/**\n * Interface for realtime updates (used by client library)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport interface IFlowRealtime<TFlow = unknown> {\n /**\n * Fetch flow definition metadata (looks up flows and steps tables)\n */\n fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }>;\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe;\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe;\n\n /**\n * Subscribe to a flow run's events\n */\n subscribeToRun(run_id: string): Promise<Unsubscribe>;\n\n /**\n * Fetch current state of a run and its steps\n */\n getRunWithStates(\n run_id: string\n ): Promise<{ run: RunRow; steps: StepStateRow[] }>;\n}\n\n/**\n * Generic base interface for flow runs that uses proper event types\n */\nexport interface FlowRunBase<TEvt = unknown> {\n readonly run_id: string;\n updateState(event: TEvt): boolean;\n step(stepSlug: string): FlowStepBase<unknown>;\n hasStep(stepSlug: string): boolean;\n dispose(): void;\n}\n\n/**\n * Generic base interface for flow steps that uses proper event types\n */\nexport interface FlowStepBase<TEvt = unknown> {\n updateState(event: TEvt): boolean;\n}\n\n/**\n * Utility type for broadcast events\n */\nexport type BroadcastEvent = BroadcastRunEvent | BroadcastStepEvent;\n\n/**\n * Composite interface for client\n */\nexport interface IFlowClient<TFlow extends AnyFlow = AnyFlow>\n extends IFlowRealtime<TFlow> {\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>>;\n\n /**\n * Get a flow run by ID\n *\n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n getRun<TSpecificFlow extends TFlow = TFlow>(\n run_id: string\n ): Promise<FlowRun<TSpecificFlow> | null>;\n}\n","import type { RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';\nimport type { FlowRow, StepRow, RunRow, StepStateRow } from '@pgflow/core';\nimport { createNanoEvents } from 'nanoevents';\nimport type {\n IFlowRealtime,\n BroadcastRunEvent,\n BroadcastStepEvent,\n Unsubscribe,\n} from './types.js';\n\n// Define the events interface for the adapter\ninterface AdapterEvents {\n runEvent: (event: BroadcastRunEvent) => void;\n stepEvent: (event: BroadcastStepEvent) => void;\n}\n\n/**\n * Adapter to handle realtime communication with Supabase\n */\nexport class SupabaseBroadcastAdapter implements IFlowRealtime {\n #supabase: SupabaseClient;\n #channels: Map<string, RealtimeChannel> = new Map();\n #emitter = createNanoEvents<AdapterEvents>();\n #reconnectionDelay: number;\n #stabilizationDelay: number;\n #schedule: typeof setTimeout;\n\n\n /**\n * Creates a new instance of SupabaseBroadcastAdapter\n *\n * @param supabase - Supabase client instance\n */\n constructor(\n supabase: SupabaseClient,\n opts: {\n reconnectDelayMs?: number;\n stabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabase;\n this.#reconnectionDelay = opts.reconnectDelayMs ?? 2000;\n this.#stabilizationDelay = opts.stabilizationDelayMs ?? 300;\n this.#schedule = opts.schedule ?? setTimeout;\n }\n \n /**\n * Handle broadcast messages from Supabase\n * @param payload - The message payload\n */\n #handleBroadcastMessage(msg: { \n event: string; \n payload: BroadcastRunEvent | BroadcastStepEvent;\n }): void {\n const { event, payload } = msg;\n \n // run_id is already inside the payload coming from the database trigger\n // so just preserve it without overwriting\n const eventData = payload;\n\n // Auto-parse JSON strings in broadcast data (realtime sends JSONB as strings)\n this.#parseJsonFields(eventData);\n\n if (event.startsWith('run:')) {\n // Handle run events\n this.#emitter.emit('runEvent', eventData as BroadcastRunEvent);\n } else if (event.startsWith('step:')) {\n // Handle step events\n this.#emitter.emit('stepEvent', eventData as BroadcastStepEvent);\n }\n }\n\n /**\n * Parse JSON string fields in broadcast event data\n * @param eventData - The event data object to parse\n */\n #parseJsonFields(eventData: Record<string, unknown>): void {\n // Parse output field if it's a JSON string\n if ('output' in eventData && typeof eventData.output === 'string') {\n try {\n eventData.output = JSON.parse(eventData.output);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n \n // Parse input field if it's a JSON string\n if ('input' in eventData && typeof eventData.input === 'string') {\n try {\n eventData.input = JSON.parse(eventData.input);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n }\n\n \n /**\n * Handle channel errors and reconnection\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @param channel - The RealtimeChannel instance\n * @param error - The error object\n */\n async #handleChannelError(\n run_id: string,\n channelName: string,\n channel: RealtimeChannel,\n error: unknown\n ): Promise<void> {\n console.error(`Channel ${channelName} error:`, error);\n \n // Schedule reconnection attempt\n this.#schedule(async () => {\n if (this.#channels.has(run_id)) {\n await this.#reconnectChannel(run_id, channelName);\n }\n }, this.#reconnectionDelay);\n }\n \n /**\n * Creates and configures a channel for a run\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @returns The configured RealtimeChannel\n */\n #createAndConfigureChannel(run_id: string, channelName: string): RealtimeChannel {\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Note: Lifecycle event listeners (subscribed, closed, error) are handled \n // by the calling code to avoid conflicts when multiple listeners try to \n // handle the same events.\n \n return channel;\n }\n \n /**\n * Reconnect to a channel and refresh state\n * @param run_id - The run ID\n * @param channelName - The channel name\n */\n async #reconnectChannel(\n run_id: string,\n channelName: string\n ): Promise<void> {\n console.log(`Attempting to reconnect to ${channelName}`);\n \n try {\n // Fetch current state to avoid missing events during disconnection\n const currentState = await this.getRunWithStates(run_id);\n \n // Update state based on current data\n this.#refreshStateFromSnapshot(run_id, currentState);\n \n // Create a new channel as the old one can't be reused\n const newChannel = this.#createAndConfigureChannel(run_id, channelName);\n \n // Set up lifecycle event handlers for reconnection\n newChannel.on('system', { event: 'subscribed' }, () => {\n console.log(`Reconnected and subscribed to channel ${channelName}`);\n });\n \n newChannel.on('system', { event: 'closed' }, () => {\n console.log(`Reconnected channel ${channelName} closed`);\n });\n \n newChannel.on('system', { event: 'error' }, (payload) => \n this.#handleChannelError(run_id, channelName, newChannel, payload.error)\n );\n \n // Subscribe and update the channels map\n newChannel.subscribe();\n this.#channels.set(run_id, newChannel);\n } catch (e) {\n console.error(`Failed to reconnect to ${channelName}:`, e);\n }\n }\n \n /**\n * Refresh client state from a state snapshot\n * @param run_id - The run ID\n * @param state - The state snapshot\n */\n #refreshStateFromSnapshot(\n run_id: string,\n state: { run: RunRow; steps: StepStateRow[] } | null\n ): void {\n if (!state || !state.run) return;\n \n // Create proper run event with correct event_type\n const runEvent: BroadcastRunEvent = {\n event_type: `run:${state.run.status}`,\n ...state.run\n } as unknown as BroadcastRunEvent;\n \n // Emit run event\n this.#emitter.emit('runEvent', runEvent);\n \n // Emit events for each step state\n if (state.steps && Array.isArray(state.steps)) {\n for (const step of state.steps) {\n // Create proper step event with correct event_type\n const stepEvent: BroadcastStepEvent = {\n event_type: `step:${step.status}`,\n ...step\n } as unknown as BroadcastStepEvent;\n \n // Emit step event\n this.#emitter.emit('stepEvent', stepEvent);\n }\n }\n }\n\n /**\n * Fetches flow definition metadata from the database\n *\n * @param flow_slug - Flow slug to fetch\n */\n async fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }> {\n // Fetch flow details and steps in parallel\n const [flowResult, stepsResult] = await Promise.all([\n this.#supabase\n .schema('pgflow')\n .from('flows')\n .select('*')\n .eq('flow_slug', flow_slug)\n .single(),\n this.#supabase\n .schema('pgflow')\n .from('steps')\n .select('*')\n .eq('flow_slug', flow_slug)\n .order('step_index', { ascending: true })\n ]);\n\n // Handle flow result\n if (flowResult.error) throw flowResult.error;\n if (!flowResult.data) throw new Error(`Flow \"${flow_slug}\" not found`);\n\n // Handle steps result\n if (stepsResult.error) throw stepsResult.error;\n \n // Ensure steps is always an array, even if it's null or undefined\n const stepsArray = Array.isArray(stepsResult.data) ? stepsResult.data : [];\n\n return {\n flow: flowResult.data as FlowRow,\n steps: stepsArray as StepRow[],\n };\n }\n\n /**\n * Registers a callback for run events\n *\n * @param callback - Function to call when run events are received\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('runEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from run event - emitter may have been disposed', e);\n }\n };\n }\n\n /**\n * Registers a callback for step events\n *\n * @param callback - Function to call when step events are received\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('stepEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from step event - emitter may have been disposed', e);\n }\n };\n }\n\n // Store unsubscribe functions per run ID for reference equality\n #unsubscribeFunctions: Map<string, () => void> = new Map();\n\n /**\n * Subscribes to a flow run's events\n *\n * @param run_id - Run ID to subscribe to\n * @returns Function to unsubscribe\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n const channelName = `pgflow:run:${run_id}`;\n\n // If already subscribed, return the existing unsubscribe function\n if (this.#channels.has(run_id)) {\n const existingUnsubscribe = this.#unsubscribeFunctions.get(run_id);\n if (existingUnsubscribe) {\n return existingUnsubscribe;\n }\n // If channel exists but no unsubscribe function, something went wrong\n // Let's clean up and recreate\n this.#unsubscribe(run_id);\n }\n\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Set up error handling\n channel.on('system', { event: 'closed' }, () => {\n console.log(`Channel ${channelName} closed`);\n });\n channel.on('system', { event: 'error' }, (payload) => {\n console.log(`Channel ${channelName} error:`, payload);\n this.#handleChannelError(run_id, channelName, channel, payload.error);\n });\n \n // Subscribe to channel and wait for confirmation (like the working realtime-send test)\n console.log(`Subscribing to channel ${channelName}...`);\n \n const subscriptionPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Subscription timeout for channel ${channelName}`));\n }, 20000); // Increased from 5s to 20s for slower CI environments\n \n channel.subscribe((status) => {\n console.log(`Channel ${channelName} subscription status:`, status);\n if (status === 'SUBSCRIBED') {\n clearTimeout(timeout);\n resolve();\n }\n // Don't reject on CHANNEL_ERROR - it's a transient state\n // Only reject on timeout\n });\n });\n \n // Wait for the 'SUBSCRIBED' acknowledgment to avoid race conditions\n await subscriptionPromise;\n\n // Stabilization delay - known Supabase Realtime limitation\n // The SUBSCRIBED event is emitted before backend routing is fully established.\n // This delay ensures the backend can receive messages sent immediately after subscription.\n // See: https://github.com/supabase/supabase-js/issues/1599\n await new Promise(resolve => this.#schedule(resolve, this.#stabilizationDelay));\n\n this.#channels.set(run_id, channel);\n\n const unsubscribe = () => this.unsubscribe(run_id);\n this.#unsubscribeFunctions.set(run_id, unsubscribe);\n return unsubscribe;\n }\n \n /**\n * Unsubscribes from a run's events\n * \n * @param run_id - Run ID to unsubscribe from\n */\n unsubscribe(run_id: string): void {\n this.#unsubscribe(run_id);\n }\n\n /**\n * Fetches current state of a run and its steps\n *\n * @param run_id - Run ID to fetch\n */\n async getRunWithStates(run_id: string): Promise<{\n run: RunRow;\n steps: StepStateRow[];\n }> {\n // Call the RPC function which returns a JSONB object\n const { data, error } = await this.#supabase\n .schema('pgflow')\n .rpc('get_run_with_states', { run_id });\n\n if (error) throw error;\n if (!data) throw new Error(`No data returned for run ${run_id}`);\n \n return data as { run: RunRow; steps: StepStateRow[] };\n }\n\n /**\n * Unsubscribes from a run's events\n *\n * @param run_id - Run ID to unsubscribe from\n */\n #unsubscribe(run_id: string): void {\n const channel = this.#channels.get(run_id);\n if (channel) {\n // Close the channel\n channel.unsubscribe();\n this.#channels.delete(run_id);\n \n // Also clean up the unsubscribe function reference\n this.#unsubscribeFunctions.delete(run_id);\n \n // We don't need to explicitly remove event listeners from the emitter\n // as they will be garbage collected when no longer referenced.\n // The event listeners are bound to specific callbacks provided by the client,\n // which will retain references if they're still in use.\n }\n }\n}\n","import { createNanoEvents } from 'nanoevents';\nimport type { AnyFlow, ExtractFlowSteps, StepOutput } from '@pgflow/dsl';\nimport { FlowStepStatus } from './types.js';\nimport type { \n FlowStepState, \n StepEvents, \n Unsubscribe, \n FlowStepBase,\n StepEvent\n} from './types.js';\n\n/**\n * Represents a single step in a flow run\n */\nexport class FlowStep<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> implements FlowStepBase<StepEvent<TFlow, TStepSlug>> {\n #state: FlowStepState<TFlow, TStepSlug>;\n #events = createNanoEvents<StepEvents<TFlow, TStepSlug>>();\n #statusPrecedence: Record<FlowStepStatus, number> = {\n [FlowStepStatus.Created]: 0,\n [FlowStepStatus.Started]: 1,\n [FlowStepStatus.Completed]: 2,\n [FlowStepStatus.Failed]: 3,\n };\n\n /**\n * Creates a new FlowStep instance\n * \n * @param initialState - Initial state for the step\n */\n constructor(initialState: FlowStepState<TFlow, TStepSlug>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID this step belongs to\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the step slug\n */\n get step_slug(): TStepSlug {\n return this.#state.step_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowStepStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the step output\n */\n get output(): StepOutput<TFlow, TStepSlug> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Register an event handler for a step event\n * \n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof StepEvents<TFlow, TStepSlug>>(\n event: E,\n callback: StepEvents<TFlow, TStepSlug>[E]\n ): Unsubscribe {\n return this.#events.on(event, callback);\n }\n\n /**\n * Wait for the step to reach a specific status\n * \n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the step instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowStepStatus.Started | FlowStepStatus.Completed | FlowStepStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n \n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n }, timeoutMs);\n }\n \n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n };\n \n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n \n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').StepStateRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowStepStatus;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.error_message = row.error_message;\n this.#state.error = row.error_message ? new Error(row.error_message) : null;\n // Note: output is not stored in step_states table, remains null\n }\n\n /**\n * Updates the step state based on an event\n *\n * @internal This method is only intended for use by FlowRun and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: StepEvent<TFlow, TStepSlug>): boolean {\n // Validate event is for this step\n if (event.step_slug !== this.#state.step_slug) {\n return false;\n }\n \n // Validate event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n \n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowStepStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Started,\n started_at: typeof event.started_at === 'string' ? new Date(event.started_at) : new Date(),\n };\n this.#events.emit('started', event);\n break;\n\n case FlowStepStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Completed,\n completed_at: typeof event.completed_at === 'string' ? new Date(event.completed_at) : new Date(),\n output: event.output as StepOutput<TFlow, TStepSlug>,\n };\n this.#events.emit('completed', event);\n break;\n\n case FlowStepStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Failed,\n failed_at: typeof event.failed_at === 'string' ? new Date(event.failed_at) : new Date(),\n error_message: typeof event.error_message === 'string' ? event.error_message : 'Unknown error',\n error: new Error(typeof event.error_message === 'string' ? event.error_message : 'Unknown error'),\n };\n this.#events.emit('failed', event);\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n \n return true;\n }\n\n /**\n * Determines if a status should be updated based on precedence\n * \n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(currentStatus: FlowStepStatus, newStatus: FlowStepStatus): boolean {\n // Don't allow changes to terminal states\n if (currentStatus === FlowStepStatus.Completed || currentStatus === FlowStepStatus.Failed) {\n return false; // Terminal states should never change\n }\n \n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n}","import { createNanoEvents } from 'nanoevents';\nimport type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n} from '@pgflow/dsl';\nimport { FlowRunStatus, FlowStepStatus } from './types.js';\nimport type {\n FlowRunState,\n FlowRunEvents,\n Unsubscribe,\n FlowRunBase,\n FlowStepBase,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\nimport { FlowStep } from './FlowStep.js';\n\n/**\n * Represents a single execution of a flow\n */\nexport class FlowRun<TFlow extends AnyFlow>\n implements FlowRunBase<FlowRunEvent<TFlow>>\n{\n #state: FlowRunState<TFlow>;\n #events = createNanoEvents<FlowRunEvents<TFlow>>();\n #steps = new Map<string, FlowStepBase>();\n #statusPrecedence: Record<FlowRunStatus, number> = {\n [FlowRunStatus.Started]: 0,\n [FlowRunStatus.Completed]: 1,\n [FlowRunStatus.Failed]: 2,\n };\n #disposed = false;\n\n /**\n * Creates a new FlowRun instance\n *\n * @param initialState - Initial state for the run\n */\n constructor(initialState: FlowRunState<TFlow>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the flow slug\n */\n get flow_slug(): string {\n return this.#state.flow_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowRunStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the flow input\n */\n get input(): ExtractFlowInput<TFlow> {\n return this.#state.input;\n }\n\n /**\n * Get the flow output\n */\n get output(): ExtractFlowOutput<TFlow> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Get the number of remaining steps\n */\n get remaining_steps(): number {\n return this.#state.remaining_steps;\n }\n\n /**\n * Register an event handler for a run event\n *\n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof FlowRunEvents<TFlow>>(\n event: E,\n callback: FlowRunEvents<TFlow>[E]\n ): Unsubscribe {\n this.#listenerCount++;\n\n // Wrap the unsubscribe function to track listener count\n const unsubscribe = this.#events.on(event, callback);\n\n return () => {\n unsubscribe();\n this.#listenerCount--;\n this.#checkAutoDispose();\n };\n }\n\n /**\n * Get a FlowStep instance for a specific step\n *\n * @param stepSlug - Step slug to get\n * @returns FlowStep instance for the specified step\n */\n step<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug\n ): FlowStep<TFlow, TStepSlug> {\n // Look up if we already have this step cached\n const existingStep = this.#steps.get(stepSlug as string);\n if (existingStep) {\n // Safe to cast since we only store steps with matching slugs\n return existingStep as unknown as FlowStep<TFlow, TStepSlug>;\n }\n\n // Create a new step instance with default state\n const step = new FlowStep<TFlow, TStepSlug>({\n run_id: this.run_id,\n step_slug: stepSlug,\n status: FlowStepStatus.Created,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n });\n\n // Cache the step\n this.#steps.set(\n stepSlug as string,\n step as FlowStepBase<StepEvent<TFlow, TStepSlug>>\n );\n\n return step;\n }\n\n /**\n * Check if this run has a specific step\n *\n * @param stepSlug - Step slug to check\n * @returns true if the step exists, false otherwise\n */\n hasStep(stepSlug: string): boolean {\n // Check if we have this step cached\n return this.#steps.has(stepSlug);\n }\n\n /**\n * Wait for the run to reach a specific status\n *\n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the run instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowRunStatus.Completed | FlowRunStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n\n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(\n new Error(\n `Timeout waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n }, timeoutMs);\n }\n\n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(\n new Error(\n `Aborted waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n };\n\n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n\n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').RunRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowRunStatus;\n this.#state.input = row.input as ExtractFlowInput<TFlow>;\n this.#state.output = row.output as ExtractFlowOutput<TFlow> | null;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.remaining_steps = row.remaining_steps;\n this.#state.error_message = null; // Database doesn't have error_message for runs\n this.#state.error = null;\n }\n\n /**\n * Updates the run state based on an event\n *\n * @internal This method is only intended for use by PgflowClient and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: FlowRunEvent<TFlow>): boolean {\n // Validate the event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n\n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowRunStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Started,\n started_at:\n typeof event.started_at === 'string'\n ? new Date(event.started_at)\n : new Date(),\n remaining_steps:\n 'remaining_steps' in event\n ? Number(event.remaining_steps)\n : this.#state.remaining_steps,\n };\n this.#events.emit('started', event);\n break;\n\n case FlowRunStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Completed,\n completed_at:\n typeof event.completed_at === 'string'\n ? new Date(event.completed_at)\n : new Date(),\n output: event.output as ExtractFlowOutput<TFlow>,\n remaining_steps: 0,\n };\n this.#events.emit('completed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n case FlowRunStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Failed,\n failed_at:\n typeof event.failed_at === 'string'\n ? new Date(event.failed_at)\n : new Date(),\n error_message:\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error',\n error: new Error(\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error'\n ),\n };\n this.#events.emit('failed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n\n return true;\n }\n\n /**\n * Updates a step state based on an event\n *\n * @param stepSlug - Step slug to update\n * @param event - Event data to update the step with\n * @returns true if the state was updated, false otherwise\n */\n updateStepState<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug,\n event: StepEvent<TFlow, TStepSlug>\n ): boolean {\n const step = this.step(stepSlug);\n return step.updateState(event);\n }\n\n // Track number of listeners\n #listenerCount = 0;\n\n /**\n * Checks if auto-dispose should be triggered (when in terminal state with no listeners)\n */\n #checkAutoDispose(): void {\n // Don't auto-dispose multiple times\n if (this.#disposed) {\n return;\n }\n\n // Only auto-dispose in terminal states\n if (\n this.status !== FlowRunStatus.Completed &&\n this.status !== FlowRunStatus.Failed\n ) {\n return;\n }\n\n // If there are no listeners, auto-dispose\n if (this.#listenerCount === 0) {\n this.dispose();\n }\n }\n\n /**\n * Determines if a status should be updated based on precedence\n *\n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(\n currentStatus: FlowRunStatus,\n newStatus: FlowRunStatus\n ): boolean {\n // Don't allow changes to terminal states\n if (\n currentStatus === FlowRunStatus.Completed ||\n currentStatus === FlowRunStatus.Failed\n ) {\n return false; // Terminal states should never change\n }\n\n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n\n /**\n * Clean up all resources held by this run\n */\n dispose(): void {\n if (this.#disposed) {\n return;\n }\n\n // Clear the map to allow garbage collection of steps\n this.#steps.clear();\n\n // Create a new events object - this effectively clears all listeners\n // without accessing the private internals of nanoevents\n this.#events = createNanoEvents<FlowRunEvents<TFlow>>();\n this.#listenerCount = 0;\n\n // Mark as disposed\n this.#disposed = true;\n }\n}\n","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type { RunRow, StepStateRow } from '@pgflow/core';\nimport {\n FlowStepStatus,\n FlowRunStatus,\n} from './types.js';\nimport type {\n BroadcastRunEvent,\n BroadcastStepEvent,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\n\n/**\n * Convert a broadcast run event to a typed run event\n */\nexport function toTypedRunEvent<TFlow extends AnyFlow>(\n evt: BroadcastRunEvent\n): FlowRunEvent<TFlow> {\n switch (evt.status) {\n case FlowRunStatus.Started:\n return {\n event_type: 'run:started',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Started,\n started_at: evt.started_at,\n remaining_steps: evt.remaining_steps,\n input: evt.input as ExtractFlowInput<TFlow>,\n };\n case FlowRunStatus.Completed:\n return {\n event_type: 'run:completed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as ExtractFlowOutput<TFlow>,\n };\n case FlowRunStatus.Failed:\n return {\n event_type: 'run:failed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a broadcast step event to a typed step event\n */\nexport function toTypedStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(evt: BroadcastStepEvent): StepEvent<TFlow, TStepSlug> {\n switch (evt.status) {\n case FlowStepStatus.Started:\n return {\n event_type: 'step:started',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: evt.started_at,\n };\n case FlowStepStatus.Completed:\n return {\n event_type: 'step:completed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as StepOutput<TFlow, TStepSlug>,\n };\n case FlowStepStatus.Failed:\n return {\n event_type: 'step:failed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a database run row to a typed run event\n */\nexport function runRowToTypedEvent<TFlow extends AnyFlow>(\n row: RunRow\n): FlowRunEvent<TFlow> {\n switch (row.status) {\n case 'started':\n return {\n event_type: 'run:started',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Started,\n started_at: row.started_at!,\n remaining_steps: row.remaining_steps,\n input: row.input as ExtractFlowInput<TFlow>,\n };\n case 'completed':\n return {\n event_type: 'run:completed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: row.completed_at!,\n output: row.output as ExtractFlowOutput<TFlow>,\n };\n case 'failed':\n return {\n event_type: 'run:failed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: row.failed_at!,\n error_message: 'Flow failed', // Database doesn't have error_message for runs\n };\n default:\n throw new Error(`Unknown run status: ${row.status}`);\n }\n}\n\n/**\n * Convert a database step state row to a typed step event\n */\nexport function stepStateRowToTypedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(row: StepStateRow): StepEvent<TFlow, TStepSlug> {\n switch (row.status) {\n case 'created':\n case 'started':\n return {\n event_type: 'step:started',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: row.started_at!,\n };\n case 'completed':\n return {\n event_type: 'step:completed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: row.completed_at!,\n output: {} as StepOutput<TFlow, TStepSlug>, // Database doesn't have output in step_states\n };\n case 'failed':\n return {\n event_type: 'step:failed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: row.failed_at!,\n error_message: row.error_message || 'Step failed',\n };\n default:\n throw new Error(`Unknown step status: ${row.status}`);\n }\n}","import { v4 as uuidv4 } from 'uuid';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';\nimport { FlowRunStatus } from './types.js';\nimport type { \n IFlowClient, \n FlowRunState, \n BroadcastRunEvent, \n BroadcastStepEvent, \n Unsubscribe, \n FlowRunBase\n} from './types.js';\nimport { SupabaseBroadcastAdapter } from './SupabaseBroadcastAdapter.js';\nimport { FlowRun } from './FlowRun.js';\nimport { toTypedRunEvent, toTypedStepEvent } from './eventAdapters.js';\n\n/**\n * Client for interacting with pgflow\n */\nexport class PgflowClient<TFlow extends AnyFlow = AnyFlow> implements IFlowClient<TFlow> {\n #supabase: SupabaseClient;\n #realtimeAdapter: SupabaseBroadcastAdapter;\n // Use the widest event type - keeps the compiler happy but\n // still provides the structural API we need (updateState/step/...)\n #runs = new Map<string, FlowRunBase<unknown>>();\n\n /**\n * Creates a new PgflowClient instance\n *\n * @param supabaseClient - Supabase client instance\n * @param opts - Optional configuration\n */\n constructor(\n supabaseClient: SupabaseClient,\n opts: {\n realtimeStabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabaseClient;\n this.#realtimeAdapter = new SupabaseBroadcastAdapter(supabaseClient, {\n stabilizationDelayMs: opts.realtimeStabilizationDelayMs,\n schedule: opts.schedule,\n });\n\n // Set up global event listeners - properly typed\n this.#realtimeAdapter.onRunEvent((event: BroadcastRunEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Convert broadcast event to typed event before updating state\n run.updateState(toTypedRunEvent(event));\n }\n });\n\n this.#realtimeAdapter.onStepEvent((event: BroadcastStepEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Always materialize the step before updating to avoid event loss\n // This ensures we cache all steps even if they were never explicitly requested\n const stepSlug = event.step_slug;\n run.step(stepSlug).updateState(toTypedStepEvent(event));\n }\n });\n }\n\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n async startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>> {\n // Generate a run_id if not provided\n const id = run_id || uuidv4();\n\n // Create initial state for the flow run\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: id,\n flow_slug,\n status: FlowRunStatus.Started,\n input: input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: -1, // Use -1 to indicate unknown until first snapshot arrives\n };\n\n // Create the flow run instance\n const run = new FlowRun<TSpecificFlow>(initialState);\n\n // Store the run\n this.#runs.set(id, run);\n\n // Set up subscription for run and step events (wait for subscription confirmation)\n await this.#realtimeAdapter.subscribeToRun(id);\n\n // Start the flow with the predetermined run_id (only after subscription is ready)\n const { data, error } = await this.#supabase.schema('pgflow').rpc('start_flow_with_states', {\n flow_slug: flow_slug,\n input: input as Record<string, unknown>,\n run_id: id\n });\n\n if (error) {\n // Clean up subscription and run instance\n this.dispose(id);\n throw error;\n }\n\n // Apply the run state snapshot (no events)\n if (data.run) {\n run.applySnapshot(data.run);\n }\n\n // Apply step state snapshots (no events)\n if (data.steps && Array.isArray(data.steps)) {\n for (const stepState of data.steps) {\n run.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n\n return run;\n }\n\n /**\n * Dispose a specific flow run\n *\n * @param runId - Run ID to dispose\n */\n dispose(runId: string): void {\n const run = this.#runs.get(runId);\n if (run) {\n // First unsubscribe from the realtime adapter\n this.#realtimeAdapter.unsubscribe(runId);\n \n // Then dispose the run\n run.dispose();\n \n // Finally remove from the runs map\n this.#runs.delete(runId);\n }\n }\n\n /**\n * Dispose all flow runs\n */\n disposeAll(): void {\n for (const runId of this.#runs.keys()) {\n this.dispose(runId);\n }\n }\n\n // Delegate IFlowRealtime methods to the adapter\n\n /**\n * Fetch flow definition metadata\n */\n async fetchFlowDefinition(flow_slug: string) {\n return this.#realtimeAdapter.fetchFlowDefinition(flow_slug);\n }\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onRunEvent(callback);\n }\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onStepEvent(callback);\n }\n\n /**\n * Subscribe to a flow run's events\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n return await this.#realtimeAdapter.subscribeToRun(run_id);\n }\n\n /**\n * Fetch current state of a run and its steps\n */\n async getRunWithStates(run_id: string) {\n return this.#realtimeAdapter.getRunWithStates(run_id);\n }\n \n /**\n * Get a flow run by ID\n * \n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n async getRun<TSpecificFlow extends TFlow = TFlow>(run_id: string): Promise<FlowRun<TSpecificFlow> | null> {\n // Check if we already have this run cached\n const existingRun = this.#runs.get(run_id);\n if (existingRun) {\n return existingRun as FlowRun<TSpecificFlow>;\n }\n \n try {\n // Fetch the run state from the database\n const { run, steps } = await this.getRunWithStates(run_id);\n \n if (!run) {\n return null;\n }\n \n // Validate required fields\n if (!run.run_id || !run.flow_slug || !run.status) {\n throw new Error('Invalid run data: missing required fields');\n }\n\n // Validate status is a valid FlowRunStatus\n const validStatuses = Object.values(FlowRunStatus);\n if (!validStatuses.includes(run.status as FlowRunStatus)) {\n throw new Error(`Invalid run data: invalid status '${run.status}'`);\n }\n\n // Create flow run with minimal initial state\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: run.run_id,\n flow_slug: run.flow_slug,\n status: run.status as FlowRunStatus,\n input: run.input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: 0,\n };\n\n // Create the flow run instance\n const flowRun = new FlowRun<TSpecificFlow>(initialState);\n\n // Apply the complete state from database snapshot\n flowRun.applySnapshot(run);\n \n // Store the run\n this.#runs.set(run_id, flowRun);\n \n // Set up subscription for run and step events\n await this.#realtimeAdapter.subscribeToRun(run_id);\n \n // Initialize steps from snapshot\n if (steps && Array.isArray(steps)) {\n for (const stepState of steps) {\n // Validate step has required fields\n if (!stepState.step_slug || !stepState.status) {\n throw new Error('Invalid step data: missing required fields');\n }\n\n // Apply snapshot state directly (no events)\n flowRun.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n \n return flowRun;\n } catch (error) {\n console.error('Error getting run:', error);\n // Re-throw if it's a validation error\n if (error instanceof Error && (error.message.includes('Invalid run data') || error.message.includes('Invalid step data'))) {\n throw error;\n }\n return null;\n }\n }\n \n}\n"],"names":["FlowRunStatus","isFlowRunEvent","value","isFlowRunStartedEvent","event","isFlowRunCompletedEvent","isFlowRunFailedEvent","FlowStepStatus","isStepEvent","isStepStartedEvent","isStepCompletedEvent","isStepFailedEvent","SupabaseBroadcastAdapter","supabase","opts","__privateAdd","_SupabaseBroadcastAdapter_instances","_supabase","_channels","_emitter","createNanoEvents","_reconnectionDelay","_stabilizationDelay","_schedule","_unsubscribeFunctions","__privateSet","flow_slug","flowResult","stepsResult","__privateGet","stepsArray","callback","unsubscribe","e","run_id","channelName","existingUnsubscribe","__privateMethod","unsubscribe_fn","channel","handleBroadcastMessage_fn","payload","handleChannelError_fn","resolve","reject","timeout","status","data","error","msg","eventData","parseJsonFields_fn","reconnectChannel_fn","createAndConfigureChannel_fn","currentState","refreshStateFromSnapshot_fn","newChannel","state","runEvent","step","stepEvent","FlowStep","initialState","_FlowStep_instances","_state","_events","_statusPrecedence","targetStatus","options","timeoutMs","signal","timeoutId","cleanedUp","unbind","abortCleanup","abortHandler","row","shouldUpdateStatus_fn","currentStatus","newStatus","currentPrecedence","FlowRun","_FlowRun_instances","_steps","_disposed","_listenerCount","__privateWrapper","checkAutoDispose_fn","stepSlug","existingStep","toTypedRunEvent","evt","toTypedStepEvent","PgflowClient","supabaseClient","_realtimeAdapter","_runs","run","input","id","uuidv4","stepState","runId","existingRun","steps","flowRun"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/lib/types.ts","../src/lib/SupabaseBroadcastAdapter.ts","../src/lib/FlowStep.ts","../src/lib/FlowRun.ts","../src/lib/eventAdapters.ts","../src/lib/PgflowClient.ts"],"sourcesContent":["import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type {\n Json,\n RunRow,\n StepStateRow,\n FlowRow,\n StepRow,\n} from '@pgflow/core';\nimport type { FlowRun } from './FlowRun.js';\n\n/**\n * Flow run status enum\n */\nexport enum FlowRunStatus {\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Flow run event data types - individual event shapes (no circular reference)\n */\nexport type FlowRunEventData<TFlow extends AnyFlow> = {\n started: {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n input: ExtractFlowInput<TFlow>;\n status: FlowRunStatus.Started;\n started_at: string;\n remaining_steps: number;\n };\n completed: {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n output: ExtractFlowOutput<TFlow>;\n status: FlowRunStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n error_message: string;\n status: FlowRunStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all flow run events (no circular reference)\n */\nexport type FlowRunEvent<TFlow extends AnyFlow> =\n FlowRunEventData<TFlow>[keyof FlowRunEventData<TFlow>];\n\n/**\n * Type guard to check if an unknown value is a valid FlowRunEvent\n */\nexport function isFlowRunEvent<TFlow extends AnyFlow>(\n value: unknown\n): value is FlowRunEvent<TFlow> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'flow_slug' in value &&\n !('step_slug' in value) &&\n 'status' in value &&\n (value.status === FlowRunStatus.Started ||\n value.status === FlowRunStatus.Completed ||\n value.status === FlowRunStatus.Failed)\n );\n}\n\n/**\n * Type guard for started events\n */\nexport function isFlowRunStartedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['started'] {\n return event.status === FlowRunStatus.Started;\n}\n\n/**\n * Type guard for completed events\n */\nexport function isFlowRunCompletedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['completed'] {\n return event.status === FlowRunStatus.Completed;\n}\n\n/**\n * Type guard for failed events\n */\nexport function isFlowRunFailedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['failed'] {\n return event.status === FlowRunStatus.Failed;\n}\n\n/**\n * Flow run event types matching nanoevents expectations (wildcard added separately)\n */\nexport type FlowRunEvents<TFlow extends AnyFlow> = {\n [K in keyof FlowRunEventData<TFlow>]: (\n event: FlowRunEventData<TFlow>[K]\n ) => void;\n} & {\n '*': (event: FlowRunEvent<TFlow>) => void;\n};\n\n/**\n * Flow step status enum\n */\nexport enum FlowStepStatus {\n Created = 'created',\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Step event data types (no circular reference)\n */\nexport type StepEventData<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n started: {\n event_type: 'step:started';\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus.Started;\n started_at: string;\n };\n completed: {\n event_type: 'step:completed';\n run_id: string;\n step_slug: TStepSlug;\n output: StepOutput<TFlow, TStepSlug>;\n status: FlowStepStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'step:failed';\n run_id: string;\n step_slug: TStepSlug;\n error_message: string;\n status: FlowStepStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all step events (no circular reference)\n */\nexport type StepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = StepEventData<TFlow, TStepSlug>[keyof StepEventData<TFlow, TStepSlug>];\n\n/**\n * Type guard to check if an unknown value is a valid StepEvent\n */\nexport function isStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(value: unknown): value is StepEvent<TFlow, TStepSlug> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'step_slug' in value &&\n 'status' in value &&\n (value.status === FlowStepStatus.Started ||\n value.status === FlowStepStatus.Completed ||\n value.status === FlowStepStatus.Failed)\n );\n}\n\n/**\n * Type guard for started step events\n */\nexport function isStepStartedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['started'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Started &&\n 'event_type' in event &&\n event.event_type === 'step:started'\n );\n}\n\n/**\n * Type guard for completed step events\n */\nexport function isStepCompletedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['completed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Completed &&\n 'event_type' in event &&\n event.event_type === 'step:completed'\n );\n}\n\n/**\n * Type guard for failed step events\n */\nexport function isStepFailedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['failed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Failed &&\n 'event_type' in event &&\n event.event_type === 'step:failed'\n );\n}\n\n/**\n * Step event types matching nanoevents expectations (wildcard added separately)\n */\nexport type StepEvents<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n [K in keyof StepEventData<TFlow, TStepSlug>]: (\n event: StepEventData<TFlow, TStepSlug>[K]\n ) => void;\n} & {\n '*': (event: StepEvent<TFlow, TStepSlug>) => void;\n};\n\n/**\n * Function returned by event subscriptions to remove the listener\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Broadcast run event types for Supabase realtime\n */\nexport type BroadcastRunStartedEvent = {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Started;\n input: Json;\n started_at: string;\n remaining_steps: number;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunCompletedEvent = {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunFailedEvent = {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Failed;\n error_message: string;\n failed_at: string;\n};\n\nexport type BroadcastRunEvent =\n | BroadcastRunStartedEvent\n | BroadcastRunCompletedEvent\n | BroadcastRunFailedEvent;\n\n/**\n * Broadcast step event types for Supabase realtime\n */\nexport type BroadcastStepStartedEvent = {\n event_type: 'step:started';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Started;\n started_at: string;\n remaining_tasks: number;\n remaining_deps: number;\n error_message?: string; // Adding for type compatibility\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepCompletedEvent = {\n event_type: 'step:completed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastStepFailedEvent = {\n event_type: 'step:failed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Failed;\n error_message: string;\n failed_at: string;\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepEvent =\n | BroadcastStepStartedEvent\n | BroadcastStepCompletedEvent\n | BroadcastStepFailedEvent;\n\n/**\n * Flow run state\n */\nexport type FlowRunState<TFlow extends AnyFlow> = {\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus;\n input: ExtractFlowInput<TFlow>;\n output: ExtractFlowOutput<TFlow> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n remaining_steps: number;\n};\n\n/**\n * Flow step state\n */\nexport type FlowStepState<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus;\n output: StepOutput<TFlow, TStepSlug> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n};\n\n/**\n * Interface for realtime updates (used by client library)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport interface IFlowRealtime<TFlow = unknown> {\n /**\n * Fetch flow definition metadata (looks up flows and steps tables)\n */\n fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }>;\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe;\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe;\n\n /**\n * Subscribe to a flow run's events\n */\n subscribeToRun(run_id: string): Promise<Unsubscribe>;\n\n /**\n * Fetch current state of a run and its steps\n */\n getRunWithStates(\n run_id: string\n ): Promise<{ run: RunRow; steps: StepStateRow[] }>;\n}\n\n/**\n * Generic base interface for flow runs that uses proper event types\n */\nexport interface FlowRunBase<TEvt = unknown> {\n readonly run_id: string;\n updateState(event: TEvt): boolean;\n step(stepSlug: string): FlowStepBase<unknown>;\n hasStep(stepSlug: string): boolean;\n dispose(): void;\n}\n\n/**\n * Generic base interface for flow steps that uses proper event types\n */\nexport interface FlowStepBase<TEvt = unknown> {\n updateState(event: TEvt): boolean;\n}\n\n/**\n * Utility type for broadcast events\n */\nexport type BroadcastEvent = BroadcastRunEvent | BroadcastStepEvent;\n\n/**\n * Composite interface for client\n */\nexport interface IFlowClient<TFlow extends AnyFlow = AnyFlow>\n extends IFlowRealtime<TFlow> {\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>>;\n\n /**\n * Get a flow run by ID\n *\n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n getRun<TSpecificFlow extends TFlow = TFlow>(\n run_id: string\n ): Promise<FlowRun<TSpecificFlow> | null>;\n}\n","import type { RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';\nimport type { FlowRow, StepRow, RunRow, StepStateRow } from '@pgflow/core';\nimport { createNanoEvents } from 'nanoevents';\nimport type {\n IFlowRealtime,\n BroadcastRunEvent,\n BroadcastStepEvent,\n Unsubscribe,\n} from './types.js';\n\n// Define the events interface for the adapter\ninterface AdapterEvents {\n runEvent: (event: BroadcastRunEvent) => void;\n stepEvent: (event: BroadcastStepEvent) => void;\n}\n\n/**\n * Adapter to handle realtime communication with Supabase\n */\nexport class SupabaseBroadcastAdapter implements IFlowRealtime {\n #supabase: SupabaseClient;\n #channels: Map<string, RealtimeChannel> = new Map();\n #emitter = createNanoEvents<AdapterEvents>();\n #reconnectionDelay: number;\n #stabilizationDelay: number;\n #schedule: typeof setTimeout;\n\n\n /**\n * Creates a new instance of SupabaseBroadcastAdapter\n *\n * @param supabase - Supabase client instance\n */\n constructor(\n supabase: SupabaseClient,\n opts: {\n reconnectDelayMs?: number;\n stabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabase;\n this.#reconnectionDelay = opts.reconnectDelayMs ?? 2000;\n this.#stabilizationDelay = opts.stabilizationDelayMs ?? 300;\n this.#schedule = opts.schedule ?? setTimeout.bind(globalThis);\n }\n \n /**\n * Handle broadcast messages from Supabase\n * @param payload - The message payload\n */\n #handleBroadcastMessage(msg: { \n event: string; \n payload: BroadcastRunEvent | BroadcastStepEvent;\n }): void {\n const { event, payload } = msg;\n \n // run_id is already inside the payload coming from the database trigger\n // so just preserve it without overwriting\n const eventData = payload;\n\n // Auto-parse JSON strings in broadcast data (realtime sends JSONB as strings)\n this.#parseJsonFields(eventData);\n\n if (event.startsWith('run:')) {\n // Handle run events\n this.#emitter.emit('runEvent', eventData as BroadcastRunEvent);\n } else if (event.startsWith('step:')) {\n // Handle step events\n this.#emitter.emit('stepEvent', eventData as BroadcastStepEvent);\n }\n }\n\n /**\n * Parse JSON string fields in broadcast event data\n * @param eventData - The event data object to parse\n */\n #parseJsonFields(eventData: Record<string, unknown>): void {\n // Parse output field if it's a JSON string\n if ('output' in eventData && typeof eventData.output === 'string') {\n try {\n eventData.output = JSON.parse(eventData.output);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n \n // Parse input field if it's a JSON string\n if ('input' in eventData && typeof eventData.input === 'string') {\n try {\n eventData.input = JSON.parse(eventData.input);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n }\n\n \n /**\n * Handle channel errors and reconnection\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @param channel - The RealtimeChannel instance\n * @param error - The error object\n */\n async #handleChannelError(\n run_id: string,\n channelName: string,\n channel: RealtimeChannel,\n error: unknown\n ): Promise<void> {\n console.error(`Channel ${channelName} error:`, error);\n \n // Schedule reconnection attempt\n this.#schedule(async () => {\n if (this.#channels.has(run_id)) {\n await this.#reconnectChannel(run_id, channelName);\n }\n }, this.#reconnectionDelay);\n }\n \n /**\n * Creates and configures a channel for a run\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @returns The configured RealtimeChannel\n */\n #createAndConfigureChannel(run_id: string, channelName: string): RealtimeChannel {\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Note: Lifecycle event listeners (subscribed, closed, error) are handled \n // by the calling code to avoid conflicts when multiple listeners try to \n // handle the same events.\n \n return channel;\n }\n \n /**\n * Reconnect to a channel and refresh state\n * @param run_id - The run ID\n * @param channelName - The channel name\n */\n async #reconnectChannel(\n run_id: string,\n channelName: string\n ): Promise<void> {\n console.log(`Attempting to reconnect to ${channelName}`);\n \n try {\n // Fetch current state to avoid missing events during disconnection\n const currentState = await this.getRunWithStates(run_id);\n \n // Update state based on current data\n this.#refreshStateFromSnapshot(run_id, currentState);\n \n // Create a new channel as the old one can't be reused\n const newChannel = this.#createAndConfigureChannel(run_id, channelName);\n \n // Set up lifecycle event handlers for reconnection\n newChannel.on('system', { event: 'subscribed' }, () => {\n console.log(`Reconnected and subscribed to channel ${channelName}`);\n });\n \n newChannel.on('system', { event: 'closed' }, () => {\n console.log(`Reconnected channel ${channelName} closed`);\n });\n \n newChannel.on('system', { event: 'error' }, (payload) => \n this.#handleChannelError(run_id, channelName, newChannel, payload.error)\n );\n \n // Subscribe and update the channels map\n newChannel.subscribe();\n this.#channels.set(run_id, newChannel);\n } catch (e) {\n console.error(`Failed to reconnect to ${channelName}:`, e);\n }\n }\n \n /**\n * Refresh client state from a state snapshot\n * @param run_id - The run ID\n * @param state - The state snapshot\n */\n #refreshStateFromSnapshot(\n run_id: string,\n state: { run: RunRow; steps: StepStateRow[] } | null\n ): void {\n if (!state || !state.run) return;\n \n // Create proper run event with correct event_type\n const runEvent: BroadcastRunEvent = {\n event_type: `run:${state.run.status}`,\n ...state.run\n } as unknown as BroadcastRunEvent;\n \n // Emit run event\n this.#emitter.emit('runEvent', runEvent);\n \n // Emit events for each step state\n if (state.steps && Array.isArray(state.steps)) {\n for (const step of state.steps) {\n // Create proper step event with correct event_type\n const stepEvent: BroadcastStepEvent = {\n event_type: `step:${step.status}`,\n ...step\n } as unknown as BroadcastStepEvent;\n \n // Emit step event\n this.#emitter.emit('stepEvent', stepEvent);\n }\n }\n }\n\n /**\n * Fetches flow definition metadata from the database\n *\n * @param flow_slug - Flow slug to fetch\n */\n async fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }> {\n // Fetch flow details and steps in parallel\n const [flowResult, stepsResult] = await Promise.all([\n this.#supabase\n .schema('pgflow')\n .from('flows')\n .select('*')\n .eq('flow_slug', flow_slug)\n .single(),\n this.#supabase\n .schema('pgflow')\n .from('steps')\n .select('*')\n .eq('flow_slug', flow_slug)\n .order('step_index', { ascending: true })\n ]);\n\n // Handle flow result\n if (flowResult.error) throw flowResult.error;\n if (!flowResult.data) throw new Error(`Flow \"${flow_slug}\" not found`);\n\n // Handle steps result\n if (stepsResult.error) throw stepsResult.error;\n \n // Ensure steps is always an array, even if it's null or undefined\n const stepsArray = Array.isArray(stepsResult.data) ? stepsResult.data : [];\n\n return {\n flow: flowResult.data as FlowRow,\n steps: stepsArray as StepRow[],\n };\n }\n\n /**\n * Registers a callback for run events\n *\n * @param callback - Function to call when run events are received\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('runEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from run event - emitter may have been disposed', e);\n }\n };\n }\n\n /**\n * Registers a callback for step events\n *\n * @param callback - Function to call when step events are received\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('stepEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from step event - emitter may have been disposed', e);\n }\n };\n }\n\n // Store unsubscribe functions per run ID for reference equality\n #unsubscribeFunctions: Map<string, () => void> = new Map();\n\n /**\n * Subscribes to a flow run's events\n *\n * @param run_id - Run ID to subscribe to\n * @returns Function to unsubscribe\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n const channelName = `pgflow:run:${run_id}`;\n\n // If already subscribed, return the existing unsubscribe function\n if (this.#channels.has(run_id)) {\n const existingUnsubscribe = this.#unsubscribeFunctions.get(run_id);\n if (existingUnsubscribe) {\n return existingUnsubscribe;\n }\n // If channel exists but no unsubscribe function, something went wrong\n // Let's clean up and recreate\n this.#unsubscribe(run_id);\n }\n\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Set up error handling\n channel.on('system', { event: 'closed' }, () => {\n console.log(`Channel ${channelName} closed`);\n });\n channel.on('system', { event: 'error' }, (payload) => {\n console.log(`Channel ${channelName} error:`, payload);\n this.#handleChannelError(run_id, channelName, channel, payload.error);\n });\n \n // Subscribe to channel and wait for confirmation (like the working realtime-send test)\n console.log(`Subscribing to channel ${channelName}...`);\n \n const subscriptionPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Subscription timeout for channel ${channelName}`));\n }, 20000); // Increased from 5s to 20s for slower CI environments\n \n channel.subscribe((status) => {\n console.log(`Channel ${channelName} subscription status:`, status);\n if (status === 'SUBSCRIBED') {\n clearTimeout(timeout);\n resolve();\n }\n // Don't reject on CHANNEL_ERROR - it's a transient state\n // Only reject on timeout\n });\n });\n \n // Wait for the 'SUBSCRIBED' acknowledgment to avoid race conditions\n await subscriptionPromise;\n\n // Stabilization delay - known Supabase Realtime limitation\n // The SUBSCRIBED event is emitted before backend routing is fully established.\n // This delay ensures the backend can receive messages sent immediately after subscription.\n // See: https://github.com/supabase/supabase-js/issues/1599\n await new Promise(resolve => this.#schedule(resolve, this.#stabilizationDelay));\n\n this.#channels.set(run_id, channel);\n\n const unsubscribe = () => this.unsubscribe(run_id);\n this.#unsubscribeFunctions.set(run_id, unsubscribe);\n return unsubscribe;\n }\n \n /**\n * Unsubscribes from a run's events\n * \n * @param run_id - Run ID to unsubscribe from\n */\n unsubscribe(run_id: string): void {\n this.#unsubscribe(run_id);\n }\n\n /**\n * Fetches current state of a run and its steps\n *\n * @param run_id - Run ID to fetch\n */\n async getRunWithStates(run_id: string): Promise<{\n run: RunRow;\n steps: StepStateRow[];\n }> {\n // Call the RPC function which returns a JSONB object\n const { data, error } = await this.#supabase\n .schema('pgflow')\n .rpc('get_run_with_states', { run_id });\n\n if (error) throw error;\n if (!data) throw new Error(`No data returned for run ${run_id}`);\n \n return data as { run: RunRow; steps: StepStateRow[] };\n }\n\n /**\n * Unsubscribes from a run's events\n *\n * @param run_id - Run ID to unsubscribe from\n */\n #unsubscribe(run_id: string): void {\n const channel = this.#channels.get(run_id);\n if (channel) {\n // Close the channel\n channel.unsubscribe();\n this.#channels.delete(run_id);\n \n // Also clean up the unsubscribe function reference\n this.#unsubscribeFunctions.delete(run_id);\n \n // We don't need to explicitly remove event listeners from the emitter\n // as they will be garbage collected when no longer referenced.\n // The event listeners are bound to specific callbacks provided by the client,\n // which will retain references if they're still in use.\n }\n }\n}\n","import { createNanoEvents } from 'nanoevents';\nimport type { AnyFlow, ExtractFlowSteps, StepOutput } from '@pgflow/dsl';\nimport { FlowStepStatus } from './types.js';\nimport type { \n FlowStepState, \n StepEvents, \n Unsubscribe, \n FlowStepBase,\n StepEvent\n} from './types.js';\n\n/**\n * Represents a single step in a flow run\n */\nexport class FlowStep<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> implements FlowStepBase<StepEvent<TFlow, TStepSlug>> {\n #state: FlowStepState<TFlow, TStepSlug>;\n #events = createNanoEvents<StepEvents<TFlow, TStepSlug>>();\n #statusPrecedence: Record<FlowStepStatus, number> = {\n [FlowStepStatus.Created]: 0,\n [FlowStepStatus.Started]: 1,\n [FlowStepStatus.Completed]: 2,\n [FlowStepStatus.Failed]: 3,\n };\n\n /**\n * Creates a new FlowStep instance\n * \n * @param initialState - Initial state for the step\n */\n constructor(initialState: FlowStepState<TFlow, TStepSlug>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID this step belongs to\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the step slug\n */\n get step_slug(): TStepSlug {\n return this.#state.step_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowStepStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the step output\n */\n get output(): StepOutput<TFlow, TStepSlug> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Register an event handler for a step event\n * \n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof StepEvents<TFlow, TStepSlug>>(\n event: E,\n callback: StepEvents<TFlow, TStepSlug>[E]\n ): Unsubscribe {\n return this.#events.on(event, callback);\n }\n\n /**\n * Wait for the step to reach a specific status\n * \n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the step instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowStepStatus.Started | FlowStepStatus.Completed | FlowStepStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n \n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n }, timeoutMs);\n }\n \n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n };\n \n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n \n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').StepStateRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowStepStatus;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.error_message = row.error_message;\n this.#state.error = row.error_message ? new Error(row.error_message) : null;\n // Note: output is not stored in step_states table, remains null\n }\n\n /**\n * Updates the step state based on an event\n *\n * @internal This method is only intended for use by FlowRun and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: StepEvent<TFlow, TStepSlug>): boolean {\n // Validate event is for this step\n if (event.step_slug !== this.#state.step_slug) {\n return false;\n }\n \n // Validate event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n \n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowStepStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Started,\n started_at: typeof event.started_at === 'string' ? new Date(event.started_at) : new Date(),\n };\n this.#events.emit('started', event);\n break;\n\n case FlowStepStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Completed,\n completed_at: typeof event.completed_at === 'string' ? new Date(event.completed_at) : new Date(),\n output: event.output as StepOutput<TFlow, TStepSlug>,\n };\n this.#events.emit('completed', event);\n break;\n\n case FlowStepStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Failed,\n failed_at: typeof event.failed_at === 'string' ? new Date(event.failed_at) : new Date(),\n error_message: typeof event.error_message === 'string' ? event.error_message : 'Unknown error',\n error: new Error(typeof event.error_message === 'string' ? event.error_message : 'Unknown error'),\n };\n this.#events.emit('failed', event);\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n \n return true;\n }\n\n /**\n * Determines if a status should be updated based on precedence\n * \n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(currentStatus: FlowStepStatus, newStatus: FlowStepStatus): boolean {\n // Don't allow changes to terminal states\n if (currentStatus === FlowStepStatus.Completed || currentStatus === FlowStepStatus.Failed) {\n return false; // Terminal states should never change\n }\n \n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n}","import { createNanoEvents } from 'nanoevents';\nimport type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n} from '@pgflow/dsl';\nimport { FlowRunStatus, FlowStepStatus } from './types.js';\nimport type {\n FlowRunState,\n FlowRunEvents,\n Unsubscribe,\n FlowRunBase,\n FlowStepBase,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\nimport { FlowStep } from './FlowStep.js';\n\n/**\n * Represents a single execution of a flow\n */\nexport class FlowRun<TFlow extends AnyFlow>\n implements FlowRunBase<FlowRunEvent<TFlow>>\n{\n #state: FlowRunState<TFlow>;\n #events = createNanoEvents<FlowRunEvents<TFlow>>();\n #steps = new Map<string, FlowStepBase>();\n #statusPrecedence: Record<FlowRunStatus, number> = {\n [FlowRunStatus.Started]: 0,\n [FlowRunStatus.Completed]: 1,\n [FlowRunStatus.Failed]: 2,\n };\n #disposed = false;\n\n /**\n * Creates a new FlowRun instance\n *\n * @param initialState - Initial state for the run\n */\n constructor(initialState: FlowRunState<TFlow>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the flow slug\n */\n get flow_slug(): string {\n return this.#state.flow_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowRunStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the flow input\n */\n get input(): ExtractFlowInput<TFlow> {\n return this.#state.input;\n }\n\n /**\n * Get the flow output\n */\n get output(): ExtractFlowOutput<TFlow> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Get the number of remaining steps\n */\n get remaining_steps(): number {\n return this.#state.remaining_steps;\n }\n\n /**\n * Register an event handler for a run event\n *\n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof FlowRunEvents<TFlow>>(\n event: E,\n callback: FlowRunEvents<TFlow>[E]\n ): Unsubscribe {\n this.#listenerCount++;\n\n // Wrap the unsubscribe function to track listener count\n const unsubscribe = this.#events.on(event, callback);\n\n return () => {\n unsubscribe();\n this.#listenerCount--;\n this.#checkAutoDispose();\n };\n }\n\n /**\n * Get a FlowStep instance for a specific step\n *\n * @param stepSlug - Step slug to get\n * @returns FlowStep instance for the specified step\n */\n step<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug\n ): FlowStep<TFlow, TStepSlug> {\n // Look up if we already have this step cached\n const existingStep = this.#steps.get(stepSlug as string);\n if (existingStep) {\n // Safe to cast since we only store steps with matching slugs\n return existingStep as unknown as FlowStep<TFlow, TStepSlug>;\n }\n\n // Create a new step instance with default state\n const step = new FlowStep<TFlow, TStepSlug>({\n run_id: this.run_id,\n step_slug: stepSlug,\n status: FlowStepStatus.Created,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n });\n\n // Cache the step\n this.#steps.set(\n stepSlug as string,\n step as FlowStepBase<StepEvent<TFlow, TStepSlug>>\n );\n\n return step;\n }\n\n /**\n * Check if this run has a specific step\n *\n * @param stepSlug - Step slug to check\n * @returns true if the step exists, false otherwise\n */\n hasStep(stepSlug: string): boolean {\n // Check if we have this step cached\n return this.#steps.has(stepSlug);\n }\n\n /**\n * Wait for the run to reach a specific status\n *\n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the run instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowRunStatus.Completed | FlowRunStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n\n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(\n new Error(\n `Timeout waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n }, timeoutMs);\n }\n\n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(\n new Error(\n `Aborted waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n };\n\n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n\n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').RunRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowRunStatus;\n this.#state.input = row.input as ExtractFlowInput<TFlow>;\n this.#state.output = row.output as ExtractFlowOutput<TFlow> | null;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.remaining_steps = row.remaining_steps;\n this.#state.error_message = null; // Database doesn't have error_message for runs\n this.#state.error = null;\n }\n\n /**\n * Updates the run state based on an event\n *\n * @internal This method is only intended for use by PgflowClient and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: FlowRunEvent<TFlow>): boolean {\n // Validate the event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n\n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowRunStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Started,\n started_at:\n typeof event.started_at === 'string'\n ? new Date(event.started_at)\n : new Date(),\n remaining_steps:\n 'remaining_steps' in event\n ? Number(event.remaining_steps)\n : this.#state.remaining_steps,\n };\n this.#events.emit('started', event);\n break;\n\n case FlowRunStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Completed,\n completed_at:\n typeof event.completed_at === 'string'\n ? new Date(event.completed_at)\n : new Date(),\n output: event.output as ExtractFlowOutput<TFlow>,\n remaining_steps: 0,\n };\n this.#events.emit('completed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n case FlowRunStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Failed,\n failed_at:\n typeof event.failed_at === 'string'\n ? new Date(event.failed_at)\n : new Date(),\n error_message:\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error',\n error: new Error(\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error'\n ),\n };\n this.#events.emit('failed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n\n return true;\n }\n\n /**\n * Updates a step state based on an event\n *\n * @param stepSlug - Step slug to update\n * @param event - Event data to update the step with\n * @returns true if the state was updated, false otherwise\n */\n updateStepState<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug,\n event: StepEvent<TFlow, TStepSlug>\n ): boolean {\n const step = this.step(stepSlug);\n return step.updateState(event);\n }\n\n // Track number of listeners\n #listenerCount = 0;\n\n /**\n * Checks if auto-dispose should be triggered (when in terminal state with no listeners)\n */\n #checkAutoDispose(): void {\n // Don't auto-dispose multiple times\n if (this.#disposed) {\n return;\n }\n\n // Only auto-dispose in terminal states\n if (\n this.status !== FlowRunStatus.Completed &&\n this.status !== FlowRunStatus.Failed\n ) {\n return;\n }\n\n // If there are no listeners, auto-dispose\n if (this.#listenerCount === 0) {\n this.dispose();\n }\n }\n\n /**\n * Determines if a status should be updated based on precedence\n *\n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(\n currentStatus: FlowRunStatus,\n newStatus: FlowRunStatus\n ): boolean {\n // Don't allow changes to terminal states\n if (\n currentStatus === FlowRunStatus.Completed ||\n currentStatus === FlowRunStatus.Failed\n ) {\n return false; // Terminal states should never change\n }\n\n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n\n /**\n * Clean up all resources held by this run\n */\n dispose(): void {\n if (this.#disposed) {\n return;\n }\n\n // Clear the map to allow garbage collection of steps\n this.#steps.clear();\n\n // Create a new events object - this effectively clears all listeners\n // without accessing the private internals of nanoevents\n this.#events = createNanoEvents<FlowRunEvents<TFlow>>();\n this.#listenerCount = 0;\n\n // Mark as disposed\n this.#disposed = true;\n }\n}\n","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type { RunRow, StepStateRow } from '@pgflow/core';\nimport {\n FlowStepStatus,\n FlowRunStatus,\n} from './types.js';\nimport type {\n BroadcastRunEvent,\n BroadcastStepEvent,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\n\n/**\n * Convert a broadcast run event to a typed run event\n */\nexport function toTypedRunEvent<TFlow extends AnyFlow>(\n evt: BroadcastRunEvent\n): FlowRunEvent<TFlow> {\n switch (evt.status) {\n case FlowRunStatus.Started:\n return {\n event_type: 'run:started',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Started,\n started_at: evt.started_at,\n remaining_steps: evt.remaining_steps,\n input: evt.input as ExtractFlowInput<TFlow>,\n };\n case FlowRunStatus.Completed:\n return {\n event_type: 'run:completed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as ExtractFlowOutput<TFlow>,\n };\n case FlowRunStatus.Failed:\n return {\n event_type: 'run:failed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a broadcast step event to a typed step event\n */\nexport function toTypedStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(evt: BroadcastStepEvent): StepEvent<TFlow, TStepSlug> {\n switch (evt.status) {\n case FlowStepStatus.Started:\n return {\n event_type: 'step:started',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: evt.started_at,\n };\n case FlowStepStatus.Completed:\n return {\n event_type: 'step:completed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as StepOutput<TFlow, TStepSlug>,\n };\n case FlowStepStatus.Failed:\n return {\n event_type: 'step:failed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a database run row to a typed run event\n */\nexport function runRowToTypedEvent<TFlow extends AnyFlow>(\n row: RunRow\n): FlowRunEvent<TFlow> {\n switch (row.status) {\n case 'started':\n return {\n event_type: 'run:started',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Started,\n started_at: row.started_at!,\n remaining_steps: row.remaining_steps,\n input: row.input as ExtractFlowInput<TFlow>,\n };\n case 'completed':\n return {\n event_type: 'run:completed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: row.completed_at!,\n output: row.output as ExtractFlowOutput<TFlow>,\n };\n case 'failed':\n return {\n event_type: 'run:failed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: row.failed_at!,\n error_message: 'Flow failed', // Database doesn't have error_message for runs\n };\n default:\n throw new Error(`Unknown run status: ${row.status}`);\n }\n}\n\n/**\n * Convert a database step state row to a typed step event\n */\nexport function stepStateRowToTypedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(row: StepStateRow): StepEvent<TFlow, TStepSlug> {\n switch (row.status) {\n case 'created':\n case 'started':\n return {\n event_type: 'step:started',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: row.started_at!,\n };\n case 'completed':\n return {\n event_type: 'step:completed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: row.completed_at!,\n output: {} as StepOutput<TFlow, TStepSlug>, // Database doesn't have output in step_states\n };\n case 'failed':\n return {\n event_type: 'step:failed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: row.failed_at!,\n error_message: row.error_message || 'Step failed',\n };\n default:\n throw new Error(`Unknown step status: ${row.status}`);\n }\n}","import { v4 as uuidv4 } from 'uuid';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';\nimport { FlowRunStatus } from './types.js';\nimport type { \n IFlowClient, \n FlowRunState, \n BroadcastRunEvent, \n BroadcastStepEvent, \n Unsubscribe, \n FlowRunBase\n} from './types.js';\nimport { SupabaseBroadcastAdapter } from './SupabaseBroadcastAdapter.js';\nimport { FlowRun } from './FlowRun.js';\nimport { toTypedRunEvent, toTypedStepEvent } from './eventAdapters.js';\n\n/**\n * Client for interacting with pgflow\n */\nexport class PgflowClient<TFlow extends AnyFlow = AnyFlow> implements IFlowClient<TFlow> {\n #supabase: SupabaseClient;\n #realtimeAdapter: SupabaseBroadcastAdapter;\n // Use the widest event type - keeps the compiler happy but\n // still provides the structural API we need (updateState/step/...)\n #runs = new Map<string, FlowRunBase<unknown>>();\n\n /**\n * Creates a new PgflowClient instance\n *\n * @param supabaseClient - Supabase client instance\n * @param opts - Optional configuration\n */\n constructor(\n supabaseClient: SupabaseClient,\n opts: {\n realtimeStabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabaseClient;\n this.#realtimeAdapter = new SupabaseBroadcastAdapter(supabaseClient, {\n stabilizationDelayMs: opts.realtimeStabilizationDelayMs,\n schedule: opts.schedule,\n });\n\n // Set up global event listeners - properly typed\n this.#realtimeAdapter.onRunEvent((event: BroadcastRunEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Convert broadcast event to typed event before updating state\n run.updateState(toTypedRunEvent(event));\n }\n });\n\n this.#realtimeAdapter.onStepEvent((event: BroadcastStepEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Always materialize the step before updating to avoid event loss\n // This ensures we cache all steps even if they were never explicitly requested\n const stepSlug = event.step_slug;\n run.step(stepSlug).updateState(toTypedStepEvent(event));\n }\n });\n }\n\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n async startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>> {\n // Generate a run_id if not provided\n const id = run_id || uuidv4();\n\n // Create initial state for the flow run\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: id,\n flow_slug,\n status: FlowRunStatus.Started,\n input: input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: -1, // Use -1 to indicate unknown until first snapshot arrives\n };\n\n // Create the flow run instance\n const run = new FlowRun<TSpecificFlow>(initialState);\n\n // Store the run\n this.#runs.set(id, run);\n\n // Set up subscription for run and step events (wait for subscription confirmation)\n await this.#realtimeAdapter.subscribeToRun(id);\n\n // Start the flow with the predetermined run_id (only after subscription is ready)\n const { data, error } = await this.#supabase.schema('pgflow').rpc('start_flow_with_states', {\n flow_slug: flow_slug,\n input: input as Record<string, unknown>,\n run_id: id\n });\n\n if (error) {\n // Clean up subscription and run instance\n this.dispose(id);\n throw error;\n }\n\n // Apply the run state snapshot (no events)\n if (data.run) {\n run.applySnapshot(data.run);\n }\n\n // Apply step state snapshots (no events)\n if (data.steps && Array.isArray(data.steps)) {\n for (const stepState of data.steps) {\n run.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n\n return run;\n }\n\n /**\n * Dispose a specific flow run\n *\n * @param runId - Run ID to dispose\n */\n dispose(runId: string): void {\n const run = this.#runs.get(runId);\n if (run) {\n // First unsubscribe from the realtime adapter\n this.#realtimeAdapter.unsubscribe(runId);\n \n // Then dispose the run\n run.dispose();\n \n // Finally remove from the runs map\n this.#runs.delete(runId);\n }\n }\n\n /**\n * Dispose all flow runs\n */\n disposeAll(): void {\n for (const runId of this.#runs.keys()) {\n this.dispose(runId);\n }\n }\n\n // Delegate IFlowRealtime methods to the adapter\n\n /**\n * Fetch flow definition metadata\n */\n async fetchFlowDefinition(flow_slug: string) {\n return this.#realtimeAdapter.fetchFlowDefinition(flow_slug);\n }\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onRunEvent(callback);\n }\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onStepEvent(callback);\n }\n\n /**\n * Subscribe to a flow run's events\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n return await this.#realtimeAdapter.subscribeToRun(run_id);\n }\n\n /**\n * Fetch current state of a run and its steps\n */\n async getRunWithStates(run_id: string) {\n return this.#realtimeAdapter.getRunWithStates(run_id);\n }\n \n /**\n * Get a flow run by ID\n * \n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n async getRun<TSpecificFlow extends TFlow = TFlow>(run_id: string): Promise<FlowRun<TSpecificFlow> | null> {\n // Check if we already have this run cached\n const existingRun = this.#runs.get(run_id);\n if (existingRun) {\n return existingRun as FlowRun<TSpecificFlow>;\n }\n \n try {\n // Fetch the run state from the database\n const { run, steps } = await this.getRunWithStates(run_id);\n \n if (!run) {\n return null;\n }\n \n // Validate required fields\n if (!run.run_id || !run.flow_slug || !run.status) {\n throw new Error('Invalid run data: missing required fields');\n }\n\n // Validate status is a valid FlowRunStatus\n const validStatuses = Object.values(FlowRunStatus);\n if (!validStatuses.includes(run.status as FlowRunStatus)) {\n throw new Error(`Invalid run data: invalid status '${run.status}'`);\n }\n\n // Create flow run with minimal initial state\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: run.run_id,\n flow_slug: run.flow_slug,\n status: run.status as FlowRunStatus,\n input: run.input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: 0,\n };\n\n // Create the flow run instance\n const flowRun = new FlowRun<TSpecificFlow>(initialState);\n\n // Apply the complete state from database snapshot\n flowRun.applySnapshot(run);\n \n // Store the run\n this.#runs.set(run_id, flowRun);\n \n // Set up subscription for run and step events\n await this.#realtimeAdapter.subscribeToRun(run_id);\n \n // Initialize steps from snapshot\n if (steps && Array.isArray(steps)) {\n for (const stepState of steps) {\n // Validate step has required fields\n if (!stepState.step_slug || !stepState.status) {\n throw new Error('Invalid step data: missing required fields');\n }\n\n // Apply snapshot state directly (no events)\n flowRun.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n \n return flowRun;\n } catch (error) {\n console.error('Error getting run:', error);\n // Re-throw if it's a validation error\n if (error instanceof Error && (error.message.includes('Invalid run data') || error.message.includes('Invalid step data'))) {\n throw error;\n }\n return null;\n }\n }\n \n}\n"],"names":["FlowRunStatus","isFlowRunEvent","value","isFlowRunStartedEvent","event","isFlowRunCompletedEvent","isFlowRunFailedEvent","FlowStepStatus","isStepEvent","isStepStartedEvent","isStepCompletedEvent","isStepFailedEvent","SupabaseBroadcastAdapter","supabase","opts","__privateAdd","_SupabaseBroadcastAdapter_instances","_supabase","_channels","_emitter","createNanoEvents","_reconnectionDelay","_stabilizationDelay","_schedule","_unsubscribeFunctions","__privateSet","flow_slug","flowResult","stepsResult","__privateGet","stepsArray","callback","unsubscribe","e","run_id","channelName","existingUnsubscribe","__privateMethod","unsubscribe_fn","channel","handleBroadcastMessage_fn","payload","handleChannelError_fn","resolve","reject","timeout","status","data","error","msg","eventData","parseJsonFields_fn","reconnectChannel_fn","createAndConfigureChannel_fn","currentState","refreshStateFromSnapshot_fn","newChannel","state","runEvent","step","stepEvent","FlowStep","initialState","_FlowStep_instances","_state","_events","_statusPrecedence","targetStatus","options","timeoutMs","signal","timeoutId","cleanedUp","unbind","abortCleanup","abortHandler","row","shouldUpdateStatus_fn","currentStatus","newStatus","currentPrecedence","FlowRun","_FlowRun_instances","_steps","_disposed","_listenerCount","__privateWrapper","checkAutoDispose_fn","stepSlug","existingStep","toTypedRunEvent","evt","toTypedStepEvent","PgflowClient","supabaseClient","_realtimeAdapter","_runs","run","input","id","uuidv4","stepState","runId","existingRun","steps","flowRun"],"mappings":"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"}
|
package/dist/package.json
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var __typeError=t=>{throw TypeError(t)},__accessCheck=(t,e,r)=>e.has(t)||__typeError("Cannot "+r),__privateGet=(t,e,r)=>(__accessCheck(t,e,"read from private field"),r?r.call(t):e.get(t)),__privateAdd=(t,e,r)=>e.has(t)?__typeError("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),__privateSet=(t,e,r,s)=>(__accessCheck(t,e,"write to private field"),s?s.call(t,r):e.set(t,r),r),__privateMethod=(t,e,r)=>(__accessCheck(t,e,"access private method"),r),__privateWrapper=(t,e,r,s)=>({set _(s){__privateSet(t,e,s,r)},get _(){return __privateGet(t,e,s)}}),pgflow=function(t){"use strict";var e,r,s,a,i,n,_,o,p,u,l,d,h,c,v,f,m,g,w,G,y,S,b,E,M,k,A,C,W,D,F,R;let $;const T=new Uint8Array(16);function U(){if(!$&&($="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!$))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return $(T)}const I=[];for(let x=0;x<256;++x)I.push((x+256).toString(16).slice(1));const P={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function j(t,e,r){if(P.randomUUID&&!t)return P.randomUUID();const s=(t=t||{}).random||(t.rng||U)();return s[6]=15&s[6]|64,s[8]=63&s[8]|128,function(t,e=0){return I[t[e+0]]+I[t[e+1]]+I[t[e+2]]+I[t[e+3]]+"-"+I[t[e+4]]+I[t[e+5]]+"-"+I[t[e+6]]+I[t[e+7]]+"-"+I[t[e+8]]+I[t[e+9]]+"-"+I[t[e+10]]+I[t[e+11]]+I[t[e+12]]+I[t[e+13]]+I[t[e+14]]+I[t[e+15]]}(s)}var q=(t=>(t.Started="started",t.Completed="completed",t.Failed="failed",t))(q||{});var L=(t=>(t.Created="created",t.Started="started",t.Completed="completed",t.Failed="failed",t))(L||{});function N(t){return!!t&&"object"==typeof t&&"run_id"in t&&"step_slug"in t&&"status"in t&&("started"===t.status||"completed"===t.status||"failed"===t.status)}let O=()=>({events:{},emit(t,...e){let r=this.events[t]||[];for(let s=0,a=r.length;s<a;s++)r[s](...e)},on(t,e){var r;return(null==(r=this.events[t])?void 0:r.push(e))||(this.events[t]=[e]),()=>{var r;this.events[t]=null==(r=this.events[t])?void 0:r.filter(t=>e!==t)}}});class z{constructor(t,o={}){__privateAdd(this,_),__privateAdd(this,e),__privateAdd(this,r,new Map),__privateAdd(this,s,O()),__privateAdd(this,a),__privateAdd(this,i),__privateAdd(this,n),__privateAdd(this,c,new Map),__privateSet(this,e,t),__privateSet(this,a,o.reconnectDelayMs??2e3),__privateSet(this,i,o.stabilizationDelayMs??300),__privateSet(this,n,o.schedule??setTimeout)}async fetchFlowDefinition(t){const[r,s]=await Promise.all([__privateGet(this,e).schema("pgflow").from("flows").select("*").eq("flow_slug",t).single(),__privateGet(this,e).schema("pgflow").from("steps").select("*").eq("flow_slug",t).order("step_index",{ascending:!0})]);if(r.error)throw r.error;if(!r.data)throw new Error(`Flow "${t}" not found`);if(s.error)throw s.error;const a=Array.isArray(s.data)?s.data:[];return{flow:r.data,steps:a}}onRunEvent(t){const e=__privateGet(this,s).on("runEvent",t);return()=>{try{e()}catch(t){console.warn("Could not unsubscribe from run event - emitter may have been disposed",t)}}}onStepEvent(t){const e=__privateGet(this,s).on("stepEvent",t);return()=>{try{e()}catch(t){console.warn("Could not unsubscribe from step event - emitter may have been disposed",t)}}}async subscribeToRun(t){const s=`pgflow:run:${t}`;if(__privateGet(this,r).has(t)){const e=__privateGet(this,c).get(t);if(e)return e;__privateMethod(this,_,v).call(this,t)}const a=__privateGet(this,e).channel(s);a.on("broadcast",{event:"*"},__privateMethod(this,_,o).bind(this)),a.on("system",{event:"closed"},()=>{console.log(`Channel ${s} closed`)}),a.on("system",{event:"error"},e=>{console.log(`Channel ${s} error:`,e),__privateMethod(this,_,u).call(this,t,s,a,e.error)}),console.log(`Subscribing to channel ${s}...`);const p=new Promise((t,e)=>{const r=setTimeout(()=>{e(new Error(`Subscription timeout for channel ${s}`))},2e4);a.subscribe(e=>{console.log(`Channel ${s} subscription status:`,e),"SUBSCRIBED"===e&&(clearTimeout(r),t())})});await p,await new Promise(t=>__privateGet(this,n).call(this,t,__privateGet(this,i))),__privateGet(this,r).set(t,a);const l=()=>this.unsubscribe(t);return __privateGet(this,c).set(t,l),l}unsubscribe(t){__privateMethod(this,_,v).call(this,t)}async getRunWithStates(t){const{data:r,error:s}=await __privateGet(this,e).schema("pgflow").rpc("get_run_with_states",{run_id:t});if(s)throw s;if(!r)throw new Error(`No data returned for run ${t}`);return r}}e=new WeakMap,r=new WeakMap,s=new WeakMap,a=new WeakMap,i=new WeakMap,n=new WeakMap,_=new WeakSet,o=function(t){const{event:e,payload:r}=t,a=r;__privateMethod(this,_,p).call(this,a),e.startsWith("run:")?__privateGet(this,s).emit("runEvent",a):e.startsWith("step:")&&__privateGet(this,s).emit("stepEvent",a)},p=function(t){if("output"in t&&"string"==typeof t.output)try{t.output=JSON.parse(t.output)}catch{}if("input"in t&&"string"==typeof t.input)try{t.input=JSON.parse(t.input)}catch{}},u=async function(t,e,s,i){console.error(`Channel ${e} error:`,i),__privateGet(this,n).call(this,async()=>{__privateGet(this,r).has(t)&&await __privateMethod(this,_,d).call(this,t,e)},__privateGet(this,a))},l=function(t,r){const s=__privateGet(this,e).channel(r);return s.on("broadcast",{event:"*"},__privateMethod(this,_,o).bind(this)),s},d=async function(t,e){console.log(`Attempting to reconnect to ${e}`);try{const s=await this.getRunWithStates(t);__privateMethod(this,_,h).call(this,t,s);const a=__privateMethod(this,_,l).call(this,t,e);a.on("system",{event:"subscribed"},()=>{console.log(`Reconnected and subscribed to channel ${e}`)}),a.on("system",{event:"closed"},()=>{console.log(`Reconnected channel ${e} closed`)}),a.on("system",{event:"error"},r=>__privateMethod(this,_,u).call(this,t,e,a,r.error)),a.subscribe(),__privateGet(this,r).set(t,a)}catch(s){console.error(`Failed to reconnect to ${e}:`,s)}},h=function(t,e){if(!e||!e.run)return;const r={event_type:`run:${e.run.status}`,...e.run};if(__privateGet(this,s).emit("runEvent",r),e.steps&&Array.isArray(e.steps))for(const a of e.steps){const t={event_type:`step:${a.status}`,...a};__privateGet(this,s).emit("stepEvent",t)}},c=new WeakMap,v=function(t){const e=__privateGet(this,r).get(t);e&&(e.unsubscribe(),__privateGet(this,r).delete(t),__privateGet(this,c).delete(t))};class V{constructor(t){__privateAdd(this,w),__privateAdd(this,f),__privateAdd(this,m,O()),__privateAdd(this,g,{[L.Created]:0,[L.Started]:1,[L.Completed]:2,[L.Failed]:3}),__privateSet(this,f,t)}get run_id(){return __privateGet(this,f).run_id}get step_slug(){return __privateGet(this,f).step_slug}get status(){return __privateGet(this,f).status}get started_at(){return __privateGet(this,f).started_at}get completed_at(){return __privateGet(this,f).completed_at}get failed_at(){return __privateGet(this,f).failed_at}get output(){return __privateGet(this,f).output}get error(){return __privateGet(this,f).error}get error_message(){return __privateGet(this,f).error_message}on(t,e){return __privateGet(this,m).on(t,e)}waitForStatus(t,e){const r=(null==e?void 0:e.timeoutMs)??3e5,{signal:s}=e||{};return this.status===t?Promise.resolve(this):new Promise((e,a)=>{let i,n,_=!1;if(r>0&&(i=setTimeout(()=>{_||(_=!0,o(),a(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${t}'`)))},r)),s){const e=()=>{_||(_=!0,i&&clearTimeout(i),o(),a(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${t}'`)))};s.addEventListener("abort",e),n=()=>{s.removeEventListener("abort",e)}}const o=this.on("*",r=>{if(r.status===t){if(_)return;_=!0,i&&clearTimeout(i),n&&n(),o(),e(this)}})})}applySnapshot(t){__privateGet(this,f).status=t.status,__privateGet(this,f).started_at=t.started_at?new Date(t.started_at):null,__privateGet(this,f).completed_at=t.completed_at?new Date(t.completed_at):null,__privateGet(this,f).failed_at=t.failed_at?new Date(t.failed_at):null,__privateGet(this,f).error_message=t.error_message,__privateGet(this,f).error=t.error_message?new Error(t.error_message):null}updateState(t){if(t.step_slug!==__privateGet(this,f).step_slug)return!1;if(t.run_id!==__privateGet(this,f).run_id)return!1;if(!__privateMethod(this,w,G).call(this,__privateGet(this,f).status,t.status))return!1;switch(t.status){case L.Started:__privateSet(this,f,{...__privateGet(this,f),status:L.Started,started_at:"string"==typeof t.started_at?new Date(t.started_at):new Date}),__privateGet(this,m).emit("started",t);break;case L.Completed:__privateSet(this,f,{...__privateGet(this,f),status:L.Completed,completed_at:"string"==typeof t.completed_at?new Date(t.completed_at):new Date,output:t.output}),__privateGet(this,m).emit("completed",t);break;case L.Failed:__privateSet(this,f,{...__privateGet(this,f),status:L.Failed,failed_at:"string"==typeof t.failed_at?new Date(t.failed_at):new Date,error_message:"string"==typeof t.error_message?t.error_message:"Unknown error",error:new Error("string"==typeof t.error_message?t.error_message:"Unknown error")}),__privateGet(this,m).emit("failed",t);break;default:return!1}return __privateGet(this,m).emit("*",t),!0}}f=new WeakMap,m=new WeakMap,g=new WeakMap,w=new WeakSet,G=function(t,e){if(t===L.Completed||t===L.Failed)return!1;const r=__privateGet(this,g)[t];return __privateGet(this,g)[e]>r};class B{constructor(t){__privateAdd(this,A),__privateAdd(this,y),__privateAdd(this,S,O()),__privateAdd(this,b,new Map),__privateAdd(this,E,{[q.Started]:0,[q.Completed]:1,[q.Failed]:2}),__privateAdd(this,M,!1),__privateAdd(this,k,0),__privateSet(this,y,t)}get run_id(){return __privateGet(this,y).run_id}get flow_slug(){return __privateGet(this,y).flow_slug}get status(){return __privateGet(this,y).status}get started_at(){return __privateGet(this,y).started_at}get completed_at(){return __privateGet(this,y).completed_at}get failed_at(){return __privateGet(this,y).failed_at}get input(){return __privateGet(this,y).input}get output(){return __privateGet(this,y).output}get error(){return __privateGet(this,y).error}get error_message(){return __privateGet(this,y).error_message}get remaining_steps(){return __privateGet(this,y).remaining_steps}on(t,e){__privateWrapper(this,k)._++;const r=__privateGet(this,S).on(t,e);return()=>{r(),__privateWrapper(this,k)._--,__privateMethod(this,A,C).call(this)}}step(t){const e=__privateGet(this,b).get(t);if(e)return e;const r=new V({run_id:this.run_id,step_slug:t,status:L.Created,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null});return __privateGet(this,b).set(t,r),r}hasStep(t){return __privateGet(this,b).has(t)}waitForStatus(t,e){const r=(null==e?void 0:e.timeoutMs)??3e5,{signal:s}=e||{};return this.status===t?Promise.resolve(this):new Promise((e,a)=>{let i,n,_=!1;if(r>0&&(i=setTimeout(()=>{_||(_=!0,o(),a(new Error(`Timeout waiting for run ${this.run_id} to reach status '${t}'`)))},r)),s){const e=()=>{_||(_=!0,i&&clearTimeout(i),o(),a(new Error(`Aborted waiting for run ${this.run_id} to reach status '${t}'`)))};s.addEventListener("abort",e),n=()=>{s.removeEventListener("abort",e)}}const o=this.on("*",r=>{if(r.status===t){if(_)return;_=!0,i&&clearTimeout(i),n&&n(),o(),e(this)}})})}applySnapshot(t){__privateGet(this,y).status=t.status,__privateGet(this,y).input=t.input,__privateGet(this,y).output=t.output,__privateGet(this,y).started_at=t.started_at?new Date(t.started_at):null,__privateGet(this,y).completed_at=t.completed_at?new Date(t.completed_at):null,__privateGet(this,y).failed_at=t.failed_at?new Date(t.failed_at):null,__privateGet(this,y).remaining_steps=t.remaining_steps,__privateGet(this,y).error_message=null,__privateGet(this,y).error=null}updateState(t){if(t.run_id!==__privateGet(this,y).run_id)return!1;if(!__privateMethod(this,A,W).call(this,__privateGet(this,y).status,t.status))return!1;switch(t.status){case q.Started:__privateSet(this,y,{...__privateGet(this,y),status:q.Started,started_at:"string"==typeof t.started_at?new Date(t.started_at):new Date,remaining_steps:"remaining_steps"in t?Number(t.remaining_steps):__privateGet(this,y).remaining_steps}),__privateGet(this,S).emit("started",t);break;case q.Completed:__privateSet(this,y,{...__privateGet(this,y),status:q.Completed,completed_at:"string"==typeof t.completed_at?new Date(t.completed_at):new Date,output:t.output,remaining_steps:0}),__privateGet(this,S).emit("completed",t),__privateMethod(this,A,C).call(this);break;case q.Failed:__privateSet(this,y,{...__privateGet(this,y),status:q.Failed,failed_at:"string"==typeof t.failed_at?new Date(t.failed_at):new Date,error_message:"string"==typeof t.error_message?t.error_message:"Unknown error",error:new Error("string"==typeof t.error_message?t.error_message:"Unknown error")}),__privateGet(this,S).emit("failed",t),__privateMethod(this,A,C).call(this);break;default:return!1}return __privateGet(this,S).emit("*",t),!0}updateStepState(t,e){return this.step(t).updateState(e)}dispose(){__privateGet(this,M)||(__privateGet(this,b).clear(),__privateSet(this,S,O()),__privateSet(this,k,0),__privateSet(this,M,!0))}}y=new WeakMap,S=new WeakMap,b=new WeakMap,E=new WeakMap,M=new WeakMap,k=new WeakMap,A=new WeakSet,C=function(){__privateGet(this,M)||this.status!==q.Completed&&this.status!==q.Failed||0===__privateGet(this,k)&&this.dispose()},W=function(t,e){if(t===q.Completed||t===q.Failed)return!1;const r=__privateGet(this,E)[t];return __privateGet(this,E)[e]>r};class J{constructor(t,e={}){__privateAdd(this,D),__privateAdd(this,F),__privateAdd(this,R,new Map),__privateSet(this,D,t),__privateSet(this,F,new z(t,{stabilizationDelayMs:e.realtimeStabilizationDelayMs,schedule:e.schedule})),__privateGet(this,F).onRunEvent(t=>{const e=__privateGet(this,R).get(t.run_id);e&&e.updateState(function(t){switch(t.status){case q.Started:return{event_type:"run:started",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Started,started_at:t.started_at,remaining_steps:t.remaining_steps,input:t.input};case q.Completed:return{event_type:"run:completed",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Completed,completed_at:t.completed_at,output:t.output};case q.Failed:return{event_type:"run:failed",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Failed,failed_at:t.failed_at,error_message:t.error_message}}}(t))}),__privateGet(this,F).onStepEvent(t=>{const e=__privateGet(this,R).get(t.run_id);if(e){const r=t.step_slug;e.step(r).updateState(function(t){switch(t.status){case L.Started:return{event_type:"step:started",run_id:t.run_id,step_slug:t.step_slug,status:L.Started,started_at:t.started_at};case L.Completed:return{event_type:"step:completed",run_id:t.run_id,step_slug:t.step_slug,status:L.Completed,completed_at:t.completed_at,output:t.output};case L.Failed:return{event_type:"step:failed",run_id:t.run_id,step_slug:t.step_slug,status:L.Failed,failed_at:t.failed_at,error_message:t.error_message}}}(t))}})}async startFlow(t,e,r){const s=r||j(),a={run_id:s,flow_slug:t,status:q.Started,input:e,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null,remaining_steps:-1},i=new B(a);__privateGet(this,R).set(s,i),await __privateGet(this,F).subscribeToRun(s);const{data:n,error:_}=await __privateGet(this,D).schema("pgflow").rpc("start_flow_with_states",{flow_slug:t,input:e,run_id:s});if(_)throw this.dispose(s),_;if(n.run&&i.applySnapshot(n.run),n.steps&&Array.isArray(n.steps))for(const o of n.steps)i.step(o.step_slug).applySnapshot(o);return i}dispose(t){const e=__privateGet(this,R).get(t);e&&(__privateGet(this,F).unsubscribe(t),e.dispose(),__privateGet(this,R).delete(t))}disposeAll(){for(const t of __privateGet(this,R).keys())this.dispose(t)}async fetchFlowDefinition(t){return __privateGet(this,F).fetchFlowDefinition(t)}onRunEvent(t){return __privateGet(this,F).onRunEvent(t)}onStepEvent(t){return __privateGet(this,F).onStepEvent(t)}async subscribeToRun(t){return await __privateGet(this,F).subscribeToRun(t)}async getRunWithStates(t){return __privateGet(this,F).getRunWithStates(t)}async getRun(t){const e=__privateGet(this,R).get(t);if(e)return e;try{const{run:e,steps:r}=await this.getRunWithStates(t);if(!e)return null;if(!e.run_id||!e.flow_slug||!e.status)throw new Error("Invalid run data: missing required fields");if(!Object.values(q).includes(e.status))throw new Error(`Invalid run data: invalid status '${e.status}'`);const s={run_id:e.run_id,flow_slug:e.flow_slug,status:e.status,input:e.input,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null,remaining_steps:0},a=new B(s);if(a.applySnapshot(e),__privateGet(this,R).set(t,a),await __privateGet(this,F).subscribeToRun(t),r&&Array.isArray(r))for(const t of r){if(!t.step_slug||!t.status)throw new Error("Invalid step data: missing required fields");a.step(t.step_slug).applySnapshot(t)}return a}catch(r){if(console.error("Error getting run:",r),r instanceof Error&&(r.message.includes("Invalid run data")||r.message.includes("Invalid step data")))throw r;return null}}}return D=new WeakMap,F=new WeakMap,R=new WeakMap,t.FlowRunStatus=q,t.FlowStepStatus=L,t.PgflowClient=J,t.createClient=function(t){return new J(t)},t.isFlowRunCompletedEvent=function(t){return"completed"===t.status},t.isFlowRunEvent=function(t){return!!t&&"object"==typeof t&&"run_id"in t&&"flow_slug"in t&&!("step_slug"in t)&&"status"in t&&("started"===t.status||"completed"===t.status||"failed"===t.status)},t.isFlowRunFailedEvent=function(t){return"failed"===t.status},t.isFlowRunStartedEvent=function(t){return"started"===t.status},t.isStepCompletedEvent=function(t){return N(t)&&"completed"===t.status&&"event_type"in t&&"step:completed"===t.event_type},t.isStepEvent=N,t.isStepFailedEvent=function(t){return N(t)&&"failed"===t.status&&"event_type"in t&&"step:failed"===t.event_type},t.isStepStartedEvent=function(t){return N(t)&&"started"===t.status&&"event_type"in t&&"step:started"===t.event_type},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t}({});
|
|
1
|
+
var __typeError=t=>{throw TypeError(t)},__accessCheck=(t,e,r)=>e.has(t)||__typeError("Cannot "+r),__privateGet=(t,e,r)=>(__accessCheck(t,e,"read from private field"),r?r.call(t):e.get(t)),__privateAdd=(t,e,r)=>e.has(t)?__typeError("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,r),__privateSet=(t,e,r,s)=>(__accessCheck(t,e,"write to private field"),s?s.call(t,r):e.set(t,r),r),__privateMethod=(t,e,r)=>(__accessCheck(t,e,"access private method"),r),__privateWrapper=(t,e,r,s)=>({set _(s){__privateSet(t,e,s,r)},get _(){return __privateGet(t,e,s)}}),pgflow=function(t){"use strict";var e,r,s,a,i,n,_,o,p,u,l,d,h,c,v,f,m,g,w,G,y,S,b,E,M,k,A,C,W,D,F,R;let $;const T=new Uint8Array(16);function U(){if(!$&&($="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!$))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return $(T)}const I=[];for(let x=0;x<256;++x)I.push((x+256).toString(16).slice(1));const P={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function j(t,e,r){if(P.randomUUID&&!t)return P.randomUUID();const s=(t=t||{}).random||(t.rng||U)();return s[6]=15&s[6]|64,s[8]=63&s[8]|128,function(t,e=0){return I[t[e+0]]+I[t[e+1]]+I[t[e+2]]+I[t[e+3]]+"-"+I[t[e+4]]+I[t[e+5]]+"-"+I[t[e+6]]+I[t[e+7]]+"-"+I[t[e+8]]+I[t[e+9]]+"-"+I[t[e+10]]+I[t[e+11]]+I[t[e+12]]+I[t[e+13]]+I[t[e+14]]+I[t[e+15]]}(s)}var q=(t=>(t.Started="started",t.Completed="completed",t.Failed="failed",t))(q||{});var L=(t=>(t.Created="created",t.Started="started",t.Completed="completed",t.Failed="failed",t))(L||{});function N(t){return!!t&&"object"==typeof t&&"run_id"in t&&"step_slug"in t&&"status"in t&&("started"===t.status||"completed"===t.status||"failed"===t.status)}let O=()=>({events:{},emit(t,...e){let r=this.events[t]||[];for(let s=0,a=r.length;s<a;s++)r[s](...e)},on(t,e){var r;return(null==(r=this.events[t])?void 0:r.push(e))||(this.events[t]=[e]),()=>{var r;this.events[t]=null==(r=this.events[t])?void 0:r.filter(t=>e!==t)}}});class z{constructor(t,o={}){__privateAdd(this,_),__privateAdd(this,e),__privateAdd(this,r,new Map),__privateAdd(this,s,O()),__privateAdd(this,a),__privateAdd(this,i),__privateAdd(this,n),__privateAdd(this,c,new Map),__privateSet(this,e,t),__privateSet(this,a,o.reconnectDelayMs??2e3),__privateSet(this,i,o.stabilizationDelayMs??300),__privateSet(this,n,o.schedule??setTimeout.bind(globalThis))}async fetchFlowDefinition(t){const[r,s]=await Promise.all([__privateGet(this,e).schema("pgflow").from("flows").select("*").eq("flow_slug",t).single(),__privateGet(this,e).schema("pgflow").from("steps").select("*").eq("flow_slug",t).order("step_index",{ascending:!0})]);if(r.error)throw r.error;if(!r.data)throw new Error(`Flow "${t}" not found`);if(s.error)throw s.error;const a=Array.isArray(s.data)?s.data:[];return{flow:r.data,steps:a}}onRunEvent(t){const e=__privateGet(this,s).on("runEvent",t);return()=>{try{e()}catch(t){console.warn("Could not unsubscribe from run event - emitter may have been disposed",t)}}}onStepEvent(t){const e=__privateGet(this,s).on("stepEvent",t);return()=>{try{e()}catch(t){console.warn("Could not unsubscribe from step event - emitter may have been disposed",t)}}}async subscribeToRun(t){const s=`pgflow:run:${t}`;if(__privateGet(this,r).has(t)){const e=__privateGet(this,c).get(t);if(e)return e;__privateMethod(this,_,v).call(this,t)}const a=__privateGet(this,e).channel(s);a.on("broadcast",{event:"*"},__privateMethod(this,_,o).bind(this)),a.on("system",{event:"closed"},()=>{console.log(`Channel ${s} closed`)}),a.on("system",{event:"error"},e=>{console.log(`Channel ${s} error:`,e),__privateMethod(this,_,u).call(this,t,s,a,e.error)}),console.log(`Subscribing to channel ${s}...`);const p=new Promise((t,e)=>{const r=setTimeout(()=>{e(new Error(`Subscription timeout for channel ${s}`))},2e4);a.subscribe(e=>{console.log(`Channel ${s} subscription status:`,e),"SUBSCRIBED"===e&&(clearTimeout(r),t())})});await p,await new Promise(t=>__privateGet(this,n).call(this,t,__privateGet(this,i))),__privateGet(this,r).set(t,a);const l=()=>this.unsubscribe(t);return __privateGet(this,c).set(t,l),l}unsubscribe(t){__privateMethod(this,_,v).call(this,t)}async getRunWithStates(t){const{data:r,error:s}=await __privateGet(this,e).schema("pgflow").rpc("get_run_with_states",{run_id:t});if(s)throw s;if(!r)throw new Error(`No data returned for run ${t}`);return r}}e=new WeakMap,r=new WeakMap,s=new WeakMap,a=new WeakMap,i=new WeakMap,n=new WeakMap,_=new WeakSet,o=function(t){const{event:e,payload:r}=t,a=r;__privateMethod(this,_,p).call(this,a),e.startsWith("run:")?__privateGet(this,s).emit("runEvent",a):e.startsWith("step:")&&__privateGet(this,s).emit("stepEvent",a)},p=function(t){if("output"in t&&"string"==typeof t.output)try{t.output=JSON.parse(t.output)}catch{}if("input"in t&&"string"==typeof t.input)try{t.input=JSON.parse(t.input)}catch{}},u=async function(t,e,s,i){console.error(`Channel ${e} error:`,i),__privateGet(this,n).call(this,async()=>{__privateGet(this,r).has(t)&&await __privateMethod(this,_,d).call(this,t,e)},__privateGet(this,a))},l=function(t,r){const s=__privateGet(this,e).channel(r);return s.on("broadcast",{event:"*"},__privateMethod(this,_,o).bind(this)),s},d=async function(t,e){console.log(`Attempting to reconnect to ${e}`);try{const s=await this.getRunWithStates(t);__privateMethod(this,_,h).call(this,t,s);const a=__privateMethod(this,_,l).call(this,t,e);a.on("system",{event:"subscribed"},()=>{console.log(`Reconnected and subscribed to channel ${e}`)}),a.on("system",{event:"closed"},()=>{console.log(`Reconnected channel ${e} closed`)}),a.on("system",{event:"error"},r=>__privateMethod(this,_,u).call(this,t,e,a,r.error)),a.subscribe(),__privateGet(this,r).set(t,a)}catch(s){console.error(`Failed to reconnect to ${e}:`,s)}},h=function(t,e){if(!e||!e.run)return;const r={event_type:`run:${e.run.status}`,...e.run};if(__privateGet(this,s).emit("runEvent",r),e.steps&&Array.isArray(e.steps))for(const a of e.steps){const t={event_type:`step:${a.status}`,...a};__privateGet(this,s).emit("stepEvent",t)}},c=new WeakMap,v=function(t){const e=__privateGet(this,r).get(t);e&&(e.unsubscribe(),__privateGet(this,r).delete(t),__privateGet(this,c).delete(t))};class V{constructor(t){__privateAdd(this,w),__privateAdd(this,f),__privateAdd(this,m,O()),__privateAdd(this,g,{[L.Created]:0,[L.Started]:1,[L.Completed]:2,[L.Failed]:3}),__privateSet(this,f,t)}get run_id(){return __privateGet(this,f).run_id}get step_slug(){return __privateGet(this,f).step_slug}get status(){return __privateGet(this,f).status}get started_at(){return __privateGet(this,f).started_at}get completed_at(){return __privateGet(this,f).completed_at}get failed_at(){return __privateGet(this,f).failed_at}get output(){return __privateGet(this,f).output}get error(){return __privateGet(this,f).error}get error_message(){return __privateGet(this,f).error_message}on(t,e){return __privateGet(this,m).on(t,e)}waitForStatus(t,e){const r=(null==e?void 0:e.timeoutMs)??3e5,{signal:s}=e||{};return this.status===t?Promise.resolve(this):new Promise((e,a)=>{let i,n,_=!1;if(r>0&&(i=setTimeout(()=>{_||(_=!0,o(),a(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${t}'`)))},r)),s){const e=()=>{_||(_=!0,i&&clearTimeout(i),o(),a(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${t}'`)))};s.addEventListener("abort",e),n=()=>{s.removeEventListener("abort",e)}}const o=this.on("*",r=>{if(r.status===t){if(_)return;_=!0,i&&clearTimeout(i),n&&n(),o(),e(this)}})})}applySnapshot(t){__privateGet(this,f).status=t.status,__privateGet(this,f).started_at=t.started_at?new Date(t.started_at):null,__privateGet(this,f).completed_at=t.completed_at?new Date(t.completed_at):null,__privateGet(this,f).failed_at=t.failed_at?new Date(t.failed_at):null,__privateGet(this,f).error_message=t.error_message,__privateGet(this,f).error=t.error_message?new Error(t.error_message):null}updateState(t){if(t.step_slug!==__privateGet(this,f).step_slug)return!1;if(t.run_id!==__privateGet(this,f).run_id)return!1;if(!__privateMethod(this,w,G).call(this,__privateGet(this,f).status,t.status))return!1;switch(t.status){case L.Started:__privateSet(this,f,{...__privateGet(this,f),status:L.Started,started_at:"string"==typeof t.started_at?new Date(t.started_at):new Date}),__privateGet(this,m).emit("started",t);break;case L.Completed:__privateSet(this,f,{...__privateGet(this,f),status:L.Completed,completed_at:"string"==typeof t.completed_at?new Date(t.completed_at):new Date,output:t.output}),__privateGet(this,m).emit("completed",t);break;case L.Failed:__privateSet(this,f,{...__privateGet(this,f),status:L.Failed,failed_at:"string"==typeof t.failed_at?new Date(t.failed_at):new Date,error_message:"string"==typeof t.error_message?t.error_message:"Unknown error",error:new Error("string"==typeof t.error_message?t.error_message:"Unknown error")}),__privateGet(this,m).emit("failed",t);break;default:return!1}return __privateGet(this,m).emit("*",t),!0}}f=new WeakMap,m=new WeakMap,g=new WeakMap,w=new WeakSet,G=function(t,e){if(t===L.Completed||t===L.Failed)return!1;const r=__privateGet(this,g)[t];return __privateGet(this,g)[e]>r};class B{constructor(t){__privateAdd(this,A),__privateAdd(this,y),__privateAdd(this,S,O()),__privateAdd(this,b,new Map),__privateAdd(this,E,{[q.Started]:0,[q.Completed]:1,[q.Failed]:2}),__privateAdd(this,M,!1),__privateAdd(this,k,0),__privateSet(this,y,t)}get run_id(){return __privateGet(this,y).run_id}get flow_slug(){return __privateGet(this,y).flow_slug}get status(){return __privateGet(this,y).status}get started_at(){return __privateGet(this,y).started_at}get completed_at(){return __privateGet(this,y).completed_at}get failed_at(){return __privateGet(this,y).failed_at}get input(){return __privateGet(this,y).input}get output(){return __privateGet(this,y).output}get error(){return __privateGet(this,y).error}get error_message(){return __privateGet(this,y).error_message}get remaining_steps(){return __privateGet(this,y).remaining_steps}on(t,e){__privateWrapper(this,k)._++;const r=__privateGet(this,S).on(t,e);return()=>{r(),__privateWrapper(this,k)._--,__privateMethod(this,A,C).call(this)}}step(t){const e=__privateGet(this,b).get(t);if(e)return e;const r=new V({run_id:this.run_id,step_slug:t,status:L.Created,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null});return __privateGet(this,b).set(t,r),r}hasStep(t){return __privateGet(this,b).has(t)}waitForStatus(t,e){const r=(null==e?void 0:e.timeoutMs)??3e5,{signal:s}=e||{};return this.status===t?Promise.resolve(this):new Promise((e,a)=>{let i,n,_=!1;if(r>0&&(i=setTimeout(()=>{_||(_=!0,o(),a(new Error(`Timeout waiting for run ${this.run_id} to reach status '${t}'`)))},r)),s){const e=()=>{_||(_=!0,i&&clearTimeout(i),o(),a(new Error(`Aborted waiting for run ${this.run_id} to reach status '${t}'`)))};s.addEventListener("abort",e),n=()=>{s.removeEventListener("abort",e)}}const o=this.on("*",r=>{if(r.status===t){if(_)return;_=!0,i&&clearTimeout(i),n&&n(),o(),e(this)}})})}applySnapshot(t){__privateGet(this,y).status=t.status,__privateGet(this,y).input=t.input,__privateGet(this,y).output=t.output,__privateGet(this,y).started_at=t.started_at?new Date(t.started_at):null,__privateGet(this,y).completed_at=t.completed_at?new Date(t.completed_at):null,__privateGet(this,y).failed_at=t.failed_at?new Date(t.failed_at):null,__privateGet(this,y).remaining_steps=t.remaining_steps,__privateGet(this,y).error_message=null,__privateGet(this,y).error=null}updateState(t){if(t.run_id!==__privateGet(this,y).run_id)return!1;if(!__privateMethod(this,A,W).call(this,__privateGet(this,y).status,t.status))return!1;switch(t.status){case q.Started:__privateSet(this,y,{...__privateGet(this,y),status:q.Started,started_at:"string"==typeof t.started_at?new Date(t.started_at):new Date,remaining_steps:"remaining_steps"in t?Number(t.remaining_steps):__privateGet(this,y).remaining_steps}),__privateGet(this,S).emit("started",t);break;case q.Completed:__privateSet(this,y,{...__privateGet(this,y),status:q.Completed,completed_at:"string"==typeof t.completed_at?new Date(t.completed_at):new Date,output:t.output,remaining_steps:0}),__privateGet(this,S).emit("completed",t),__privateMethod(this,A,C).call(this);break;case q.Failed:__privateSet(this,y,{...__privateGet(this,y),status:q.Failed,failed_at:"string"==typeof t.failed_at?new Date(t.failed_at):new Date,error_message:"string"==typeof t.error_message?t.error_message:"Unknown error",error:new Error("string"==typeof t.error_message?t.error_message:"Unknown error")}),__privateGet(this,S).emit("failed",t),__privateMethod(this,A,C).call(this);break;default:return!1}return __privateGet(this,S).emit("*",t),!0}updateStepState(t,e){return this.step(t).updateState(e)}dispose(){__privateGet(this,M)||(__privateGet(this,b).clear(),__privateSet(this,S,O()),__privateSet(this,k,0),__privateSet(this,M,!0))}}y=new WeakMap,S=new WeakMap,b=new WeakMap,E=new WeakMap,M=new WeakMap,k=new WeakMap,A=new WeakSet,C=function(){__privateGet(this,M)||this.status!==q.Completed&&this.status!==q.Failed||0===__privateGet(this,k)&&this.dispose()},W=function(t,e){if(t===q.Completed||t===q.Failed)return!1;const r=__privateGet(this,E)[t];return __privateGet(this,E)[e]>r};class J{constructor(t,e={}){__privateAdd(this,D),__privateAdd(this,F),__privateAdd(this,R,new Map),__privateSet(this,D,t),__privateSet(this,F,new z(t,{stabilizationDelayMs:e.realtimeStabilizationDelayMs,schedule:e.schedule})),__privateGet(this,F).onRunEvent(t=>{const e=__privateGet(this,R).get(t.run_id);e&&e.updateState(function(t){switch(t.status){case q.Started:return{event_type:"run:started",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Started,started_at:t.started_at,remaining_steps:t.remaining_steps,input:t.input};case q.Completed:return{event_type:"run:completed",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Completed,completed_at:t.completed_at,output:t.output};case q.Failed:return{event_type:"run:failed",run_id:t.run_id,flow_slug:t.flow_slug,status:q.Failed,failed_at:t.failed_at,error_message:t.error_message}}}(t))}),__privateGet(this,F).onStepEvent(t=>{const e=__privateGet(this,R).get(t.run_id);if(e){const r=t.step_slug;e.step(r).updateState(function(t){switch(t.status){case L.Started:return{event_type:"step:started",run_id:t.run_id,step_slug:t.step_slug,status:L.Started,started_at:t.started_at};case L.Completed:return{event_type:"step:completed",run_id:t.run_id,step_slug:t.step_slug,status:L.Completed,completed_at:t.completed_at,output:t.output};case L.Failed:return{event_type:"step:failed",run_id:t.run_id,step_slug:t.step_slug,status:L.Failed,failed_at:t.failed_at,error_message:t.error_message}}}(t))}})}async startFlow(t,e,r){const s=r||j(),a={run_id:s,flow_slug:t,status:q.Started,input:e,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null,remaining_steps:-1},i=new B(a);__privateGet(this,R).set(s,i),await __privateGet(this,F).subscribeToRun(s);const{data:n,error:_}=await __privateGet(this,D).schema("pgflow").rpc("start_flow_with_states",{flow_slug:t,input:e,run_id:s});if(_)throw this.dispose(s),_;if(n.run&&i.applySnapshot(n.run),n.steps&&Array.isArray(n.steps))for(const o of n.steps)i.step(o.step_slug).applySnapshot(o);return i}dispose(t){const e=__privateGet(this,R).get(t);e&&(__privateGet(this,F).unsubscribe(t),e.dispose(),__privateGet(this,R).delete(t))}disposeAll(){for(const t of __privateGet(this,R).keys())this.dispose(t)}async fetchFlowDefinition(t){return __privateGet(this,F).fetchFlowDefinition(t)}onRunEvent(t){return __privateGet(this,F).onRunEvent(t)}onStepEvent(t){return __privateGet(this,F).onStepEvent(t)}async subscribeToRun(t){return await __privateGet(this,F).subscribeToRun(t)}async getRunWithStates(t){return __privateGet(this,F).getRunWithStates(t)}async getRun(t){const e=__privateGet(this,R).get(t);if(e)return e;try{const{run:e,steps:r}=await this.getRunWithStates(t);if(!e)return null;if(!e.run_id||!e.flow_slug||!e.status)throw new Error("Invalid run data: missing required fields");if(!Object.values(q).includes(e.status))throw new Error(`Invalid run data: invalid status '${e.status}'`);const s={run_id:e.run_id,flow_slug:e.flow_slug,status:e.status,input:e.input,output:null,error:null,error_message:null,started_at:null,completed_at:null,failed_at:null,remaining_steps:0},a=new B(s);if(a.applySnapshot(e),__privateGet(this,R).set(t,a),await __privateGet(this,F).subscribeToRun(t),r&&Array.isArray(r))for(const t of r){if(!t.step_slug||!t.status)throw new Error("Invalid step data: missing required fields");a.step(t.step_slug).applySnapshot(t)}return a}catch(r){if(console.error("Error getting run:",r),r instanceof Error&&(r.message.includes("Invalid run data")||r.message.includes("Invalid step data")))throw r;return null}}}return D=new WeakMap,F=new WeakMap,R=new WeakMap,t.FlowRunStatus=q,t.FlowStepStatus=L,t.PgflowClient=J,t.createClient=function(t){return new J(t)},t.isFlowRunCompletedEvent=function(t){return"completed"===t.status},t.isFlowRunEvent=function(t){return!!t&&"object"==typeof t&&"run_id"in t&&"flow_slug"in t&&!("step_slug"in t)&&"status"in t&&("started"===t.status||"completed"===t.status||"failed"===t.status)},t.isFlowRunFailedEvent=function(t){return"failed"===t.status},t.isFlowRunStartedEvent=function(t){return"started"===t.status},t.isStepCompletedEvent=function(t){return N(t)&&"completed"===t.status&&"event_type"in t&&"step:completed"===t.event_type},t.isStepEvent=N,t.isStepFailedEvent=function(t){return N(t)&&"failed"===t.status&&"event_type"in t&&"step:failed"===t.event_type},t.isStepStartedEvent=function(t){return N(t)&&"started"===t.status&&"event_type"in t&&"step:started"===t.event_type},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),t}({});
|
|
2
2
|
//# sourceMappingURL=pgflow-client.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pgflow-client.browser.js","sources":["../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/rng.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/stringify.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/native.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/v4.js","../src/lib/types.ts","../../../node_modules/.pnpm/nanoevents@7.0.1/node_modules/nanoevents/index.js","../src/lib/SupabaseBroadcastAdapter.ts","../src/lib/FlowStep.ts","../src/lib/FlowRun.ts","../src/lib/PgflowClient.ts","../src/lib/eventAdapters.ts","../src/browser.ts"],"sourcesContent":["// Unique ID creation requires a high quality random # generator. In the browser we therefore\n// require the crypto API and do not support built-in fallback to lower quality random number\n// generators (like Math.random()).\nlet getRandomValues;\nconst rnds8 = new Uint8Array(16);\nexport default function rng() {\n // lazy load so that environments that need to polyfill have a chance to do so\n if (!getRandomValues) {\n // getRandomValues needs to be invoked in a context where \"this\" is a Crypto implementation.\n getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);\n\n if (!getRandomValues) {\n throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n }\n }\n\n return getRandomValues(rnds8);\n}","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\n\nexport function unsafeStringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];\n}\n\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);\nexport default {\n randomUUID\n};","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\n\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return unsafeStringify(rnds);\n}\n\nexport default v4;","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type {\n Json,\n RunRow,\n StepStateRow,\n FlowRow,\n StepRow,\n} from '@pgflow/core';\nimport type { FlowRun } from './FlowRun.js';\n\n/**\n * Flow run status enum\n */\nexport enum FlowRunStatus {\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Flow run event data types - individual event shapes (no circular reference)\n */\nexport type FlowRunEventData<TFlow extends AnyFlow> = {\n started: {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n input: ExtractFlowInput<TFlow>;\n status: FlowRunStatus.Started;\n started_at: string;\n remaining_steps: number;\n };\n completed: {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n output: ExtractFlowOutput<TFlow>;\n status: FlowRunStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n error_message: string;\n status: FlowRunStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all flow run events (no circular reference)\n */\nexport type FlowRunEvent<TFlow extends AnyFlow> =\n FlowRunEventData<TFlow>[keyof FlowRunEventData<TFlow>];\n\n/**\n * Type guard to check if an unknown value is a valid FlowRunEvent\n */\nexport function isFlowRunEvent<TFlow extends AnyFlow>(\n value: unknown\n): value is FlowRunEvent<TFlow> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'flow_slug' in value &&\n !('step_slug' in value) &&\n 'status' in value &&\n (value.status === FlowRunStatus.Started ||\n value.status === FlowRunStatus.Completed ||\n value.status === FlowRunStatus.Failed)\n );\n}\n\n/**\n * Type guard for started events\n */\nexport function isFlowRunStartedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['started'] {\n return event.status === FlowRunStatus.Started;\n}\n\n/**\n * Type guard for completed events\n */\nexport function isFlowRunCompletedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['completed'] {\n return event.status === FlowRunStatus.Completed;\n}\n\n/**\n * Type guard for failed events\n */\nexport function isFlowRunFailedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['failed'] {\n return event.status === FlowRunStatus.Failed;\n}\n\n/**\n * Flow run event types matching nanoevents expectations (wildcard added separately)\n */\nexport type FlowRunEvents<TFlow extends AnyFlow> = {\n [K in keyof FlowRunEventData<TFlow>]: (\n event: FlowRunEventData<TFlow>[K]\n ) => void;\n} & {\n '*': (event: FlowRunEvent<TFlow>) => void;\n};\n\n/**\n * Flow step status enum\n */\nexport enum FlowStepStatus {\n Created = 'created',\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Step event data types (no circular reference)\n */\nexport type StepEventData<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n started: {\n event_type: 'step:started';\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus.Started;\n started_at: string;\n };\n completed: {\n event_type: 'step:completed';\n run_id: string;\n step_slug: TStepSlug;\n output: StepOutput<TFlow, TStepSlug>;\n status: FlowStepStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'step:failed';\n run_id: string;\n step_slug: TStepSlug;\n error_message: string;\n status: FlowStepStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all step events (no circular reference)\n */\nexport type StepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = StepEventData<TFlow, TStepSlug>[keyof StepEventData<TFlow, TStepSlug>];\n\n/**\n * Type guard to check if an unknown value is a valid StepEvent\n */\nexport function isStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(value: unknown): value is StepEvent<TFlow, TStepSlug> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'step_slug' in value &&\n 'status' in value &&\n (value.status === FlowStepStatus.Started ||\n value.status === FlowStepStatus.Completed ||\n value.status === FlowStepStatus.Failed)\n );\n}\n\n/**\n * Type guard for started step events\n */\nexport function isStepStartedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['started'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Started &&\n 'event_type' in event &&\n event.event_type === 'step:started'\n );\n}\n\n/**\n * Type guard for completed step events\n */\nexport function isStepCompletedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['completed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Completed &&\n 'event_type' in event &&\n event.event_type === 'step:completed'\n );\n}\n\n/**\n * Type guard for failed step events\n */\nexport function isStepFailedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['failed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Failed &&\n 'event_type' in event &&\n event.event_type === 'step:failed'\n );\n}\n\n/**\n * Step event types matching nanoevents expectations (wildcard added separately)\n */\nexport type StepEvents<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n [K in keyof StepEventData<TFlow, TStepSlug>]: (\n event: StepEventData<TFlow, TStepSlug>[K]\n ) => void;\n} & {\n '*': (event: StepEvent<TFlow, TStepSlug>) => void;\n};\n\n/**\n * Function returned by event subscriptions to remove the listener\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Broadcast run event types for Supabase realtime\n */\nexport type BroadcastRunStartedEvent = {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Started;\n input: Json;\n started_at: string;\n remaining_steps: number;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunCompletedEvent = {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunFailedEvent = {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Failed;\n error_message: string;\n failed_at: string;\n};\n\nexport type BroadcastRunEvent =\n | BroadcastRunStartedEvent\n | BroadcastRunCompletedEvent\n | BroadcastRunFailedEvent;\n\n/**\n * Broadcast step event types for Supabase realtime\n */\nexport type BroadcastStepStartedEvent = {\n event_type: 'step:started';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Started;\n started_at: string;\n remaining_tasks: number;\n remaining_deps: number;\n error_message?: string; // Adding for type compatibility\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepCompletedEvent = {\n event_type: 'step:completed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastStepFailedEvent = {\n event_type: 'step:failed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Failed;\n error_message: string;\n failed_at: string;\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepEvent =\n | BroadcastStepStartedEvent\n | BroadcastStepCompletedEvent\n | BroadcastStepFailedEvent;\n\n/**\n * Flow run state\n */\nexport type FlowRunState<TFlow extends AnyFlow> = {\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus;\n input: ExtractFlowInput<TFlow>;\n output: ExtractFlowOutput<TFlow> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n remaining_steps: number;\n};\n\n/**\n * Flow step state\n */\nexport type FlowStepState<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus;\n output: StepOutput<TFlow, TStepSlug> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n};\n\n/**\n * Interface for realtime updates (used by client library)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport interface IFlowRealtime<TFlow = unknown> {\n /**\n * Fetch flow definition metadata (looks up flows and steps tables)\n */\n fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }>;\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe;\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe;\n\n /**\n * Subscribe to a flow run's events\n */\n subscribeToRun(run_id: string): Promise<Unsubscribe>;\n\n /**\n * Fetch current state of a run and its steps\n */\n getRunWithStates(\n run_id: string\n ): Promise<{ run: RunRow; steps: StepStateRow[] }>;\n}\n\n/**\n * Generic base interface for flow runs that uses proper event types\n */\nexport interface FlowRunBase<TEvt = unknown> {\n readonly run_id: string;\n updateState(event: TEvt): boolean;\n step(stepSlug: string): FlowStepBase<unknown>;\n hasStep(stepSlug: string): boolean;\n dispose(): void;\n}\n\n/**\n * Generic base interface for flow steps that uses proper event types\n */\nexport interface FlowStepBase<TEvt = unknown> {\n updateState(event: TEvt): boolean;\n}\n\n/**\n * Utility type for broadcast events\n */\nexport type BroadcastEvent = BroadcastRunEvent | BroadcastStepEvent;\n\n/**\n * Composite interface for client\n */\nexport interface IFlowClient<TFlow extends AnyFlow = AnyFlow>\n extends IFlowRealtime<TFlow> {\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>>;\n\n /**\n * Get a flow run by ID\n *\n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n getRun<TSpecificFlow extends TFlow = TFlow>(\n run_id: string\n ): Promise<FlowRun<TSpecificFlow> | null>;\n}\n","export let createNanoEvents = () => ({\n events: {},\n emit(event, ...args) {\n let callbacks = this.events[event] || []\n for (let i = 0, length = callbacks.length; i < length; i++) {\n callbacks[i](...args)\n }\n },\n on(event, cb) {\n this.events[event]?.push(cb) || (this.events[event] = [cb])\n return () => {\n this.events[event] = this.events[event]?.filter(i => cb !== i)\n }\n }\n})\n","import type { RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';\nimport type { FlowRow, StepRow, RunRow, StepStateRow } from '@pgflow/core';\nimport { createNanoEvents } from 'nanoevents';\nimport type {\n IFlowRealtime,\n BroadcastRunEvent,\n BroadcastStepEvent,\n Unsubscribe,\n} from './types.js';\n\n// Define the events interface for the adapter\ninterface AdapterEvents {\n runEvent: (event: BroadcastRunEvent) => void;\n stepEvent: (event: BroadcastStepEvent) => void;\n}\n\n/**\n * Adapter to handle realtime communication with Supabase\n */\nexport class SupabaseBroadcastAdapter implements IFlowRealtime {\n #supabase: SupabaseClient;\n #channels: Map<string, RealtimeChannel> = new Map();\n #emitter = createNanoEvents<AdapterEvents>();\n #reconnectionDelay: number;\n #stabilizationDelay: number;\n #schedule: typeof setTimeout;\n\n\n /**\n * Creates a new instance of SupabaseBroadcastAdapter\n *\n * @param supabase - Supabase client instance\n */\n constructor(\n supabase: SupabaseClient,\n opts: {\n reconnectDelayMs?: number;\n stabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabase;\n this.#reconnectionDelay = opts.reconnectDelayMs ?? 2000;\n this.#stabilizationDelay = opts.stabilizationDelayMs ?? 300;\n this.#schedule = opts.schedule ?? setTimeout;\n }\n \n /**\n * Handle broadcast messages from Supabase\n * @param payload - The message payload\n */\n #handleBroadcastMessage(msg: { \n event: string; \n payload: BroadcastRunEvent | BroadcastStepEvent;\n }): void {\n const { event, payload } = msg;\n \n // run_id is already inside the payload coming from the database trigger\n // so just preserve it without overwriting\n const eventData = payload;\n\n // Auto-parse JSON strings in broadcast data (realtime sends JSONB as strings)\n this.#parseJsonFields(eventData);\n\n if (event.startsWith('run:')) {\n // Handle run events\n this.#emitter.emit('runEvent', eventData as BroadcastRunEvent);\n } else if (event.startsWith('step:')) {\n // Handle step events\n this.#emitter.emit('stepEvent', eventData as BroadcastStepEvent);\n }\n }\n\n /**\n * Parse JSON string fields in broadcast event data\n * @param eventData - The event data object to parse\n */\n #parseJsonFields(eventData: Record<string, unknown>): void {\n // Parse output field if it's a JSON string\n if ('output' in eventData && typeof eventData.output === 'string') {\n try {\n eventData.output = JSON.parse(eventData.output);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n \n // Parse input field if it's a JSON string\n if ('input' in eventData && typeof eventData.input === 'string') {\n try {\n eventData.input = JSON.parse(eventData.input);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n }\n\n \n /**\n * Handle channel errors and reconnection\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @param channel - The RealtimeChannel instance\n * @param error - The error object\n */\n async #handleChannelError(\n run_id: string,\n channelName: string,\n channel: RealtimeChannel,\n error: unknown\n ): Promise<void> {\n console.error(`Channel ${channelName} error:`, error);\n \n // Schedule reconnection attempt\n this.#schedule(async () => {\n if (this.#channels.has(run_id)) {\n await this.#reconnectChannel(run_id, channelName);\n }\n }, this.#reconnectionDelay);\n }\n \n /**\n * Creates and configures a channel for a run\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @returns The configured RealtimeChannel\n */\n #createAndConfigureChannel(run_id: string, channelName: string): RealtimeChannel {\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Note: Lifecycle event listeners (subscribed, closed, error) are handled \n // by the calling code to avoid conflicts when multiple listeners try to \n // handle the same events.\n \n return channel;\n }\n \n /**\n * Reconnect to a channel and refresh state\n * @param run_id - The run ID\n * @param channelName - The channel name\n */\n async #reconnectChannel(\n run_id: string,\n channelName: string\n ): Promise<void> {\n console.log(`Attempting to reconnect to ${channelName}`);\n \n try {\n // Fetch current state to avoid missing events during disconnection\n const currentState = await this.getRunWithStates(run_id);\n \n // Update state based on current data\n this.#refreshStateFromSnapshot(run_id, currentState);\n \n // Create a new channel as the old one can't be reused\n const newChannel = this.#createAndConfigureChannel(run_id, channelName);\n \n // Set up lifecycle event handlers for reconnection\n newChannel.on('system', { event: 'subscribed' }, () => {\n console.log(`Reconnected and subscribed to channel ${channelName}`);\n });\n \n newChannel.on('system', { event: 'closed' }, () => {\n console.log(`Reconnected channel ${channelName} closed`);\n });\n \n newChannel.on('system', { event: 'error' }, (payload) => \n this.#handleChannelError(run_id, channelName, newChannel, payload.error)\n );\n \n // Subscribe and update the channels map\n newChannel.subscribe();\n this.#channels.set(run_id, newChannel);\n } catch (e) {\n console.error(`Failed to reconnect to ${channelName}:`, e);\n }\n }\n \n /**\n * Refresh client state from a state snapshot\n * @param run_id - The run ID\n * @param state - The state snapshot\n */\n #refreshStateFromSnapshot(\n run_id: string,\n state: { run: RunRow; steps: StepStateRow[] } | null\n ): void {\n if (!state || !state.run) return;\n \n // Create proper run event with correct event_type\n const runEvent: BroadcastRunEvent = {\n event_type: `run:${state.run.status}`,\n ...state.run\n } as unknown as BroadcastRunEvent;\n \n // Emit run event\n this.#emitter.emit('runEvent', runEvent);\n \n // Emit events for each step state\n if (state.steps && Array.isArray(state.steps)) {\n for (const step of state.steps) {\n // Create proper step event with correct event_type\n const stepEvent: BroadcastStepEvent = {\n event_type: `step:${step.status}`,\n ...step\n } as unknown as BroadcastStepEvent;\n \n // Emit step event\n this.#emitter.emit('stepEvent', stepEvent);\n }\n }\n }\n\n /**\n * Fetches flow definition metadata from the database\n *\n * @param flow_slug - Flow slug to fetch\n */\n async fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }> {\n // Fetch flow details and steps in parallel\n const [flowResult, stepsResult] = await Promise.all([\n this.#supabase\n .schema('pgflow')\n .from('flows')\n .select('*')\n .eq('flow_slug', flow_slug)\n .single(),\n this.#supabase\n .schema('pgflow')\n .from('steps')\n .select('*')\n .eq('flow_slug', flow_slug)\n .order('step_index', { ascending: true })\n ]);\n\n // Handle flow result\n if (flowResult.error) throw flowResult.error;\n if (!flowResult.data) throw new Error(`Flow \"${flow_slug}\" not found`);\n\n // Handle steps result\n if (stepsResult.error) throw stepsResult.error;\n \n // Ensure steps is always an array, even if it's null or undefined\n const stepsArray = Array.isArray(stepsResult.data) ? stepsResult.data : [];\n\n return {\n flow: flowResult.data as FlowRow,\n steps: stepsArray as StepRow[],\n };\n }\n\n /**\n * Registers a callback for run events\n *\n * @param callback - Function to call when run events are received\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('runEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from run event - emitter may have been disposed', e);\n }\n };\n }\n\n /**\n * Registers a callback for step events\n *\n * @param callback - Function to call when step events are received\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('stepEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from step event - emitter may have been disposed', e);\n }\n };\n }\n\n // Store unsubscribe functions per run ID for reference equality\n #unsubscribeFunctions: Map<string, () => void> = new Map();\n\n /**\n * Subscribes to a flow run's events\n *\n * @param run_id - Run ID to subscribe to\n * @returns Function to unsubscribe\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n const channelName = `pgflow:run:${run_id}`;\n\n // If already subscribed, return the existing unsubscribe function\n if (this.#channels.has(run_id)) {\n const existingUnsubscribe = this.#unsubscribeFunctions.get(run_id);\n if (existingUnsubscribe) {\n return existingUnsubscribe;\n }\n // If channel exists but no unsubscribe function, something went wrong\n // Let's clean up and recreate\n this.#unsubscribe(run_id);\n }\n\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Set up error handling\n channel.on('system', { event: 'closed' }, () => {\n console.log(`Channel ${channelName} closed`);\n });\n channel.on('system', { event: 'error' }, (payload) => {\n console.log(`Channel ${channelName} error:`, payload);\n this.#handleChannelError(run_id, channelName, channel, payload.error);\n });\n \n // Subscribe to channel and wait for confirmation (like the working realtime-send test)\n console.log(`Subscribing to channel ${channelName}...`);\n \n const subscriptionPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Subscription timeout for channel ${channelName}`));\n }, 20000); // Increased from 5s to 20s for slower CI environments\n \n channel.subscribe((status) => {\n console.log(`Channel ${channelName} subscription status:`, status);\n if (status === 'SUBSCRIBED') {\n clearTimeout(timeout);\n resolve();\n }\n // Don't reject on CHANNEL_ERROR - it's a transient state\n // Only reject on timeout\n });\n });\n \n // Wait for the 'SUBSCRIBED' acknowledgment to avoid race conditions\n await subscriptionPromise;\n\n // Stabilization delay - known Supabase Realtime limitation\n // The SUBSCRIBED event is emitted before backend routing is fully established.\n // This delay ensures the backend can receive messages sent immediately after subscription.\n // See: https://github.com/supabase/supabase-js/issues/1599\n await new Promise(resolve => this.#schedule(resolve, this.#stabilizationDelay));\n\n this.#channels.set(run_id, channel);\n\n const unsubscribe = () => this.unsubscribe(run_id);\n this.#unsubscribeFunctions.set(run_id, unsubscribe);\n return unsubscribe;\n }\n \n /**\n * Unsubscribes from a run's events\n * \n * @param run_id - Run ID to unsubscribe from\n */\n unsubscribe(run_id: string): void {\n this.#unsubscribe(run_id);\n }\n\n /**\n * Fetches current state of a run and its steps\n *\n * @param run_id - Run ID to fetch\n */\n async getRunWithStates(run_id: string): Promise<{\n run: RunRow;\n steps: StepStateRow[];\n }> {\n // Call the RPC function which returns a JSONB object\n const { data, error } = await this.#supabase\n .schema('pgflow')\n .rpc('get_run_with_states', { run_id });\n\n if (error) throw error;\n if (!data) throw new Error(`No data returned for run ${run_id}`);\n \n return data as { run: RunRow; steps: StepStateRow[] };\n }\n\n /**\n * Unsubscribes from a run's events\n *\n * @param run_id - Run ID to unsubscribe from\n */\n #unsubscribe(run_id: string): void {\n const channel = this.#channels.get(run_id);\n if (channel) {\n // Close the channel\n channel.unsubscribe();\n this.#channels.delete(run_id);\n \n // Also clean up the unsubscribe function reference\n this.#unsubscribeFunctions.delete(run_id);\n \n // We don't need to explicitly remove event listeners from the emitter\n // as they will be garbage collected when no longer referenced.\n // The event listeners are bound to specific callbacks provided by the client,\n // which will retain references if they're still in use.\n }\n }\n}\n","import { createNanoEvents } from 'nanoevents';\nimport type { AnyFlow, ExtractFlowSteps, StepOutput } from '@pgflow/dsl';\nimport { FlowStepStatus } from './types.js';\nimport type { \n FlowStepState, \n StepEvents, \n Unsubscribe, \n FlowStepBase,\n StepEvent\n} from './types.js';\n\n/**\n * Represents a single step in a flow run\n */\nexport class FlowStep<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> implements FlowStepBase<StepEvent<TFlow, TStepSlug>> {\n #state: FlowStepState<TFlow, TStepSlug>;\n #events = createNanoEvents<StepEvents<TFlow, TStepSlug>>();\n #statusPrecedence: Record<FlowStepStatus, number> = {\n [FlowStepStatus.Created]: 0,\n [FlowStepStatus.Started]: 1,\n [FlowStepStatus.Completed]: 2,\n [FlowStepStatus.Failed]: 3,\n };\n\n /**\n * Creates a new FlowStep instance\n * \n * @param initialState - Initial state for the step\n */\n constructor(initialState: FlowStepState<TFlow, TStepSlug>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID this step belongs to\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the step slug\n */\n get step_slug(): TStepSlug {\n return this.#state.step_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowStepStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the step output\n */\n get output(): StepOutput<TFlow, TStepSlug> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Register an event handler for a step event\n * \n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof StepEvents<TFlow, TStepSlug>>(\n event: E,\n callback: StepEvents<TFlow, TStepSlug>[E]\n ): Unsubscribe {\n return this.#events.on(event, callback);\n }\n\n /**\n * Wait for the step to reach a specific status\n * \n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the step instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowStepStatus.Started | FlowStepStatus.Completed | FlowStepStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n \n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n }, timeoutMs);\n }\n \n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n };\n \n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n \n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').StepStateRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowStepStatus;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.error_message = row.error_message;\n this.#state.error = row.error_message ? new Error(row.error_message) : null;\n // Note: output is not stored in step_states table, remains null\n }\n\n /**\n * Updates the step state based on an event\n *\n * @internal This method is only intended for use by FlowRun and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: StepEvent<TFlow, TStepSlug>): boolean {\n // Validate event is for this step\n if (event.step_slug !== this.#state.step_slug) {\n return false;\n }\n \n // Validate event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n \n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowStepStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Started,\n started_at: typeof event.started_at === 'string' ? new Date(event.started_at) : new Date(),\n };\n this.#events.emit('started', event);\n break;\n\n case FlowStepStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Completed,\n completed_at: typeof event.completed_at === 'string' ? new Date(event.completed_at) : new Date(),\n output: event.output as StepOutput<TFlow, TStepSlug>,\n };\n this.#events.emit('completed', event);\n break;\n\n case FlowStepStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Failed,\n failed_at: typeof event.failed_at === 'string' ? new Date(event.failed_at) : new Date(),\n error_message: typeof event.error_message === 'string' ? event.error_message : 'Unknown error',\n error: new Error(typeof event.error_message === 'string' ? event.error_message : 'Unknown error'),\n };\n this.#events.emit('failed', event);\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n \n return true;\n }\n\n /**\n * Determines if a status should be updated based on precedence\n * \n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(currentStatus: FlowStepStatus, newStatus: FlowStepStatus): boolean {\n // Don't allow changes to terminal states\n if (currentStatus === FlowStepStatus.Completed || currentStatus === FlowStepStatus.Failed) {\n return false; // Terminal states should never change\n }\n \n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n}","import { createNanoEvents } from 'nanoevents';\nimport type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n} from '@pgflow/dsl';\nimport { FlowRunStatus, FlowStepStatus } from './types.js';\nimport type {\n FlowRunState,\n FlowRunEvents,\n Unsubscribe,\n FlowRunBase,\n FlowStepBase,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\nimport { FlowStep } from './FlowStep.js';\n\n/**\n * Represents a single execution of a flow\n */\nexport class FlowRun<TFlow extends AnyFlow>\n implements FlowRunBase<FlowRunEvent<TFlow>>\n{\n #state: FlowRunState<TFlow>;\n #events = createNanoEvents<FlowRunEvents<TFlow>>();\n #steps = new Map<string, FlowStepBase>();\n #statusPrecedence: Record<FlowRunStatus, number> = {\n [FlowRunStatus.Started]: 0,\n [FlowRunStatus.Completed]: 1,\n [FlowRunStatus.Failed]: 2,\n };\n #disposed = false;\n\n /**\n * Creates a new FlowRun instance\n *\n * @param initialState - Initial state for the run\n */\n constructor(initialState: FlowRunState<TFlow>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the flow slug\n */\n get flow_slug(): string {\n return this.#state.flow_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowRunStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the flow input\n */\n get input(): ExtractFlowInput<TFlow> {\n return this.#state.input;\n }\n\n /**\n * Get the flow output\n */\n get output(): ExtractFlowOutput<TFlow> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Get the number of remaining steps\n */\n get remaining_steps(): number {\n return this.#state.remaining_steps;\n }\n\n /**\n * Register an event handler for a run event\n *\n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof FlowRunEvents<TFlow>>(\n event: E,\n callback: FlowRunEvents<TFlow>[E]\n ): Unsubscribe {\n this.#listenerCount++;\n\n // Wrap the unsubscribe function to track listener count\n const unsubscribe = this.#events.on(event, callback);\n\n return () => {\n unsubscribe();\n this.#listenerCount--;\n this.#checkAutoDispose();\n };\n }\n\n /**\n * Get a FlowStep instance for a specific step\n *\n * @param stepSlug - Step slug to get\n * @returns FlowStep instance for the specified step\n */\n step<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug\n ): FlowStep<TFlow, TStepSlug> {\n // Look up if we already have this step cached\n const existingStep = this.#steps.get(stepSlug as string);\n if (existingStep) {\n // Safe to cast since we only store steps with matching slugs\n return existingStep as unknown as FlowStep<TFlow, TStepSlug>;\n }\n\n // Create a new step instance with default state\n const step = new FlowStep<TFlow, TStepSlug>({\n run_id: this.run_id,\n step_slug: stepSlug,\n status: FlowStepStatus.Created,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n });\n\n // Cache the step\n this.#steps.set(\n stepSlug as string,\n step as FlowStepBase<StepEvent<TFlow, TStepSlug>>\n );\n\n return step;\n }\n\n /**\n * Check if this run has a specific step\n *\n * @param stepSlug - Step slug to check\n * @returns true if the step exists, false otherwise\n */\n hasStep(stepSlug: string): boolean {\n // Check if we have this step cached\n return this.#steps.has(stepSlug);\n }\n\n /**\n * Wait for the run to reach a specific status\n *\n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the run instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowRunStatus.Completed | FlowRunStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n\n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(\n new Error(\n `Timeout waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n }, timeoutMs);\n }\n\n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(\n new Error(\n `Aborted waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n };\n\n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n\n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').RunRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowRunStatus;\n this.#state.input = row.input as ExtractFlowInput<TFlow>;\n this.#state.output = row.output as ExtractFlowOutput<TFlow> | null;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.remaining_steps = row.remaining_steps;\n this.#state.error_message = null; // Database doesn't have error_message for runs\n this.#state.error = null;\n }\n\n /**\n * Updates the run state based on an event\n *\n * @internal This method is only intended for use by PgflowClient and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: FlowRunEvent<TFlow>): boolean {\n // Validate the event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n\n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowRunStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Started,\n started_at:\n typeof event.started_at === 'string'\n ? new Date(event.started_at)\n : new Date(),\n remaining_steps:\n 'remaining_steps' in event\n ? Number(event.remaining_steps)\n : this.#state.remaining_steps,\n };\n this.#events.emit('started', event);\n break;\n\n case FlowRunStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Completed,\n completed_at:\n typeof event.completed_at === 'string'\n ? new Date(event.completed_at)\n : new Date(),\n output: event.output as ExtractFlowOutput<TFlow>,\n remaining_steps: 0,\n };\n this.#events.emit('completed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n case FlowRunStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Failed,\n failed_at:\n typeof event.failed_at === 'string'\n ? new Date(event.failed_at)\n : new Date(),\n error_message:\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error',\n error: new Error(\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error'\n ),\n };\n this.#events.emit('failed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n\n return true;\n }\n\n /**\n * Updates a step state based on an event\n *\n * @param stepSlug - Step slug to update\n * @param event - Event data to update the step with\n * @returns true if the state was updated, false otherwise\n */\n updateStepState<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug,\n event: StepEvent<TFlow, TStepSlug>\n ): boolean {\n const step = this.step(stepSlug);\n return step.updateState(event);\n }\n\n // Track number of listeners\n #listenerCount = 0;\n\n /**\n * Checks if auto-dispose should be triggered (when in terminal state with no listeners)\n */\n #checkAutoDispose(): void {\n // Don't auto-dispose multiple times\n if (this.#disposed) {\n return;\n }\n\n // Only auto-dispose in terminal states\n if (\n this.status !== FlowRunStatus.Completed &&\n this.status !== FlowRunStatus.Failed\n ) {\n return;\n }\n\n // If there are no listeners, auto-dispose\n if (this.#listenerCount === 0) {\n this.dispose();\n }\n }\n\n /**\n * Determines if a status should be updated based on precedence\n *\n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(\n currentStatus: FlowRunStatus,\n newStatus: FlowRunStatus\n ): boolean {\n // Don't allow changes to terminal states\n if (\n currentStatus === FlowRunStatus.Completed ||\n currentStatus === FlowRunStatus.Failed\n ) {\n return false; // Terminal states should never change\n }\n\n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n\n /**\n * Clean up all resources held by this run\n */\n dispose(): void {\n if (this.#disposed) {\n return;\n }\n\n // Clear the map to allow garbage collection of steps\n this.#steps.clear();\n\n // Create a new events object - this effectively clears all listeners\n // without accessing the private internals of nanoevents\n this.#events = createNanoEvents<FlowRunEvents<TFlow>>();\n this.#listenerCount = 0;\n\n // Mark as disposed\n this.#disposed = true;\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';\nimport { FlowRunStatus } from './types.js';\nimport type { \n IFlowClient, \n FlowRunState, \n BroadcastRunEvent, \n BroadcastStepEvent, \n Unsubscribe, \n FlowRunBase\n} from './types.js';\nimport { SupabaseBroadcastAdapter } from './SupabaseBroadcastAdapter.js';\nimport { FlowRun } from './FlowRun.js';\nimport { toTypedRunEvent, toTypedStepEvent } from './eventAdapters.js';\n\n/**\n * Client for interacting with pgflow\n */\nexport class PgflowClient<TFlow extends AnyFlow = AnyFlow> implements IFlowClient<TFlow> {\n #supabase: SupabaseClient;\n #realtimeAdapter: SupabaseBroadcastAdapter;\n // Use the widest event type - keeps the compiler happy but\n // still provides the structural API we need (updateState/step/...)\n #runs = new Map<string, FlowRunBase<unknown>>();\n\n /**\n * Creates a new PgflowClient instance\n *\n * @param supabaseClient - Supabase client instance\n * @param opts - Optional configuration\n */\n constructor(\n supabaseClient: SupabaseClient,\n opts: {\n realtimeStabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabaseClient;\n this.#realtimeAdapter = new SupabaseBroadcastAdapter(supabaseClient, {\n stabilizationDelayMs: opts.realtimeStabilizationDelayMs,\n schedule: opts.schedule,\n });\n\n // Set up global event listeners - properly typed\n this.#realtimeAdapter.onRunEvent((event: BroadcastRunEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Convert broadcast event to typed event before updating state\n run.updateState(toTypedRunEvent(event));\n }\n });\n\n this.#realtimeAdapter.onStepEvent((event: BroadcastStepEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Always materialize the step before updating to avoid event loss\n // This ensures we cache all steps even if they were never explicitly requested\n const stepSlug = event.step_slug;\n run.step(stepSlug).updateState(toTypedStepEvent(event));\n }\n });\n }\n\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n async startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>> {\n // Generate a run_id if not provided\n const id = run_id || uuidv4();\n\n // Create initial state for the flow run\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: id,\n flow_slug,\n status: FlowRunStatus.Started,\n input: input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: -1, // Use -1 to indicate unknown until first snapshot arrives\n };\n\n // Create the flow run instance\n const run = new FlowRun<TSpecificFlow>(initialState);\n\n // Store the run\n this.#runs.set(id, run);\n\n // Set up subscription for run and step events (wait for subscription confirmation)\n await this.#realtimeAdapter.subscribeToRun(id);\n\n // Start the flow with the predetermined run_id (only after subscription is ready)\n const { data, error } = await this.#supabase.schema('pgflow').rpc('start_flow_with_states', {\n flow_slug: flow_slug,\n input: input as Record<string, unknown>,\n run_id: id\n });\n\n if (error) {\n // Clean up subscription and run instance\n this.dispose(id);\n throw error;\n }\n\n // Apply the run state snapshot (no events)\n if (data.run) {\n run.applySnapshot(data.run);\n }\n\n // Apply step state snapshots (no events)\n if (data.steps && Array.isArray(data.steps)) {\n for (const stepState of data.steps) {\n run.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n\n return run;\n }\n\n /**\n * Dispose a specific flow run\n *\n * @param runId - Run ID to dispose\n */\n dispose(runId: string): void {\n const run = this.#runs.get(runId);\n if (run) {\n // First unsubscribe from the realtime adapter\n this.#realtimeAdapter.unsubscribe(runId);\n \n // Then dispose the run\n run.dispose();\n \n // Finally remove from the runs map\n this.#runs.delete(runId);\n }\n }\n\n /**\n * Dispose all flow runs\n */\n disposeAll(): void {\n for (const runId of this.#runs.keys()) {\n this.dispose(runId);\n }\n }\n\n // Delegate IFlowRealtime methods to the adapter\n\n /**\n * Fetch flow definition metadata\n */\n async fetchFlowDefinition(flow_slug: string) {\n return this.#realtimeAdapter.fetchFlowDefinition(flow_slug);\n }\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onRunEvent(callback);\n }\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onStepEvent(callback);\n }\n\n /**\n * Subscribe to a flow run's events\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n return await this.#realtimeAdapter.subscribeToRun(run_id);\n }\n\n /**\n * Fetch current state of a run and its steps\n */\n async getRunWithStates(run_id: string) {\n return this.#realtimeAdapter.getRunWithStates(run_id);\n }\n \n /**\n * Get a flow run by ID\n * \n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n async getRun<TSpecificFlow extends TFlow = TFlow>(run_id: string): Promise<FlowRun<TSpecificFlow> | null> {\n // Check if we already have this run cached\n const existingRun = this.#runs.get(run_id);\n if (existingRun) {\n return existingRun as FlowRun<TSpecificFlow>;\n }\n \n try {\n // Fetch the run state from the database\n const { run, steps } = await this.getRunWithStates(run_id);\n \n if (!run) {\n return null;\n }\n \n // Validate required fields\n if (!run.run_id || !run.flow_slug || !run.status) {\n throw new Error('Invalid run data: missing required fields');\n }\n\n // Validate status is a valid FlowRunStatus\n const validStatuses = Object.values(FlowRunStatus);\n if (!validStatuses.includes(run.status as FlowRunStatus)) {\n throw new Error(`Invalid run data: invalid status '${run.status}'`);\n }\n\n // Create flow run with minimal initial state\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: run.run_id,\n flow_slug: run.flow_slug,\n status: run.status as FlowRunStatus,\n input: run.input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: 0,\n };\n\n // Create the flow run instance\n const flowRun = new FlowRun<TSpecificFlow>(initialState);\n\n // Apply the complete state from database snapshot\n flowRun.applySnapshot(run);\n \n // Store the run\n this.#runs.set(run_id, flowRun);\n \n // Set up subscription for run and step events\n await this.#realtimeAdapter.subscribeToRun(run_id);\n \n // Initialize steps from snapshot\n if (steps && Array.isArray(steps)) {\n for (const stepState of steps) {\n // Validate step has required fields\n if (!stepState.step_slug || !stepState.status) {\n throw new Error('Invalid step data: missing required fields');\n }\n\n // Apply snapshot state directly (no events)\n flowRun.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n \n return flowRun;\n } catch (error) {\n console.error('Error getting run:', error);\n // Re-throw if it's a validation error\n if (error instanceof Error && (error.message.includes('Invalid run data') || error.message.includes('Invalid step data'))) {\n throw error;\n }\n return null;\n }\n }\n \n}\n","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type { RunRow, StepStateRow } from '@pgflow/core';\nimport {\n FlowStepStatus,\n FlowRunStatus,\n} from './types.js';\nimport type {\n BroadcastRunEvent,\n BroadcastStepEvent,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\n\n/**\n * Convert a broadcast run event to a typed run event\n */\nexport function toTypedRunEvent<TFlow extends AnyFlow>(\n evt: BroadcastRunEvent\n): FlowRunEvent<TFlow> {\n switch (evt.status) {\n case FlowRunStatus.Started:\n return {\n event_type: 'run:started',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Started,\n started_at: evt.started_at,\n remaining_steps: evt.remaining_steps,\n input: evt.input as ExtractFlowInput<TFlow>,\n };\n case FlowRunStatus.Completed:\n return {\n event_type: 'run:completed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as ExtractFlowOutput<TFlow>,\n };\n case FlowRunStatus.Failed:\n return {\n event_type: 'run:failed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a broadcast step event to a typed step event\n */\nexport function toTypedStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(evt: BroadcastStepEvent): StepEvent<TFlow, TStepSlug> {\n switch (evt.status) {\n case FlowStepStatus.Started:\n return {\n event_type: 'step:started',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: evt.started_at,\n };\n case FlowStepStatus.Completed:\n return {\n event_type: 'step:completed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as StepOutput<TFlow, TStepSlug>,\n };\n case FlowStepStatus.Failed:\n return {\n event_type: 'step:failed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a database run row to a typed run event\n */\nexport function runRowToTypedEvent<TFlow extends AnyFlow>(\n row: RunRow\n): FlowRunEvent<TFlow> {\n switch (row.status) {\n case 'started':\n return {\n event_type: 'run:started',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Started,\n started_at: row.started_at!,\n remaining_steps: row.remaining_steps,\n input: row.input as ExtractFlowInput<TFlow>,\n };\n case 'completed':\n return {\n event_type: 'run:completed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: row.completed_at!,\n output: row.output as ExtractFlowOutput<TFlow>,\n };\n case 'failed':\n return {\n event_type: 'run:failed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: row.failed_at!,\n error_message: 'Flow failed', // Database doesn't have error_message for runs\n };\n default:\n throw new Error(`Unknown run status: ${row.status}`);\n }\n}\n\n/**\n * Convert a database step state row to a typed step event\n */\nexport function stepStateRowToTypedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(row: StepStateRow): StepEvent<TFlow, TStepSlug> {\n switch (row.status) {\n case 'created':\n case 'started':\n return {\n event_type: 'step:started',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: row.started_at!,\n };\n case 'completed':\n return {\n event_type: 'step:completed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: row.completed_at!,\n output: {} as StepOutput<TFlow, TStepSlug>, // Database doesn't have output in step_states\n };\n case 'failed':\n return {\n event_type: 'step:failed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: row.failed_at!,\n error_message: row.error_message || 'Step failed',\n };\n default:\n throw new Error(`Unknown step status: ${row.status}`);\n }\n}","// Browser-specific entry point\nexport { PgflowClient } from './lib/PgflowClient.js';\nexport { FlowRunStatus, FlowStepStatus } from './lib/types.js';\nexport * from './lib/types.js';\n\n// Import the PgflowClient constructor for the factory\nimport { PgflowClient } from './lib/PgflowClient.js';\nimport type { SupabaseClient } from '@supabase/supabase-js';\n\n// Factory function for creating PgflowClient instances\nexport function createClient(supabaseClient: SupabaseClient) {\n return new PgflowClient(supabaseClient);\n}"],"names":["getRandomValues","rnds8","Uint8Array","rng","crypto","bind","Error","byteToHex","i","push","toString","slice","native","randomUUID","v4","options","buf","offset","rnds","random","arr","unsafeStringify","FlowRunStatus","FlowStepStatus","isStepEvent","value","status","createNanoEvents","events","emit","event","args","callbacks","this","length","on","cb","_a","filter","SupabaseBroadcastAdapter","constructor","supabase","opts","__privateAdd","_SupabaseBroadcastAdapter_instances","_supabase","_channels","Map","_emitter","_reconnectionDelay","_stabilizationDelay","_schedule","_unsubscribeFunctions","__privateSet","reconnectDelayMs","stabilizationDelayMs","schedule","setTimeout","fetchFlowDefinition","flow_slug","flowResult","stepsResult","Promise","all","__privateGet","schema","from","select","eq","single","order","ascending","error","data","stepsArray","Array","isArray","flow","steps","onRunEvent","callback","unsubscribe","e","console","warn","onStepEvent","subscribeToRun","run_id","channelName","has","existingUnsubscribe","get","__privateMethod","call","channel","handleBroadcastMessage_fn","log","payload","handleChannelError_fn","subscriptionPromise","resolve","reject","timeout","subscribe","clearTimeout","set","getRunWithStates","rpc","WeakMap","WeakSet","msg","eventData","startsWith","parseJsonFields_fn","output","JSON","parse","input","async","reconnectChannel_fn","createAndConfigureChannel_fn","currentState","refreshStateFromSnapshot_fn","newChannel","state","run","runEvent","event_type","step","stepEvent","unsubscribe_fn","delete","FlowStep","initialState","_FlowStep_instances","_state","_events","_statusPrecedence","Created","Started","Completed","Failed","step_slug","started_at","completed_at","failed_at","error_message","waitForStatus","targetStatus","timeoutMs","signal","timeoutId","abortCleanup","cleanedUp","unbind","abortHandler","addEventListener","removeEventListener","applySnapshot","row","Date","updateState","shouldUpdateStatus_fn","currentStatus","newStatus","currentPrecedence","FlowRun","_FlowRun_instances","_steps","_disposed","_listenerCount","remaining_steps","__privateWrapper","_","checkAutoDispose_fn","stepSlug","existingStep","hasStep","Number","updateStepState","dispose","clear","PgflowClient","supabaseClient","_realtimeAdapter","_runs","realtimeStabilizationDelayMs","evt","toTypedRunEvent","toTypedStepEvent","startFlow","id","uuidv4","stepState","runId","disposeAll","keys","getRun","existingRun","Object","values","includes","flowRun","message"],"mappings":"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","x_google_ignoreList":[0,1,2,3,5]}
|
|
1
|
+
{"version":3,"file":"pgflow-client.browser.js","sources":["../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/rng.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/stringify.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/native.js","../../../node_modules/.pnpm/uuid@9.0.1/node_modules/uuid/dist/esm-browser/v4.js","../src/lib/types.ts","../../../node_modules/.pnpm/nanoevents@7.0.1/node_modules/nanoevents/index.js","../src/lib/SupabaseBroadcastAdapter.ts","../src/lib/FlowStep.ts","../src/lib/FlowRun.ts","../src/lib/PgflowClient.ts","../src/lib/eventAdapters.ts","../src/browser.ts"],"sourcesContent":["// Unique ID creation requires a high quality random # generator. In the browser we therefore\n// require the crypto API and do not support built-in fallback to lower quality random number\n// generators (like Math.random()).\nlet getRandomValues;\nconst rnds8 = new Uint8Array(16);\nexport default function rng() {\n // lazy load so that environments that need to polyfill have a chance to do so\n if (!getRandomValues) {\n // getRandomValues needs to be invoked in a context where \"this\" is a Crypto implementation.\n getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);\n\n if (!getRandomValues) {\n throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n }\n }\n\n return getRandomValues(rnds8);\n}","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\n\nexport function unsafeStringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];\n}\n\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);\nexport default {\n randomUUID\n};","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\n\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return unsafeStringify(rnds);\n}\n\nexport default v4;","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type {\n Json,\n RunRow,\n StepStateRow,\n FlowRow,\n StepRow,\n} from '@pgflow/core';\nimport type { FlowRun } from './FlowRun.js';\n\n/**\n * Flow run status enum\n */\nexport enum FlowRunStatus {\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Flow run event data types - individual event shapes (no circular reference)\n */\nexport type FlowRunEventData<TFlow extends AnyFlow> = {\n started: {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n input: ExtractFlowInput<TFlow>;\n status: FlowRunStatus.Started;\n started_at: string;\n remaining_steps: number;\n };\n completed: {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n output: ExtractFlowOutput<TFlow>;\n status: FlowRunStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n error_message: string;\n status: FlowRunStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all flow run events (no circular reference)\n */\nexport type FlowRunEvent<TFlow extends AnyFlow> =\n FlowRunEventData<TFlow>[keyof FlowRunEventData<TFlow>];\n\n/**\n * Type guard to check if an unknown value is a valid FlowRunEvent\n */\nexport function isFlowRunEvent<TFlow extends AnyFlow>(\n value: unknown\n): value is FlowRunEvent<TFlow> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'flow_slug' in value &&\n !('step_slug' in value) &&\n 'status' in value &&\n (value.status === FlowRunStatus.Started ||\n value.status === FlowRunStatus.Completed ||\n value.status === FlowRunStatus.Failed)\n );\n}\n\n/**\n * Type guard for started events\n */\nexport function isFlowRunStartedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['started'] {\n return event.status === FlowRunStatus.Started;\n}\n\n/**\n * Type guard for completed events\n */\nexport function isFlowRunCompletedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['completed'] {\n return event.status === FlowRunStatus.Completed;\n}\n\n/**\n * Type guard for failed events\n */\nexport function isFlowRunFailedEvent<TFlow extends AnyFlow>(\n event: FlowRunEvent<TFlow>\n): event is FlowRunEventData<TFlow>['failed'] {\n return event.status === FlowRunStatus.Failed;\n}\n\n/**\n * Flow run event types matching nanoevents expectations (wildcard added separately)\n */\nexport type FlowRunEvents<TFlow extends AnyFlow> = {\n [K in keyof FlowRunEventData<TFlow>]: (\n event: FlowRunEventData<TFlow>[K]\n ) => void;\n} & {\n '*': (event: FlowRunEvent<TFlow>) => void;\n};\n\n/**\n * Flow step status enum\n */\nexport enum FlowStepStatus {\n Created = 'created',\n Started = 'started',\n Completed = 'completed',\n Failed = 'failed',\n}\n\n/**\n * Step event data types (no circular reference)\n */\nexport type StepEventData<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n started: {\n event_type: 'step:started';\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus.Started;\n started_at: string;\n };\n completed: {\n event_type: 'step:completed';\n run_id: string;\n step_slug: TStepSlug;\n output: StepOutput<TFlow, TStepSlug>;\n status: FlowStepStatus.Completed;\n completed_at: string;\n };\n failed: {\n event_type: 'step:failed';\n run_id: string;\n step_slug: TStepSlug;\n error_message: string;\n status: FlowStepStatus.Failed;\n failed_at: string;\n };\n};\n\n/**\n * Strong discriminated union for all step events (no circular reference)\n */\nexport type StepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = StepEventData<TFlow, TStepSlug>[keyof StepEventData<TFlow, TStepSlug>];\n\n/**\n * Type guard to check if an unknown value is a valid StepEvent\n */\nexport function isStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(value: unknown): value is StepEvent<TFlow, TStepSlug> {\n return (\n !!value &&\n typeof value === 'object' &&\n 'run_id' in value &&\n 'step_slug' in value &&\n 'status' in value &&\n (value.status === FlowStepStatus.Started ||\n value.status === FlowStepStatus.Completed ||\n value.status === FlowStepStatus.Failed)\n );\n}\n\n/**\n * Type guard for started step events\n */\nexport function isStepStartedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['started'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Started &&\n 'event_type' in event &&\n event.event_type === 'step:started'\n );\n}\n\n/**\n * Type guard for completed step events\n */\nexport function isStepCompletedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['completed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Completed &&\n 'event_type' in event &&\n event.event_type === 'step:completed'\n );\n}\n\n/**\n * Type guard for failed step events\n */\nexport function isStepFailedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n>(event: unknown): event is StepEventData<TFlow, TStepSlug>['failed'] {\n return (\n isStepEvent<TFlow, TStepSlug>(event) &&\n event.status === FlowStepStatus.Failed &&\n 'event_type' in event &&\n event.event_type === 'step:failed'\n );\n}\n\n/**\n * Step event types matching nanoevents expectations (wildcard added separately)\n */\nexport type StepEvents<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n [K in keyof StepEventData<TFlow, TStepSlug>]: (\n event: StepEventData<TFlow, TStepSlug>[K]\n ) => void;\n} & {\n '*': (event: StepEvent<TFlow, TStepSlug>) => void;\n};\n\n/**\n * Function returned by event subscriptions to remove the listener\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Broadcast run event types for Supabase realtime\n */\nexport type BroadcastRunStartedEvent = {\n event_type: 'run:started';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Started;\n input: Json;\n started_at: string;\n remaining_steps: number;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunCompletedEvent = {\n event_type: 'run:completed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastRunFailedEvent = {\n event_type: 'run:failed';\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus.Failed;\n error_message: string;\n failed_at: string;\n};\n\nexport type BroadcastRunEvent =\n | BroadcastRunStartedEvent\n | BroadcastRunCompletedEvent\n | BroadcastRunFailedEvent;\n\n/**\n * Broadcast step event types for Supabase realtime\n */\nexport type BroadcastStepStartedEvent = {\n event_type: 'step:started';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Started;\n started_at: string;\n remaining_tasks: number;\n remaining_deps: number;\n error_message?: string; // Adding for type compatibility\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepCompletedEvent = {\n event_type: 'step:completed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Completed;\n output: Json;\n completed_at: string;\n error_message?: string; // Adding for type compatibility\n};\n\nexport type BroadcastStepFailedEvent = {\n event_type: 'step:failed';\n run_id: string;\n step_slug: string;\n status: FlowStepStatus.Failed;\n error_message: string;\n failed_at: string;\n output?: Json; // Adding for type compatibility\n};\n\nexport type BroadcastStepEvent =\n | BroadcastStepStartedEvent\n | BroadcastStepCompletedEvent\n | BroadcastStepFailedEvent;\n\n/**\n * Flow run state\n */\nexport type FlowRunState<TFlow extends AnyFlow> = {\n run_id: string;\n flow_slug: string;\n status: FlowRunStatus;\n input: ExtractFlowInput<TFlow>;\n output: ExtractFlowOutput<TFlow> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n remaining_steps: number;\n};\n\n/**\n * Flow step state\n */\nexport type FlowStepState<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> = {\n run_id: string;\n step_slug: TStepSlug;\n status: FlowStepStatus;\n output: StepOutput<TFlow, TStepSlug> | null;\n error: Error | null;\n error_message: string | null;\n started_at: Date | null;\n completed_at: Date | null;\n failed_at: Date | null;\n};\n\n/**\n * Interface for realtime updates (used by client library)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport interface IFlowRealtime<TFlow = unknown> {\n /**\n * Fetch flow definition metadata (looks up flows and steps tables)\n */\n fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }>;\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe;\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe;\n\n /**\n * Subscribe to a flow run's events\n */\n subscribeToRun(run_id: string): Promise<Unsubscribe>;\n\n /**\n * Fetch current state of a run and its steps\n */\n getRunWithStates(\n run_id: string\n ): Promise<{ run: RunRow; steps: StepStateRow[] }>;\n}\n\n/**\n * Generic base interface for flow runs that uses proper event types\n */\nexport interface FlowRunBase<TEvt = unknown> {\n readonly run_id: string;\n updateState(event: TEvt): boolean;\n step(stepSlug: string): FlowStepBase<unknown>;\n hasStep(stepSlug: string): boolean;\n dispose(): void;\n}\n\n/**\n * Generic base interface for flow steps that uses proper event types\n */\nexport interface FlowStepBase<TEvt = unknown> {\n updateState(event: TEvt): boolean;\n}\n\n/**\n * Utility type for broadcast events\n */\nexport type BroadcastEvent = BroadcastRunEvent | BroadcastStepEvent;\n\n/**\n * Composite interface for client\n */\nexport interface IFlowClient<TFlow extends AnyFlow = AnyFlow>\n extends IFlowRealtime<TFlow> {\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>>;\n\n /**\n * Get a flow run by ID\n *\n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n getRun<TSpecificFlow extends TFlow = TFlow>(\n run_id: string\n ): Promise<FlowRun<TSpecificFlow> | null>;\n}\n","export let createNanoEvents = () => ({\n events: {},\n emit(event, ...args) {\n let callbacks = this.events[event] || []\n for (let i = 0, length = callbacks.length; i < length; i++) {\n callbacks[i](...args)\n }\n },\n on(event, cb) {\n this.events[event]?.push(cb) || (this.events[event] = [cb])\n return () => {\n this.events[event] = this.events[event]?.filter(i => cb !== i)\n }\n }\n})\n","import type { RealtimeChannel, SupabaseClient } from '@supabase/supabase-js';\nimport type { FlowRow, StepRow, RunRow, StepStateRow } from '@pgflow/core';\nimport { createNanoEvents } from 'nanoevents';\nimport type {\n IFlowRealtime,\n BroadcastRunEvent,\n BroadcastStepEvent,\n Unsubscribe,\n} from './types.js';\n\n// Define the events interface for the adapter\ninterface AdapterEvents {\n runEvent: (event: BroadcastRunEvent) => void;\n stepEvent: (event: BroadcastStepEvent) => void;\n}\n\n/**\n * Adapter to handle realtime communication with Supabase\n */\nexport class SupabaseBroadcastAdapter implements IFlowRealtime {\n #supabase: SupabaseClient;\n #channels: Map<string, RealtimeChannel> = new Map();\n #emitter = createNanoEvents<AdapterEvents>();\n #reconnectionDelay: number;\n #stabilizationDelay: number;\n #schedule: typeof setTimeout;\n\n\n /**\n * Creates a new instance of SupabaseBroadcastAdapter\n *\n * @param supabase - Supabase client instance\n */\n constructor(\n supabase: SupabaseClient,\n opts: {\n reconnectDelayMs?: number;\n stabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabase;\n this.#reconnectionDelay = opts.reconnectDelayMs ?? 2000;\n this.#stabilizationDelay = opts.stabilizationDelayMs ?? 300;\n this.#schedule = opts.schedule ?? setTimeout.bind(globalThis);\n }\n \n /**\n * Handle broadcast messages from Supabase\n * @param payload - The message payload\n */\n #handleBroadcastMessage(msg: { \n event: string; \n payload: BroadcastRunEvent | BroadcastStepEvent;\n }): void {\n const { event, payload } = msg;\n \n // run_id is already inside the payload coming from the database trigger\n // so just preserve it without overwriting\n const eventData = payload;\n\n // Auto-parse JSON strings in broadcast data (realtime sends JSONB as strings)\n this.#parseJsonFields(eventData);\n\n if (event.startsWith('run:')) {\n // Handle run events\n this.#emitter.emit('runEvent', eventData as BroadcastRunEvent);\n } else if (event.startsWith('step:')) {\n // Handle step events\n this.#emitter.emit('stepEvent', eventData as BroadcastStepEvent);\n }\n }\n\n /**\n * Parse JSON string fields in broadcast event data\n * @param eventData - The event data object to parse\n */\n #parseJsonFields(eventData: Record<string, unknown>): void {\n // Parse output field if it's a JSON string\n if ('output' in eventData && typeof eventData.output === 'string') {\n try {\n eventData.output = JSON.parse(eventData.output);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n \n // Parse input field if it's a JSON string\n if ('input' in eventData && typeof eventData.input === 'string') {\n try {\n eventData.input = JSON.parse(eventData.input);\n } catch {\n // Keep as string if not valid JSON\n }\n }\n }\n\n \n /**\n * Handle channel errors and reconnection\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @param channel - The RealtimeChannel instance\n * @param error - The error object\n */\n async #handleChannelError(\n run_id: string,\n channelName: string,\n channel: RealtimeChannel,\n error: unknown\n ): Promise<void> {\n console.error(`Channel ${channelName} error:`, error);\n \n // Schedule reconnection attempt\n this.#schedule(async () => {\n if (this.#channels.has(run_id)) {\n await this.#reconnectChannel(run_id, channelName);\n }\n }, this.#reconnectionDelay);\n }\n \n /**\n * Creates and configures a channel for a run\n * @param run_id - The run ID\n * @param channelName - The channel name\n * @returns The configured RealtimeChannel\n */\n #createAndConfigureChannel(run_id: string, channelName: string): RealtimeChannel {\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Note: Lifecycle event listeners (subscribed, closed, error) are handled \n // by the calling code to avoid conflicts when multiple listeners try to \n // handle the same events.\n \n return channel;\n }\n \n /**\n * Reconnect to a channel and refresh state\n * @param run_id - The run ID\n * @param channelName - The channel name\n */\n async #reconnectChannel(\n run_id: string,\n channelName: string\n ): Promise<void> {\n console.log(`Attempting to reconnect to ${channelName}`);\n \n try {\n // Fetch current state to avoid missing events during disconnection\n const currentState = await this.getRunWithStates(run_id);\n \n // Update state based on current data\n this.#refreshStateFromSnapshot(run_id, currentState);\n \n // Create a new channel as the old one can't be reused\n const newChannel = this.#createAndConfigureChannel(run_id, channelName);\n \n // Set up lifecycle event handlers for reconnection\n newChannel.on('system', { event: 'subscribed' }, () => {\n console.log(`Reconnected and subscribed to channel ${channelName}`);\n });\n \n newChannel.on('system', { event: 'closed' }, () => {\n console.log(`Reconnected channel ${channelName} closed`);\n });\n \n newChannel.on('system', { event: 'error' }, (payload) => \n this.#handleChannelError(run_id, channelName, newChannel, payload.error)\n );\n \n // Subscribe and update the channels map\n newChannel.subscribe();\n this.#channels.set(run_id, newChannel);\n } catch (e) {\n console.error(`Failed to reconnect to ${channelName}:`, e);\n }\n }\n \n /**\n * Refresh client state from a state snapshot\n * @param run_id - The run ID\n * @param state - The state snapshot\n */\n #refreshStateFromSnapshot(\n run_id: string,\n state: { run: RunRow; steps: StepStateRow[] } | null\n ): void {\n if (!state || !state.run) return;\n \n // Create proper run event with correct event_type\n const runEvent: BroadcastRunEvent = {\n event_type: `run:${state.run.status}`,\n ...state.run\n } as unknown as BroadcastRunEvent;\n \n // Emit run event\n this.#emitter.emit('runEvent', runEvent);\n \n // Emit events for each step state\n if (state.steps && Array.isArray(state.steps)) {\n for (const step of state.steps) {\n // Create proper step event with correct event_type\n const stepEvent: BroadcastStepEvent = {\n event_type: `step:${step.status}`,\n ...step\n } as unknown as BroadcastStepEvent;\n \n // Emit step event\n this.#emitter.emit('stepEvent', stepEvent);\n }\n }\n }\n\n /**\n * Fetches flow definition metadata from the database\n *\n * @param flow_slug - Flow slug to fetch\n */\n async fetchFlowDefinition(flow_slug: string): Promise<{\n flow: FlowRow;\n steps: StepRow[];\n }> {\n // Fetch flow details and steps in parallel\n const [flowResult, stepsResult] = await Promise.all([\n this.#supabase\n .schema('pgflow')\n .from('flows')\n .select('*')\n .eq('flow_slug', flow_slug)\n .single(),\n this.#supabase\n .schema('pgflow')\n .from('steps')\n .select('*')\n .eq('flow_slug', flow_slug)\n .order('step_index', { ascending: true })\n ]);\n\n // Handle flow result\n if (flowResult.error) throw flowResult.error;\n if (!flowResult.data) throw new Error(`Flow \"${flow_slug}\" not found`);\n\n // Handle steps result\n if (stepsResult.error) throw stepsResult.error;\n \n // Ensure steps is always an array, even if it's null or undefined\n const stepsArray = Array.isArray(stepsResult.data) ? stepsResult.data : [];\n\n return {\n flow: flowResult.data as FlowRow,\n steps: stepsArray as StepRow[],\n };\n }\n\n /**\n * Registers a callback for run events\n *\n * @param callback - Function to call when run events are received\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('runEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from run event - emitter may have been disposed', e);\n }\n };\n }\n\n /**\n * Registers a callback for step events\n *\n * @param callback - Function to call when step events are received\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n // Add a guard to prevent errors if called after emitter is deleted\n const unsubscribe = this.#emitter.on('stepEvent', callback);\n return () => {\n try {\n unsubscribe();\n } catch (e) {\n console.warn('Could not unsubscribe from step event - emitter may have been disposed', e);\n }\n };\n }\n\n // Store unsubscribe functions per run ID for reference equality\n #unsubscribeFunctions: Map<string, () => void> = new Map();\n\n /**\n * Subscribes to a flow run's events\n *\n * @param run_id - Run ID to subscribe to\n * @returns Function to unsubscribe\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n const channelName = `pgflow:run:${run_id}`;\n\n // If already subscribed, return the existing unsubscribe function\n if (this.#channels.has(run_id)) {\n const existingUnsubscribe = this.#unsubscribeFunctions.get(run_id);\n if (existingUnsubscribe) {\n return existingUnsubscribe;\n }\n // If channel exists but no unsubscribe function, something went wrong\n // Let's clean up and recreate\n this.#unsubscribe(run_id);\n }\n\n const channel = this.#supabase.channel(channelName);\n \n // Listen to *all* broadcast messages; filter inside the handler.\n // Using the 3-arg overload with event filter for proper Supabase v2 client compatibility.\n channel.on('broadcast', { event: '*' }, this.#handleBroadcastMessage.bind(this));\n \n // Set up error handling\n channel.on('system', { event: 'closed' }, () => {\n console.log(`Channel ${channelName} closed`);\n });\n channel.on('system', { event: 'error' }, (payload) => {\n console.log(`Channel ${channelName} error:`, payload);\n this.#handleChannelError(run_id, channelName, channel, payload.error);\n });\n \n // Subscribe to channel and wait for confirmation (like the working realtime-send test)\n console.log(`Subscribing to channel ${channelName}...`);\n \n const subscriptionPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Subscription timeout for channel ${channelName}`));\n }, 20000); // Increased from 5s to 20s for slower CI environments\n \n channel.subscribe((status) => {\n console.log(`Channel ${channelName} subscription status:`, status);\n if (status === 'SUBSCRIBED') {\n clearTimeout(timeout);\n resolve();\n }\n // Don't reject on CHANNEL_ERROR - it's a transient state\n // Only reject on timeout\n });\n });\n \n // Wait for the 'SUBSCRIBED' acknowledgment to avoid race conditions\n await subscriptionPromise;\n\n // Stabilization delay - known Supabase Realtime limitation\n // The SUBSCRIBED event is emitted before backend routing is fully established.\n // This delay ensures the backend can receive messages sent immediately after subscription.\n // See: https://github.com/supabase/supabase-js/issues/1599\n await new Promise(resolve => this.#schedule(resolve, this.#stabilizationDelay));\n\n this.#channels.set(run_id, channel);\n\n const unsubscribe = () => this.unsubscribe(run_id);\n this.#unsubscribeFunctions.set(run_id, unsubscribe);\n return unsubscribe;\n }\n \n /**\n * Unsubscribes from a run's events\n * \n * @param run_id - Run ID to unsubscribe from\n */\n unsubscribe(run_id: string): void {\n this.#unsubscribe(run_id);\n }\n\n /**\n * Fetches current state of a run and its steps\n *\n * @param run_id - Run ID to fetch\n */\n async getRunWithStates(run_id: string): Promise<{\n run: RunRow;\n steps: StepStateRow[];\n }> {\n // Call the RPC function which returns a JSONB object\n const { data, error } = await this.#supabase\n .schema('pgflow')\n .rpc('get_run_with_states', { run_id });\n\n if (error) throw error;\n if (!data) throw new Error(`No data returned for run ${run_id}`);\n \n return data as { run: RunRow; steps: StepStateRow[] };\n }\n\n /**\n * Unsubscribes from a run's events\n *\n * @param run_id - Run ID to unsubscribe from\n */\n #unsubscribe(run_id: string): void {\n const channel = this.#channels.get(run_id);\n if (channel) {\n // Close the channel\n channel.unsubscribe();\n this.#channels.delete(run_id);\n \n // Also clean up the unsubscribe function reference\n this.#unsubscribeFunctions.delete(run_id);\n \n // We don't need to explicitly remove event listeners from the emitter\n // as they will be garbage collected when no longer referenced.\n // The event listeners are bound to specific callbacks provided by the client,\n // which will retain references if they're still in use.\n }\n }\n}\n","import { createNanoEvents } from 'nanoevents';\nimport type { AnyFlow, ExtractFlowSteps, StepOutput } from '@pgflow/dsl';\nimport { FlowStepStatus } from './types.js';\nimport type { \n FlowStepState, \n StepEvents, \n Unsubscribe, \n FlowStepBase,\n StepEvent\n} from './types.js';\n\n/**\n * Represents a single step in a flow run\n */\nexport class FlowStep<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string\n> implements FlowStepBase<StepEvent<TFlow, TStepSlug>> {\n #state: FlowStepState<TFlow, TStepSlug>;\n #events = createNanoEvents<StepEvents<TFlow, TStepSlug>>();\n #statusPrecedence: Record<FlowStepStatus, number> = {\n [FlowStepStatus.Created]: 0,\n [FlowStepStatus.Started]: 1,\n [FlowStepStatus.Completed]: 2,\n [FlowStepStatus.Failed]: 3,\n };\n\n /**\n * Creates a new FlowStep instance\n * \n * @param initialState - Initial state for the step\n */\n constructor(initialState: FlowStepState<TFlow, TStepSlug>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID this step belongs to\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the step slug\n */\n get step_slug(): TStepSlug {\n return this.#state.step_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowStepStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the step output\n */\n get output(): StepOutput<TFlow, TStepSlug> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Register an event handler for a step event\n * \n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof StepEvents<TFlow, TStepSlug>>(\n event: E,\n callback: StepEvents<TFlow, TStepSlug>[E]\n ): Unsubscribe {\n return this.#events.on(event, callback);\n }\n\n /**\n * Wait for the step to reach a specific status\n * \n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the step instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowStepStatus.Started | FlowStepStatus.Completed | FlowStepStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n \n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(new Error(`Timeout waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n }, timeoutMs);\n }\n \n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(new Error(`Aborted waiting for step ${this.step_slug} to reach status '${targetStatus}'`));\n };\n \n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n \n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').StepStateRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowStepStatus;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.error_message = row.error_message;\n this.#state.error = row.error_message ? new Error(row.error_message) : null;\n // Note: output is not stored in step_states table, remains null\n }\n\n /**\n * Updates the step state based on an event\n *\n * @internal This method is only intended for use by FlowRun and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: StepEvent<TFlow, TStepSlug>): boolean {\n // Validate event is for this step\n if (event.step_slug !== this.#state.step_slug) {\n return false;\n }\n \n // Validate event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n \n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowStepStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Started,\n started_at: typeof event.started_at === 'string' ? new Date(event.started_at) : new Date(),\n };\n this.#events.emit('started', event);\n break;\n\n case FlowStepStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Completed,\n completed_at: typeof event.completed_at === 'string' ? new Date(event.completed_at) : new Date(),\n output: event.output as StepOutput<TFlow, TStepSlug>,\n };\n this.#events.emit('completed', event);\n break;\n\n case FlowStepStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowStepStatus.Failed,\n failed_at: typeof event.failed_at === 'string' ? new Date(event.failed_at) : new Date(),\n error_message: typeof event.error_message === 'string' ? event.error_message : 'Unknown error',\n error: new Error(typeof event.error_message === 'string' ? event.error_message : 'Unknown error'),\n };\n this.#events.emit('failed', event);\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n \n return true;\n }\n\n /**\n * Determines if a status should be updated based on precedence\n * \n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(currentStatus: FlowStepStatus, newStatus: FlowStepStatus): boolean {\n // Don't allow changes to terminal states\n if (currentStatus === FlowStepStatus.Completed || currentStatus === FlowStepStatus.Failed) {\n return false; // Terminal states should never change\n }\n \n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n}","import { createNanoEvents } from 'nanoevents';\nimport type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n} from '@pgflow/dsl';\nimport { FlowRunStatus, FlowStepStatus } from './types.js';\nimport type {\n FlowRunState,\n FlowRunEvents,\n Unsubscribe,\n FlowRunBase,\n FlowStepBase,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\nimport { FlowStep } from './FlowStep.js';\n\n/**\n * Represents a single execution of a flow\n */\nexport class FlowRun<TFlow extends AnyFlow>\n implements FlowRunBase<FlowRunEvent<TFlow>>\n{\n #state: FlowRunState<TFlow>;\n #events = createNanoEvents<FlowRunEvents<TFlow>>();\n #steps = new Map<string, FlowStepBase>();\n #statusPrecedence: Record<FlowRunStatus, number> = {\n [FlowRunStatus.Started]: 0,\n [FlowRunStatus.Completed]: 1,\n [FlowRunStatus.Failed]: 2,\n };\n #disposed = false;\n\n /**\n * Creates a new FlowRun instance\n *\n * @param initialState - Initial state for the run\n */\n constructor(initialState: FlowRunState<TFlow>) {\n this.#state = initialState;\n }\n\n /**\n * Get the run ID\n */\n get run_id(): string {\n return this.#state.run_id;\n }\n\n /**\n * Get the flow slug\n */\n get flow_slug(): string {\n return this.#state.flow_slug;\n }\n\n /**\n * Get the current status\n */\n get status(): FlowRunStatus {\n return this.#state.status;\n }\n\n /**\n * Get the started_at timestamp\n */\n get started_at(): Date | null {\n return this.#state.started_at;\n }\n\n /**\n * Get the completed_at timestamp\n */\n get completed_at(): Date | null {\n return this.#state.completed_at;\n }\n\n /**\n * Get the failed_at timestamp\n */\n get failed_at(): Date | null {\n return this.#state.failed_at;\n }\n\n /**\n * Get the flow input\n */\n get input(): ExtractFlowInput<TFlow> {\n return this.#state.input;\n }\n\n /**\n * Get the flow output\n */\n get output(): ExtractFlowOutput<TFlow> | null {\n return this.#state.output;\n }\n\n /**\n * Get the error object\n */\n get error(): Error | null {\n return this.#state.error;\n }\n\n /**\n * Get the error message\n */\n get error_message(): string | null {\n return this.#state.error_message;\n }\n\n /**\n * Get the number of remaining steps\n */\n get remaining_steps(): number {\n return this.#state.remaining_steps;\n }\n\n /**\n * Register an event handler for a run event\n *\n * @param event - Event type to listen for\n * @param callback - Callback function to execute when event is emitted\n * @returns Function to unsubscribe from the event\n */\n on<E extends keyof FlowRunEvents<TFlow>>(\n event: E,\n callback: FlowRunEvents<TFlow>[E]\n ): Unsubscribe {\n this.#listenerCount++;\n\n // Wrap the unsubscribe function to track listener count\n const unsubscribe = this.#events.on(event, callback);\n\n return () => {\n unsubscribe();\n this.#listenerCount--;\n this.#checkAutoDispose();\n };\n }\n\n /**\n * Get a FlowStep instance for a specific step\n *\n * @param stepSlug - Step slug to get\n * @returns FlowStep instance for the specified step\n */\n step<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug\n ): FlowStep<TFlow, TStepSlug> {\n // Look up if we already have this step cached\n const existingStep = this.#steps.get(stepSlug as string);\n if (existingStep) {\n // Safe to cast since we only store steps with matching slugs\n return existingStep as unknown as FlowStep<TFlow, TStepSlug>;\n }\n\n // Create a new step instance with default state\n const step = new FlowStep<TFlow, TStepSlug>({\n run_id: this.run_id,\n step_slug: stepSlug,\n status: FlowStepStatus.Created,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n });\n\n // Cache the step\n this.#steps.set(\n stepSlug as string,\n step as FlowStepBase<StepEvent<TFlow, TStepSlug>>\n );\n\n return step;\n }\n\n /**\n * Check if this run has a specific step\n *\n * @param stepSlug - Step slug to check\n * @returns true if the step exists, false otherwise\n */\n hasStep(stepSlug: string): boolean {\n // Check if we have this step cached\n return this.#steps.has(stepSlug);\n }\n\n /**\n * Wait for the run to reach a specific status\n *\n * @param targetStatus - The status to wait for\n * @param options - Optional timeout and abort signal\n * @returns Promise that resolves with the run instance when the status is reached\n */\n waitForStatus(\n targetStatus: FlowRunStatus.Completed | FlowRunStatus.Failed,\n options?: { timeoutMs?: number; signal?: AbortSignal }\n ): Promise<this> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000; // Default 5 minutes\n const { signal } = options || {};\n\n // If we already have the target status, resolve immediately\n if (this.status === targetStatus) {\n return Promise.resolve(this);\n }\n\n // Otherwise, wait for the status to change\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined;\n let cleanedUp = false;\n\n // Set up timeout if provided\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => {\n if (cleanedUp) return; // Prevent firing if already cleaned up\n cleanedUp = true;\n unbind();\n reject(\n new Error(\n `Timeout waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n }, timeoutMs);\n }\n\n // Set up abort signal if provided\n let abortCleanup: (() => void) | undefined;\n if (signal) {\n const abortHandler = () => {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n unbind();\n reject(\n new Error(\n `Aborted waiting for run ${this.run_id} to reach status '${targetStatus}'`\n )\n );\n };\n\n signal.addEventListener('abort', abortHandler);\n abortCleanup = () => {\n signal.removeEventListener('abort', abortHandler);\n };\n }\n\n // Subscribe to all events\n const unbind = this.on('*', (event) => {\n if (event.status === targetStatus) {\n if (cleanedUp) return; // Prevent double cleanup\n cleanedUp = true;\n if (timeoutId) clearTimeout(timeoutId);\n if (abortCleanup) abortCleanup();\n unbind();\n resolve(this);\n }\n });\n });\n }\n\n /**\n * Apply state from database snapshot (no events emitted)\n * Used when initializing state from start_flow_with_states() or get_run_with_states()\n *\n * @internal This method is only intended for use by PgflowClient.\n * Applications should not call this directly.\n */\n applySnapshot(row: import('@pgflow/core').RunRow): void {\n // Direct state assignment from database row (no event conversion)\n this.#state.status = row.status as FlowRunStatus;\n this.#state.input = row.input as ExtractFlowInput<TFlow>;\n this.#state.output = row.output as ExtractFlowOutput<TFlow> | null;\n this.#state.started_at = row.started_at ? new Date(row.started_at) : null;\n this.#state.completed_at = row.completed_at ? new Date(row.completed_at) : null;\n this.#state.failed_at = row.failed_at ? new Date(row.failed_at) : null;\n this.#state.remaining_steps = row.remaining_steps;\n this.#state.error_message = null; // Database doesn't have error_message for runs\n this.#state.error = null;\n }\n\n /**\n * Updates the run state based on an event\n *\n * @internal This method is only intended for use by PgflowClient and tests.\n * Applications should not call this directly - state updates should come from\n * database events through the PgflowClient.\n *\n * TODO: After v1.0, make this method private and refactor tests to use PgflowClient\n * with event emission instead of direct state manipulation.\n */\n updateState(event: FlowRunEvent<TFlow>): boolean {\n // Validate the event is for this run\n if (event.run_id !== this.#state.run_id) {\n return false;\n }\n\n // Check if the event status has higher precedence than current status\n if (!this.#shouldUpdateStatus(this.#state.status, event.status)) {\n return false;\n }\n\n // Update state based on event type using narrowing type guards\n switch (event.status) {\n case FlowRunStatus.Started:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Started,\n started_at:\n typeof event.started_at === 'string'\n ? new Date(event.started_at)\n : new Date(),\n remaining_steps:\n 'remaining_steps' in event\n ? Number(event.remaining_steps)\n : this.#state.remaining_steps,\n };\n this.#events.emit('started', event);\n break;\n\n case FlowRunStatus.Completed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Completed,\n completed_at:\n typeof event.completed_at === 'string'\n ? new Date(event.completed_at)\n : new Date(),\n output: event.output as ExtractFlowOutput<TFlow>,\n remaining_steps: 0,\n };\n this.#events.emit('completed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n case FlowRunStatus.Failed:\n this.#state = {\n ...this.#state,\n status: FlowRunStatus.Failed,\n failed_at:\n typeof event.failed_at === 'string'\n ? new Date(event.failed_at)\n : new Date(),\n error_message:\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error',\n error: new Error(\n typeof event.error_message === 'string'\n ? event.error_message\n : 'Unknown error'\n ),\n };\n this.#events.emit('failed', event);\n\n // Check for auto-dispose\n this.#checkAutoDispose();\n break;\n\n default: {\n // Exhaustiveness check - ensures all event statuses are handled\n event satisfies never;\n return false;\n }\n }\n\n // Also emit to the catch-all listener\n this.#events.emit('*', event);\n\n return true;\n }\n\n /**\n * Updates a step state based on an event\n *\n * @param stepSlug - Step slug to update\n * @param event - Event data to update the step with\n * @returns true if the state was updated, false otherwise\n */\n updateStepState<TStepSlug extends keyof ExtractFlowSteps<TFlow> & string>(\n stepSlug: TStepSlug,\n event: StepEvent<TFlow, TStepSlug>\n ): boolean {\n const step = this.step(stepSlug);\n return step.updateState(event);\n }\n\n // Track number of listeners\n #listenerCount = 0;\n\n /**\n * Checks if auto-dispose should be triggered (when in terminal state with no listeners)\n */\n #checkAutoDispose(): void {\n // Don't auto-dispose multiple times\n if (this.#disposed) {\n return;\n }\n\n // Only auto-dispose in terminal states\n if (\n this.status !== FlowRunStatus.Completed &&\n this.status !== FlowRunStatus.Failed\n ) {\n return;\n }\n\n // If there are no listeners, auto-dispose\n if (this.#listenerCount === 0) {\n this.dispose();\n }\n }\n\n /**\n * Determines if a status should be updated based on precedence\n *\n * @param currentStatus - Current status\n * @param newStatus - New status\n * @returns true if the status should be updated, false otherwise\n */\n #shouldUpdateStatus(\n currentStatus: FlowRunStatus,\n newStatus: FlowRunStatus\n ): boolean {\n // Don't allow changes to terminal states\n if (\n currentStatus === FlowRunStatus.Completed ||\n currentStatus === FlowRunStatus.Failed\n ) {\n return false; // Terminal states should never change\n }\n\n const currentPrecedence = this.#statusPrecedence[currentStatus];\n const newPrecedence = this.#statusPrecedence[newStatus];\n\n // Only allow transitions to higher precedence non-terminal status\n return newPrecedence > currentPrecedence;\n }\n\n /**\n * Clean up all resources held by this run\n */\n dispose(): void {\n if (this.#disposed) {\n return;\n }\n\n // Clear the map to allow garbage collection of steps\n this.#steps.clear();\n\n // Create a new events object - this effectively clears all listeners\n // without accessing the private internals of nanoevents\n this.#events = createNanoEvents<FlowRunEvents<TFlow>>();\n this.#listenerCount = 0;\n\n // Mark as disposed\n this.#disposed = true;\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';\nimport { FlowRunStatus } from './types.js';\nimport type { \n IFlowClient, \n FlowRunState, \n BroadcastRunEvent, \n BroadcastStepEvent, \n Unsubscribe, \n FlowRunBase\n} from './types.js';\nimport { SupabaseBroadcastAdapter } from './SupabaseBroadcastAdapter.js';\nimport { FlowRun } from './FlowRun.js';\nimport { toTypedRunEvent, toTypedStepEvent } from './eventAdapters.js';\n\n/**\n * Client for interacting with pgflow\n */\nexport class PgflowClient<TFlow extends AnyFlow = AnyFlow> implements IFlowClient<TFlow> {\n #supabase: SupabaseClient;\n #realtimeAdapter: SupabaseBroadcastAdapter;\n // Use the widest event type - keeps the compiler happy but\n // still provides the structural API we need (updateState/step/...)\n #runs = new Map<string, FlowRunBase<unknown>>();\n\n /**\n * Creates a new PgflowClient instance\n *\n * @param supabaseClient - Supabase client instance\n * @param opts - Optional configuration\n */\n constructor(\n supabaseClient: SupabaseClient,\n opts: {\n realtimeStabilizationDelayMs?: number;\n schedule?: typeof setTimeout;\n } = {}\n ) {\n this.#supabase = supabaseClient;\n this.#realtimeAdapter = new SupabaseBroadcastAdapter(supabaseClient, {\n stabilizationDelayMs: opts.realtimeStabilizationDelayMs,\n schedule: opts.schedule,\n });\n\n // Set up global event listeners - properly typed\n this.#realtimeAdapter.onRunEvent((event: BroadcastRunEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Convert broadcast event to typed event before updating state\n run.updateState(toTypedRunEvent(event));\n }\n });\n\n this.#realtimeAdapter.onStepEvent((event: BroadcastStepEvent) => {\n const run = this.#runs.get(event.run_id);\n if (run) {\n // Always materialize the step before updating to avoid event loss\n // This ensures we cache all steps even if they were never explicitly requested\n const stepSlug = event.step_slug;\n run.step(stepSlug).updateState(toTypedStepEvent(event));\n }\n });\n }\n\n /**\n * Start a flow with optional run_id\n *\n * @param flow_slug - Flow slug to start\n * @param input - Input data for the flow\n * @param run_id - Optional run ID (will be generated if not provided)\n * @returns Promise that resolves with the FlowRun instance\n */\n async startFlow<TSpecificFlow extends TFlow>(\n flow_slug: string,\n input: ExtractFlowInput<TSpecificFlow>,\n run_id?: string\n ): Promise<FlowRun<TSpecificFlow>> {\n // Generate a run_id if not provided\n const id = run_id || uuidv4();\n\n // Create initial state for the flow run\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: id,\n flow_slug,\n status: FlowRunStatus.Started,\n input: input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: -1, // Use -1 to indicate unknown until first snapshot arrives\n };\n\n // Create the flow run instance\n const run = new FlowRun<TSpecificFlow>(initialState);\n\n // Store the run\n this.#runs.set(id, run);\n\n // Set up subscription for run and step events (wait for subscription confirmation)\n await this.#realtimeAdapter.subscribeToRun(id);\n\n // Start the flow with the predetermined run_id (only after subscription is ready)\n const { data, error } = await this.#supabase.schema('pgflow').rpc('start_flow_with_states', {\n flow_slug: flow_slug,\n input: input as Record<string, unknown>,\n run_id: id\n });\n\n if (error) {\n // Clean up subscription and run instance\n this.dispose(id);\n throw error;\n }\n\n // Apply the run state snapshot (no events)\n if (data.run) {\n run.applySnapshot(data.run);\n }\n\n // Apply step state snapshots (no events)\n if (data.steps && Array.isArray(data.steps)) {\n for (const stepState of data.steps) {\n run.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n\n return run;\n }\n\n /**\n * Dispose a specific flow run\n *\n * @param runId - Run ID to dispose\n */\n dispose(runId: string): void {\n const run = this.#runs.get(runId);\n if (run) {\n // First unsubscribe from the realtime adapter\n this.#realtimeAdapter.unsubscribe(runId);\n \n // Then dispose the run\n run.dispose();\n \n // Finally remove from the runs map\n this.#runs.delete(runId);\n }\n }\n\n /**\n * Dispose all flow runs\n */\n disposeAll(): void {\n for (const runId of this.#runs.keys()) {\n this.dispose(runId);\n }\n }\n\n // Delegate IFlowRealtime methods to the adapter\n\n /**\n * Fetch flow definition metadata\n */\n async fetchFlowDefinition(flow_slug: string) {\n return this.#realtimeAdapter.fetchFlowDefinition(flow_slug);\n }\n\n /**\n * Register a callback for run events\n * @returns Function to unsubscribe from the event\n */\n onRunEvent(callback: (event: BroadcastRunEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onRunEvent(callback);\n }\n\n /**\n * Register a callback for step events\n * @returns Function to unsubscribe from the event\n */\n onStepEvent(callback: (event: BroadcastStepEvent) => void): Unsubscribe {\n return this.#realtimeAdapter.onStepEvent(callback);\n }\n\n /**\n * Subscribe to a flow run's events\n */\n async subscribeToRun(run_id: string): Promise<() => void> {\n return await this.#realtimeAdapter.subscribeToRun(run_id);\n }\n\n /**\n * Fetch current state of a run and its steps\n */\n async getRunWithStates(run_id: string) {\n return this.#realtimeAdapter.getRunWithStates(run_id);\n }\n \n /**\n * Get a flow run by ID\n * \n * @param run_id - ID of the run to get\n * @returns Promise that resolves with the FlowRun instance or null if not found\n */\n async getRun<TSpecificFlow extends TFlow = TFlow>(run_id: string): Promise<FlowRun<TSpecificFlow> | null> {\n // Check if we already have this run cached\n const existingRun = this.#runs.get(run_id);\n if (existingRun) {\n return existingRun as FlowRun<TSpecificFlow>;\n }\n \n try {\n // Fetch the run state from the database\n const { run, steps } = await this.getRunWithStates(run_id);\n \n if (!run) {\n return null;\n }\n \n // Validate required fields\n if (!run.run_id || !run.flow_slug || !run.status) {\n throw new Error('Invalid run data: missing required fields');\n }\n\n // Validate status is a valid FlowRunStatus\n const validStatuses = Object.values(FlowRunStatus);\n if (!validStatuses.includes(run.status as FlowRunStatus)) {\n throw new Error(`Invalid run data: invalid status '${run.status}'`);\n }\n\n // Create flow run with minimal initial state\n const initialState: FlowRunState<TSpecificFlow> = {\n run_id: run.run_id,\n flow_slug: run.flow_slug,\n status: run.status as FlowRunStatus,\n input: run.input as ExtractFlowInput<TSpecificFlow>,\n output: null,\n error: null,\n error_message: null,\n started_at: null,\n completed_at: null,\n failed_at: null,\n remaining_steps: 0,\n };\n\n // Create the flow run instance\n const flowRun = new FlowRun<TSpecificFlow>(initialState);\n\n // Apply the complete state from database snapshot\n flowRun.applySnapshot(run);\n \n // Store the run\n this.#runs.set(run_id, flowRun);\n \n // Set up subscription for run and step events\n await this.#realtimeAdapter.subscribeToRun(run_id);\n \n // Initialize steps from snapshot\n if (steps && Array.isArray(steps)) {\n for (const stepState of steps) {\n // Validate step has required fields\n if (!stepState.step_slug || !stepState.status) {\n throw new Error('Invalid step data: missing required fields');\n }\n\n // Apply snapshot state directly (no events)\n flowRun.step(stepState.step_slug).applySnapshot(stepState);\n }\n }\n \n return flowRun;\n } catch (error) {\n console.error('Error getting run:', error);\n // Re-throw if it's a validation error\n if (error instanceof Error && (error.message.includes('Invalid run data') || error.message.includes('Invalid step data'))) {\n throw error;\n }\n return null;\n }\n }\n \n}\n","import type {\n AnyFlow,\n ExtractFlowInput,\n ExtractFlowOutput,\n ExtractFlowSteps,\n StepOutput,\n} from '@pgflow/dsl';\nimport type { RunRow, StepStateRow } from '@pgflow/core';\nimport {\n FlowStepStatus,\n FlowRunStatus,\n} from './types.js';\nimport type {\n BroadcastRunEvent,\n BroadcastStepEvent,\n FlowRunEvent,\n StepEvent,\n} from './types.js';\n\n/**\n * Convert a broadcast run event to a typed run event\n */\nexport function toTypedRunEvent<TFlow extends AnyFlow>(\n evt: BroadcastRunEvent\n): FlowRunEvent<TFlow> {\n switch (evt.status) {\n case FlowRunStatus.Started:\n return {\n event_type: 'run:started',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Started,\n started_at: evt.started_at,\n remaining_steps: evt.remaining_steps,\n input: evt.input as ExtractFlowInput<TFlow>,\n };\n case FlowRunStatus.Completed:\n return {\n event_type: 'run:completed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as ExtractFlowOutput<TFlow>,\n };\n case FlowRunStatus.Failed:\n return {\n event_type: 'run:failed',\n run_id: evt.run_id,\n flow_slug: evt.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a broadcast step event to a typed step event\n */\nexport function toTypedStepEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(evt: BroadcastStepEvent): StepEvent<TFlow, TStepSlug> {\n switch (evt.status) {\n case FlowStepStatus.Started:\n return {\n event_type: 'step:started',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: evt.started_at,\n };\n case FlowStepStatus.Completed:\n return {\n event_type: 'step:completed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: evt.completed_at,\n output: evt.output as StepOutput<TFlow, TStepSlug>,\n };\n case FlowStepStatus.Failed:\n return {\n event_type: 'step:failed',\n run_id: evt.run_id,\n step_slug: evt.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: evt.failed_at,\n error_message: evt.error_message,\n };\n }\n}\n\n/**\n * Convert a database run row to a typed run event\n */\nexport function runRowToTypedEvent<TFlow extends AnyFlow>(\n row: RunRow\n): FlowRunEvent<TFlow> {\n switch (row.status) {\n case 'started':\n return {\n event_type: 'run:started',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Started,\n started_at: row.started_at!,\n remaining_steps: row.remaining_steps,\n input: row.input as ExtractFlowInput<TFlow>,\n };\n case 'completed':\n return {\n event_type: 'run:completed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Completed,\n completed_at: row.completed_at!,\n output: row.output as ExtractFlowOutput<TFlow>,\n };\n case 'failed':\n return {\n event_type: 'run:failed',\n run_id: row.run_id,\n flow_slug: row.flow_slug,\n status: FlowRunStatus.Failed,\n failed_at: row.failed_at!,\n error_message: 'Flow failed', // Database doesn't have error_message for runs\n };\n default:\n throw new Error(`Unknown run status: ${row.status}`);\n }\n}\n\n/**\n * Convert a database step state row to a typed step event\n */\nexport function stepStateRowToTypedEvent<\n TFlow extends AnyFlow,\n TStepSlug extends keyof ExtractFlowSteps<TFlow> & string,\n>(row: StepStateRow): StepEvent<TFlow, TStepSlug> {\n switch (row.status) {\n case 'created':\n case 'started':\n return {\n event_type: 'step:started',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Started,\n started_at: row.started_at!,\n };\n case 'completed':\n return {\n event_type: 'step:completed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Completed,\n completed_at: row.completed_at!,\n output: {} as StepOutput<TFlow, TStepSlug>, // Database doesn't have output in step_states\n };\n case 'failed':\n return {\n event_type: 'step:failed',\n run_id: row.run_id,\n step_slug: row.step_slug as TStepSlug,\n status: FlowStepStatus.Failed,\n failed_at: row.failed_at!,\n error_message: row.error_message || 'Step failed',\n };\n default:\n throw new Error(`Unknown step status: ${row.status}`);\n }\n}","// Browser-specific entry point\nexport { PgflowClient } from './lib/PgflowClient.js';\nexport { FlowRunStatus, FlowStepStatus } from './lib/types.js';\nexport * from './lib/types.js';\n\n// Import the PgflowClient constructor for the factory\nimport { PgflowClient } from './lib/PgflowClient.js';\nimport type { SupabaseClient } from '@supabase/supabase-js';\n\n// Factory function for creating PgflowClient instances\nexport function createClient(supabaseClient: SupabaseClient) {\n return new PgflowClient(supabaseClient);\n}"],"names":["getRandomValues","rnds8","Uint8Array","rng","crypto","bind","Error","byteToHex","i","push","toString","slice","native","randomUUID","v4","options","buf","offset","rnds","random","arr","unsafeStringify","FlowRunStatus","FlowStepStatus","isStepEvent","value","status","createNanoEvents","events","emit","event","args","callbacks","this","length","on","cb","_a","filter","SupabaseBroadcastAdapter","constructor","supabase","opts","__privateAdd","_SupabaseBroadcastAdapter_instances","_supabase","_channels","Map","_emitter","_reconnectionDelay","_stabilizationDelay","_schedule","_unsubscribeFunctions","__privateSet","reconnectDelayMs","stabilizationDelayMs","schedule","setTimeout","globalThis","fetchFlowDefinition","flow_slug","flowResult","stepsResult","Promise","all","__privateGet","schema","from","select","eq","single","order","ascending","error","data","stepsArray","Array","isArray","flow","steps","onRunEvent","callback","unsubscribe","e","console","warn","onStepEvent","subscribeToRun","run_id","channelName","has","existingUnsubscribe","get","__privateMethod","call","channel","handleBroadcastMessage_fn","log","payload","handleChannelError_fn","subscriptionPromise","resolve","reject","timeout","subscribe","clearTimeout","set","getRunWithStates","rpc","WeakMap","WeakSet","msg","eventData","startsWith","parseJsonFields_fn","output","JSON","parse","input","async","reconnectChannel_fn","createAndConfigureChannel_fn","currentState","refreshStateFromSnapshot_fn","newChannel","state","run","runEvent","event_type","step","stepEvent","unsubscribe_fn","delete","FlowStep","initialState","_FlowStep_instances","_state","_events","_statusPrecedence","Created","Started","Completed","Failed","step_slug","started_at","completed_at","failed_at","error_message","waitForStatus","targetStatus","timeoutMs","signal","timeoutId","abortCleanup","cleanedUp","unbind","abortHandler","addEventListener","removeEventListener","applySnapshot","row","Date","updateState","shouldUpdateStatus_fn","currentStatus","newStatus","currentPrecedence","FlowRun","_FlowRun_instances","_steps","_disposed","_listenerCount","remaining_steps","__privateWrapper","_","checkAutoDispose_fn","stepSlug","existingStep","hasStep","Number","updateStepState","dispose","clear","PgflowClient","supabaseClient","_realtimeAdapter","_runs","realtimeStabilizationDelayMs","evt","toTypedRunEvent","toTypedStepEvent","startFlow","id","uuidv4","stepState","runId","disposeAll","keys","getRun","existingRun","Object","values","includes","flowRun","message"],"mappings":"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","x_google_ignoreList":[0,1,2,3,5]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgflow/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"@supabase/supabase-js": "^2.49.4",
|
|
13
13
|
"nanoevents": "^7.0.1",
|
|
14
14
|
"uuid": "^9.0.0",
|
|
15
|
-
"@pgflow/core": "0.
|
|
16
|
-
"@pgflow/dsl": "0.
|
|
15
|
+
"@pgflow/core": "0.12.0",
|
|
16
|
+
"@pgflow/dsl": "0.12.0"
|
|
17
17
|
},
|
|
18
18
|
"main": "./dist/index.js",
|
|
19
19
|
"module": "./dist/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"terser": "^5.43.0",
|
|
49
49
|
"vite-plugin-dts": "~3.8.1",
|
|
50
50
|
"vitest": "1.3.1",
|
|
51
|
-
"@pgflow/dsl": "0.
|
|
51
|
+
"@pgflow/dsl": "0.12.0"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"verify-exports": "node scripts/verify-exports.js"
|