@tanstack/workflow-runtime 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +22 -0
  2. package/dist/define-runtime.cjs +50 -0
  3. package/dist/define-runtime.cjs.map +1 -0
  4. package/dist/define-runtime.d.cts +16 -0
  5. package/dist/define-runtime.d.ts +16 -0
  6. package/dist/define-runtime.js +48 -0
  7. package/dist/define-runtime.js.map +1 -0
  8. package/dist/in-memory-store.cjs +457 -0
  9. package/dist/in-memory-store.cjs.map +1 -0
  10. package/dist/in-memory-store.d.cts +8 -0
  11. package/dist/in-memory-store.d.ts +8 -0
  12. package/dist/in-memory-store.js +457 -0
  13. package/dist/in-memory-store.js.map +1 -0
  14. package/dist/index.cjs +14 -0
  15. package/dist/index.d.cts +7 -0
  16. package/dist/index.d.ts +7 -0
  17. package/dist/index.js +7 -0
  18. package/dist/run-store-adapter.cjs +30 -0
  19. package/dist/run-store-adapter.cjs.map +1 -0
  20. package/dist/run-store-adapter.d.cts +7 -0
  21. package/dist/run-store-adapter.d.ts +7 -0
  22. package/dist/run-store-adapter.js +29 -0
  23. package/dist/run-store-adapter.js.map +1 -0
  24. package/dist/runtime-driver.cjs +334 -0
  25. package/dist/runtime-driver.cjs.map +1 -0
  26. package/dist/runtime-driver.d.cts +12 -0
  27. package/dist/runtime-driver.d.ts +12 -0
  28. package/dist/runtime-driver.js +334 -0
  29. package/dist/runtime-driver.js.map +1 -0
  30. package/dist/schedule-materializer.cjs +156 -0
  31. package/dist/schedule-materializer.cjs.map +1 -0
  32. package/dist/schedule-materializer.d.cts +28 -0
  33. package/dist/schedule-materializer.d.ts +28 -0
  34. package/dist/schedule-materializer.js +155 -0
  35. package/dist/schedule-materializer.js.map +1 -0
  36. package/dist/types.cjs +0 -0
  37. package/dist/types.d.cts +375 -0
  38. package/dist/types.d.ts +375 -0
  39. package/dist/types.js +1 -0
  40. package/package.json +60 -0
  41. package/src/define-runtime.ts +46 -0
  42. package/src/in-memory-store.ts +607 -0
  43. package/src/index.ts +74 -0
  44. package/src/run-store-adapter.ts +49 -0
  45. package/src/runtime-driver.ts +536 -0
  46. package/src/schedule-materializer.ts +272 -0
  47. package/src/types.ts +462 -0
@@ -0,0 +1,607 @@
1
+ /* eslint-disable @typescript-eslint/require-await -- In-memory implementation satisfies async storage contracts synchronously. */
2
+ import { LogConflictError } from '@tanstack/workflow-core'
3
+ import type {
4
+ DeleteReason,
5
+ RunState,
6
+ WorkflowEvent,
7
+ } from '@tanstack/workflow-core'
8
+ import type {
9
+ AppendEventsArgs,
10
+ AppendEventsResult,
11
+ ClaimDueScheduleBucketsArgs,
12
+ ClaimDueTimersArgs,
13
+ ClaimRunArgs,
14
+ ClaimRunResult,
15
+ ClaimStaleRunsArgs,
16
+ CreateRunArgs,
17
+ CreateRunResult,
18
+ DeliverApprovalArgs,
19
+ DeliverApprovalResult,
20
+ DeliverSignalArgs,
21
+ DeliverSignalResult,
22
+ HeartbeatRunLeaseArgs,
23
+ LeaseOwner,
24
+ ListRunsArgs,
25
+ LoadedExecution,
26
+ MarkRunErroredArgs,
27
+ MarkRunFinishedArgs,
28
+ MarkRunPausedArgs,
29
+ MarkScheduleBucketStartedArgs,
30
+ ReadEventsArgs,
31
+ ReleaseRunLeaseArgs,
32
+ RunClaim,
33
+ RunId,
34
+ RunSummary,
35
+ RunTimeline,
36
+ SaveRunStateArgs,
37
+ ScheduleBucket,
38
+ ScheduleBucketId,
39
+ ScheduleId,
40
+ ScheduleTimerArgs,
41
+ StoredWorkflowEvent,
42
+ TimerWakeup,
43
+ UpsertScheduleArgs,
44
+ WorkflowExecution,
45
+ WorkflowExecutionStore,
46
+ WorkflowLease,
47
+ WorkflowRunStoreAdapterStore,
48
+ } from './types'
49
+
50
+ interface TimerRecord extends TimerWakeup {
51
+ lease?: WorkflowLease
52
+ }
53
+
54
+ interface ScheduleRecord {
55
+ scheduleId: ScheduleId
56
+ workflowId: string
57
+ workflowVersion?: string
58
+ nextFireAt?: number
59
+ input: unknown
60
+ overlapPolicy: ScheduleBucket['overlapPolicy']
61
+ enabled: boolean
62
+ }
63
+
64
+ interface ScheduleBucketRecord extends ScheduleBucket {
65
+ status: 'claimed' | 'started'
66
+ lease?: WorkflowLease
67
+ }
68
+
69
+ export type InMemoryWorkflowExecutionStore = WorkflowExecutionStore &
70
+ WorkflowRunStoreAdapterStore
71
+
72
+ export function inMemoryWorkflowExecutionStore(): InMemoryWorkflowExecutionStore {
73
+ const runs = new Map<RunId, WorkflowExecution>()
74
+ const runStates = new Map<RunId, RunState>()
75
+ const logs = new Map<RunId, Array<StoredWorkflowEvent>>()
76
+ const timers = new Map<string, TimerRecord>()
77
+ const signalDeliveries = new Map<string, true>()
78
+ const schedules = new Map<ScheduleId, ScheduleRecord>()
79
+ const scheduleBuckets = new Map<string, ScheduleBucketRecord>()
80
+ const subscribers = new Map<
81
+ RunId,
82
+ Set<(event: WorkflowEvent, index: number) => void>
83
+ >()
84
+
85
+ function setRun(run: WorkflowExecution) {
86
+ runs.set(run.runId, cloneRun(run))
87
+ }
88
+
89
+ function getRun(runId: RunId) {
90
+ const run = runs.get(runId)
91
+ return run ? cloneRun(run) : undefined
92
+ }
93
+
94
+ function updateRun(
95
+ runId: RunId,
96
+ updater: (run: WorkflowExecution) => WorkflowExecution,
97
+ ) {
98
+ const existing = runs.get(runId)
99
+ if (!existing) return undefined
100
+ const next = updater(cloneRun(existing))
101
+ setRun(next)
102
+ return cloneRun(next)
103
+ }
104
+
105
+ return {
106
+ async createRun(args: CreateRunArgs): Promise<CreateRunResult> {
107
+ const existing = getRun(args.runId)
108
+ if (existing) return { kind: 'existing', run: existing }
109
+
110
+ const run: WorkflowExecution = {
111
+ runId: args.runId,
112
+ workflowId: args.workflowId,
113
+ workflowVersion: args.workflowVersion,
114
+ status: 'queued',
115
+ input: args.input,
116
+ createdAt: args.now,
117
+ updatedAt: args.now,
118
+ }
119
+ setRun(run)
120
+ return { kind: 'created', run: cloneRun(run) }
121
+ },
122
+
123
+ async loadRun(runId: RunId) {
124
+ return getRun(runId)
125
+ },
126
+
127
+ async loadExecution(runId: RunId): Promise<LoadedExecution | undefined> {
128
+ const run = getRun(runId)
129
+ if (!run) return undefined
130
+ return {
131
+ run,
132
+ events: cloneStoredEvents(logs.get(runId) ?? []),
133
+ }
134
+ },
135
+
136
+ async loadRunState(runId: RunId) {
137
+ const state = runStates.get(runId)
138
+ return state ? cloneRunState(state) : undefined
139
+ },
140
+
141
+ async saveRunState(args: SaveRunStateArgs) {
142
+ const state = cloneRunState(args.state)
143
+ runStates.set(state.runId, state)
144
+ setRun(executionFromRunState(state, runs.get(state.runId)?.lease))
145
+ },
146
+
147
+ async deleteRun(runId: RunId, _reason: DeleteReason) {
148
+ runs.delete(runId)
149
+ runStates.delete(runId)
150
+ logs.delete(runId)
151
+ subscribers.delete(runId)
152
+ for (const [key, timer] of timers.entries()) {
153
+ if (timer.runId === runId) timers.delete(key)
154
+ }
155
+ for (const key of signalDeliveries.keys()) {
156
+ if (key.startsWith(`${runId}:`)) signalDeliveries.delete(key)
157
+ }
158
+ },
159
+
160
+ async appendEvents(args: AppendEventsArgs): Promise<AppendEventsResult> {
161
+ const log = logs.get(args.runId) ?? []
162
+ if (log.length !== args.expectedNextIndex) {
163
+ throw new LogConflictError(
164
+ args.runId,
165
+ args.expectedNextIndex,
166
+ log[args.expectedNextIndex]?.event,
167
+ )
168
+ }
169
+
170
+ for (const event of args.events) {
171
+ const stored = storeEvent(args.runId, log.length, event)
172
+ log.push(stored)
173
+ publish(subscribers, args.runId, stored.event, stored.eventIndex)
174
+ }
175
+
176
+ logs.set(args.runId, log)
177
+ return { nextIndex: log.length }
178
+ },
179
+
180
+ async readEvents(args: ReadEventsArgs) {
181
+ const fromIndex = args.fromIndex ?? 0
182
+ return cloneStoredEvents((logs.get(args.runId) ?? []).slice(fromIndex))
183
+ },
184
+
185
+ subscribeEvents(runId, fromIndex, onEvent) {
186
+ const log = logs.get(runId) ?? []
187
+ for (let index = fromIndex; index < log.length; index++) {
188
+ const stored = log[index]
189
+ if (stored) onEvent(stored.event, stored.eventIndex)
190
+ }
191
+
192
+ let runSubscribers = subscribers.get(runId)
193
+ if (!runSubscribers) {
194
+ runSubscribers = new Set()
195
+ subscribers.set(runId, runSubscribers)
196
+ }
197
+ runSubscribers.add(onEvent)
198
+
199
+ return () => {
200
+ runSubscribers.delete(onEvent)
201
+ if (runSubscribers.size === 0) subscribers.delete(runId)
202
+ }
203
+ },
204
+
205
+ async claimRun(args: ClaimRunArgs): Promise<ClaimRunResult> {
206
+ const existing = getRun(args.runId)
207
+ if (!existing) return { kind: 'not-found' }
208
+ if (isTerminal(existing.status)) {
209
+ return { kind: 'not-claimable', run: existing }
210
+ }
211
+ if (!canClaim(existing.lease, args.leaseOwner, args.now)) {
212
+ return { kind: 'not-claimable', run: existing }
213
+ }
214
+
215
+ const claimed = updateRun(args.runId, (run) => ({
216
+ ...run,
217
+ status: 'running',
218
+ lease: lease(args.leaseOwner, args.leaseMs, args.now),
219
+ updatedAt: args.now,
220
+ }))
221
+ return { kind: 'claimed', run: claimed! }
222
+ },
223
+
224
+ async heartbeatRunLease(args: HeartbeatRunLeaseArgs) {
225
+ updateRun(args.runId, (run) => {
226
+ if (run.lease?.owner !== args.leaseOwner) return run
227
+ return {
228
+ ...run,
229
+ lease: lease(args.leaseOwner, args.leaseMs, args.now),
230
+ updatedAt: args.now,
231
+ }
232
+ })
233
+ },
234
+
235
+ async releaseRunLease(args: ReleaseRunLeaseArgs) {
236
+ updateRun(args.runId, (run) => {
237
+ if (run.lease?.owner !== args.leaseOwner) return run
238
+ return {
239
+ ...run,
240
+ lease: undefined,
241
+ }
242
+ })
243
+ },
244
+
245
+ async markRunPaused(args: MarkRunPausedArgs) {
246
+ updateRun(args.runId, (run) => ({
247
+ ...run,
248
+ status: 'paused',
249
+ waitingFor: args.waitingFor,
250
+ pendingApproval: args.pendingApproval,
251
+ wakeAt: args.wakeAt,
252
+ lease: undefined,
253
+ updatedAt: args.now,
254
+ }))
255
+ },
256
+
257
+ async markRunFinished(args: MarkRunFinishedArgs) {
258
+ updateRun(args.runId, (run) => ({
259
+ ...run,
260
+ status: 'finished',
261
+ output: args.output,
262
+ waitingFor: undefined,
263
+ pendingApproval: undefined,
264
+ wakeAt: undefined,
265
+ lease: undefined,
266
+ updatedAt: args.now,
267
+ }))
268
+ },
269
+
270
+ async markRunErrored(args: MarkRunErroredArgs) {
271
+ void args.code
272
+ updateRun(args.runId, (run) => ({
273
+ ...run,
274
+ status: 'errored',
275
+ error: args.error,
276
+ waitingFor: undefined,
277
+ pendingApproval: undefined,
278
+ wakeAt: undefined,
279
+ lease: undefined,
280
+ updatedAt: args.now,
281
+ }))
282
+ },
283
+
284
+ async scheduleTimer(args: ScheduleTimerArgs) {
285
+ timers.set(timerKey(args.runId, args.signalId), {
286
+ runId: args.runId,
287
+ workflowId: args.workflowId,
288
+ workflowVersion: args.workflowVersion,
289
+ wakeAt: args.wakeAt,
290
+ signalId: args.signalId,
291
+ })
292
+ updateRun(args.runId, (run) => ({
293
+ ...run,
294
+ wakeAt: args.wakeAt,
295
+ updatedAt: args.now,
296
+ }))
297
+ },
298
+
299
+ async claimDueTimers(args: ClaimDueTimersArgs) {
300
+ const due: Array<TimerWakeup> = []
301
+ for (const [key, timer] of timers.entries()) {
302
+ if (due.length >= args.limit) break
303
+ if (timer.wakeAt > args.now) continue
304
+ if (!canClaim(timer.lease, args.leaseOwner, args.now)) continue
305
+
306
+ timers.set(key, {
307
+ ...timer,
308
+ lease: lease(args.leaseOwner, args.leaseMs, args.now),
309
+ })
310
+ due.push(cloneTimerWakeup(timer))
311
+ }
312
+ return due
313
+ },
314
+
315
+ async deliverSignal<TPayload>(
316
+ args: DeliverSignalArgs<TPayload>,
317
+ ): Promise<DeliverSignalResult> {
318
+ const run = getRun(args.runId)
319
+ if (!run) return { kind: 'not-found' }
320
+
321
+ const key = signalKey(args.runId, args.delivery.signalId)
322
+ if (signalDeliveries.has(key)) return { kind: 'duplicate', run }
323
+ if (run.waitingFor?.signalName !== args.delivery.name) {
324
+ return { kind: 'not-waiting', run }
325
+ }
326
+
327
+ signalDeliveries.set(key, true)
328
+ timers.delete(timerKey(args.runId, args.delivery.signalId))
329
+ const updated = updateRun(args.runId, (current) => ({
330
+ ...current,
331
+ status: 'queued',
332
+ waitingFor: undefined,
333
+ pendingApproval: undefined,
334
+ wakeAt: undefined,
335
+ updatedAt: args.now,
336
+ }))
337
+ return { kind: 'delivered', run: updated! }
338
+ },
339
+
340
+ async deliverApproval(
341
+ args: DeliverApprovalArgs,
342
+ ): Promise<DeliverApprovalResult> {
343
+ const run = getRun(args.runId)
344
+ if (!run) return { kind: 'not-found' }
345
+
346
+ const key = signalKey(args.runId, `approval:${args.approval.approvalId}`)
347
+ if (signalDeliveries.has(key)) return { kind: 'duplicate', run }
348
+ if (run.pendingApproval?.approvalId !== args.approval.approvalId) {
349
+ return { kind: 'not-waiting', run }
350
+ }
351
+
352
+ signalDeliveries.set(key, true)
353
+ const updated = updateRun(args.runId, (current) => ({
354
+ ...current,
355
+ status: 'queued',
356
+ waitingFor: undefined,
357
+ pendingApproval: undefined,
358
+ wakeAt: undefined,
359
+ updatedAt: args.now,
360
+ }))
361
+ return { kind: 'delivered', run: updated! }
362
+ },
363
+
364
+ async upsertSchedule(args: UpsertScheduleArgs) {
365
+ schedules.set(args.scheduleId, {
366
+ scheduleId: args.scheduleId,
367
+ workflowId: args.workflowId,
368
+ workflowVersion: args.workflowVersion,
369
+ nextFireAt: args.nextFireAt,
370
+ input: args.input,
371
+ overlapPolicy: args.overlapPolicy,
372
+ enabled: args.enabled,
373
+ })
374
+ },
375
+
376
+ async claimDueScheduleBuckets(args: ClaimDueScheduleBucketsArgs) {
377
+ const due: Array<ScheduleBucket> = []
378
+ for (const schedule of schedules.values()) {
379
+ if (due.length >= args.limit) break
380
+ if (!schedule.enabled || schedule.nextFireAt === undefined) continue
381
+ if (schedule.nextFireAt > args.now) continue
382
+
383
+ const bucketId = `${schedule.nextFireAt}` satisfies ScheduleBucketId
384
+ const key = scheduleBucketKey(schedule.scheduleId, bucketId)
385
+ const existing = scheduleBuckets.get(key)
386
+ if (existing?.status === 'started') continue
387
+ if (existing && !canClaim(existing.lease, args.leaseOwner, args.now)) {
388
+ continue
389
+ }
390
+
391
+ const bucket: ScheduleBucketRecord = {
392
+ scheduleId: schedule.scheduleId,
393
+ bucketId,
394
+ workflowId: schedule.workflowId,
395
+ workflowVersion: schedule.workflowVersion,
396
+ runId: `${schedule.workflowId}:${schedule.scheduleId}:${bucketId}`,
397
+ fireAt: schedule.nextFireAt,
398
+ input: schedule.input,
399
+ overlapPolicy: schedule.overlapPolicy,
400
+ status: 'claimed',
401
+ lease: lease(args.leaseOwner, args.leaseMs, args.now),
402
+ }
403
+ scheduleBuckets.set(key, bucket)
404
+ due.push(cloneScheduleBucket(bucket))
405
+ }
406
+ return due
407
+ },
408
+
409
+ async markScheduleBucketStarted(args: MarkScheduleBucketStartedArgs) {
410
+ const key = scheduleBucketKey(args.scheduleId, args.bucketId)
411
+ const bucket = scheduleBuckets.get(key)
412
+ if (!bucket) return
413
+ scheduleBuckets.set(key, {
414
+ ...bucket,
415
+ runId: args.runId,
416
+ status: 'started',
417
+ })
418
+ },
419
+
420
+ async claimStaleRuns(args: ClaimStaleRunsArgs) {
421
+ const claims: Array<RunClaim> = []
422
+ for (const run of runs.values()) {
423
+ if (claims.length >= args.limit) break
424
+ if (run.status !== 'running') continue
425
+ if (!run.lease || run.lease.expiresAt > args.now) continue
426
+
427
+ const nextLease = lease(args.leaseOwner, args.leaseMs, args.now)
428
+ const claimed = updateRun(run.runId, (current) => ({
429
+ ...current,
430
+ lease: nextLease,
431
+ updatedAt: args.now,
432
+ }))
433
+ if (claimed) claims.push({ run: claimed, lease: cloneLease(nextLease) })
434
+ }
435
+ return claims
436
+ },
437
+
438
+ async listRuns(args: ListRunsArgs) {
439
+ const offset = args.cursor ? Number(args.cursor) : 0
440
+ const start = Number.isFinite(offset) && offset > 0 ? offset : 0
441
+ return Array.from(runs.values())
442
+ .filter((run) => !args.workflowId || run.workflowId === args.workflowId)
443
+ .filter((run) => !args.status || run.status === args.status)
444
+ .sort((a, b) => b.updatedAt - a.updatedAt)
445
+ .slice(start, start + args.limit)
446
+ .map(toRunSummary)
447
+ },
448
+
449
+ async getRunTimeline(runId: RunId): Promise<RunTimeline | undefined> {
450
+ const run = getRun(runId)
451
+ if (!run) return undefined
452
+ return {
453
+ run,
454
+ events: cloneStoredEvents(logs.get(runId) ?? []),
455
+ }
456
+ },
457
+ }
458
+ }
459
+
460
+ function executionFromRunState(
461
+ state: RunState,
462
+ leaseValue?: WorkflowLease,
463
+ ): WorkflowExecution {
464
+ return {
465
+ runId: state.runId,
466
+ workflowId: state.workflowId,
467
+ workflowVersion: state.workflowVersion,
468
+ status: state.status,
469
+ input: state.input,
470
+ output: state.output,
471
+ error: state.error,
472
+ waitingFor: state.waitingFor,
473
+ pendingApproval: state.pendingApproval,
474
+ wakeAt:
475
+ state.waitingFor?.signalName === '__timer'
476
+ ? state.waitingFor.deadline
477
+ : undefined,
478
+ lease: leaseValue ? cloneLease(leaseValue) : undefined,
479
+ createdAt: state.createdAt,
480
+ updatedAt: state.updatedAt,
481
+ }
482
+ }
483
+
484
+ function storeEvent(
485
+ runId: RunId,
486
+ eventIndex: number,
487
+ event: WorkflowEvent,
488
+ ): StoredWorkflowEvent {
489
+ return {
490
+ runId,
491
+ eventIndex,
492
+ eventType: event.type,
493
+ stepId: getStepId(event),
494
+ event,
495
+ createdAt: event.ts,
496
+ }
497
+ }
498
+
499
+ function getStepId(event: WorkflowEvent) {
500
+ return 'stepId' in event ? event.stepId : undefined
501
+ }
502
+
503
+ function lease(owner: LeaseOwner, leaseMs: number, now: number): WorkflowLease {
504
+ return { owner, expiresAt: now + leaseMs }
505
+ }
506
+
507
+ function canClaim(
508
+ existing: WorkflowLease | undefined,
509
+ owner: LeaseOwner,
510
+ now: number,
511
+ ) {
512
+ return !existing || existing.owner === owner || existing.expiresAt <= now
513
+ }
514
+
515
+ function isTerminal(status: WorkflowExecution['status']) {
516
+ return status === 'finished' || status === 'errored' || status === 'aborted'
517
+ }
518
+
519
+ function timerKey(runId: RunId, signalId: string) {
520
+ return `${runId}:${signalId}`
521
+ }
522
+
523
+ function signalKey(runId: RunId, signalId: string) {
524
+ return `${runId}:${signalId}`
525
+ }
526
+
527
+ function scheduleBucketKey(scheduleId: ScheduleId, bucketId: ScheduleBucketId) {
528
+ return `${scheduleId}:${bucketId}`
529
+ }
530
+
531
+ function publish(
532
+ subscribers: Map<RunId, Set<(event: WorkflowEvent, index: number) => void>>,
533
+ runId: RunId,
534
+ event: WorkflowEvent,
535
+ index: number,
536
+ ) {
537
+ const runSubscribers = subscribers.get(runId)
538
+ if (!runSubscribers) return
539
+ for (const subscriber of runSubscribers) {
540
+ try {
541
+ subscriber(event, index)
542
+ } catch {
543
+ /* Subscriber errors must not break persistence. */
544
+ }
545
+ }
546
+ }
547
+
548
+ function toRunSummary(run: WorkflowExecution): RunSummary {
549
+ return {
550
+ runId: run.runId,
551
+ workflowId: run.workflowId,
552
+ workflowVersion: run.workflowVersion,
553
+ status: run.status,
554
+ waitingFor: run.waitingFor,
555
+ pendingApproval: run.pendingApproval,
556
+ wakeAt: run.wakeAt,
557
+ createdAt: run.createdAt,
558
+ updatedAt: run.updatedAt,
559
+ }
560
+ }
561
+
562
+ function cloneRun(run: WorkflowExecution): WorkflowExecution {
563
+ return {
564
+ ...run,
565
+ waitingFor: run.waitingFor
566
+ ? { ...run.waitingFor, meta: cloneRecord(run.waitingFor.meta) }
567
+ : undefined,
568
+ pendingApproval: run.pendingApproval
569
+ ? { ...run.pendingApproval }
570
+ : undefined,
571
+ lease: run.lease ? cloneLease(run.lease) : undefined,
572
+ }
573
+ }
574
+
575
+ function cloneRunState(state: RunState): RunState {
576
+ return {
577
+ ...state,
578
+ waitingFor: state.waitingFor
579
+ ? { ...state.waitingFor, meta: cloneRecord(state.waitingFor.meta) }
580
+ : undefined,
581
+ pendingApproval: state.pendingApproval
582
+ ? { ...state.pendingApproval }
583
+ : undefined,
584
+ }
585
+ }
586
+
587
+ function cloneStoredEvents(
588
+ events: ReadonlyArray<StoredWorkflowEvent>,
589
+ ): Array<StoredWorkflowEvent> {
590
+ return events.map((event) => ({ ...event }))
591
+ }
592
+
593
+ function cloneTimerWakeup(timer: TimerWakeup): TimerWakeup {
594
+ return { ...timer }
595
+ }
596
+
597
+ function cloneScheduleBucket(bucket: ScheduleBucket): ScheduleBucket {
598
+ return { ...bucket }
599
+ }
600
+
601
+ function cloneLease(leaseValue: WorkflowLease): WorkflowLease {
602
+ return { ...leaseValue }
603
+ }
604
+
605
+ function cloneRecord(value: Record<string, unknown> | undefined) {
606
+ return value ? { ...value } : value
607
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ export { cron, defineWorkflowRuntime, every } from './define-runtime'
2
+ export {
3
+ inMemoryWorkflowExecutionStore,
4
+ type InMemoryWorkflowExecutionStore,
5
+ } from './in-memory-store'
6
+ export { createRuntimeDriver } from './runtime-driver'
7
+ export { createRunStoreAdapter } from './run-store-adapter'
8
+ export { materializeWorkflowSchedules } from './schedule-materializer'
9
+ export type {
10
+ MaterializedWorkflowSchedule,
11
+ MaterializeWorkflowSchedulesOptions,
12
+ } from './schedule-materializer'
13
+
14
+ export type {
15
+ AppendEventsArgs,
16
+ AppendEventsResult,
17
+ ClaimDueScheduleBucketsArgs,
18
+ ClaimDueTimersArgs,
19
+ ClaimRunArgs,
20
+ ClaimRunResult,
21
+ ClaimStaleRunsArgs,
22
+ CreateRunArgs,
23
+ CreateRunResult,
24
+ DeliverApprovalArgs,
25
+ DeliverApprovalResult,
26
+ DeliverSignalArgs,
27
+ DeliverSignalResult,
28
+ HeartbeatRunLeaseArgs,
29
+ LeaseOwner,
30
+ ListRunsArgs,
31
+ LoadedExecution,
32
+ MarkRunErroredArgs,
33
+ MarkRunFinishedArgs,
34
+ MarkRunPausedArgs,
35
+ MarkScheduleBucketStartedArgs,
36
+ ReadEventsArgs,
37
+ ReleaseRunLeaseArgs,
38
+ RunClaim,
39
+ RunId,
40
+ RunSummary,
41
+ RunTimeline,
42
+ SaveRunStateArgs,
43
+ ScheduleBucket,
44
+ ScheduleBucketId,
45
+ ScheduleId,
46
+ ScheduleTimerArgs,
47
+ StoredWorkflowEvent,
48
+ TimerWakeup,
49
+ UpsertScheduleArgs,
50
+ WorkflowExecution,
51
+ WorkflowExecutionStatus,
52
+ WorkflowExecutionStore,
53
+ WorkflowId,
54
+ WorkflowLease,
55
+ WorkflowLoader,
56
+ WorkflowLoaderResult,
57
+ WorkflowOverlapPolicy,
58
+ WorkflowRegistration,
59
+ WorkflowRegistrationMap,
60
+ WorkflowRuntimeConfig,
61
+ WorkflowRuntimeDeliverApprovalArgs,
62
+ WorkflowRuntimeDeliverSignalArgs,
63
+ WorkflowRuntimeDefinition,
64
+ WorkflowRuntimeRunResult,
65
+ WorkflowRuntimeRunResultKind,
66
+ WorkflowRuntimeStartRunArgs,
67
+ WorkflowRuntimeSweepArgs,
68
+ WorkflowRuntimeSweepResult,
69
+ WorkflowRunStoreAdapter,
70
+ WorkflowRunStoreAdapterStore,
71
+ WorkflowScheduleDefinition,
72
+ WorkflowScheduleSpec,
73
+ WorkflowVersion,
74
+ } from './types'