@hotmeshio/hotmesh 0.13.0 → 0.14.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.
Files changed (194) hide show
  1. package/README.md +18 -22
  2. package/build/modules/enums.d.ts +60 -5
  3. package/build/modules/enums.js +62 -7
  4. package/build/modules/errors.d.ts +15 -3
  5. package/build/modules/errors.js +17 -2
  6. package/build/package.json +6 -1
  7. package/build/services/activities/activity/context.d.ts +22 -0
  8. package/build/services/activities/activity/context.js +76 -0
  9. package/build/services/activities/activity/index.d.ts +116 -0
  10. package/build/services/activities/activity/index.js +299 -0
  11. package/build/services/activities/activity/mapping.d.ts +12 -0
  12. package/build/services/activities/activity/mapping.js +63 -0
  13. package/build/services/activities/activity/process.d.ts +28 -0
  14. package/build/services/activities/activity/process.js +100 -0
  15. package/build/services/activities/activity/protocol.d.ts +39 -0
  16. package/build/services/activities/activity/protocol.js +151 -0
  17. package/build/services/activities/activity/state.d.ts +40 -0
  18. package/build/services/activities/activity/state.js +143 -0
  19. package/build/services/activities/activity/transition.d.ts +23 -0
  20. package/build/services/activities/activity/transition.js +71 -0
  21. package/build/services/activities/activity/verify.d.ts +22 -0
  22. package/build/services/activities/activity/verify.js +85 -0
  23. package/build/services/activities/await.d.ts +1 -4
  24. package/build/services/activities/await.js +2 -36
  25. package/build/services/activities/cycle.d.ts +1 -11
  26. package/build/services/activities/cycle.js +3 -46
  27. package/build/services/activities/hook.d.ts +2 -11
  28. package/build/services/activities/hook.js +30 -50
  29. package/build/services/activities/interrupt.d.ts +2 -4
  30. package/build/services/activities/interrupt.js +4 -38
  31. package/build/services/activities/signal.d.ts +1 -11
  32. package/build/services/activities/signal.js +3 -48
  33. package/build/services/activities/trigger.d.ts +1 -3
  34. package/build/services/activities/trigger.js +0 -3
  35. package/build/services/activities/worker.d.ts +3 -6
  36. package/build/services/activities/worker.js +4 -40
  37. package/build/services/connector/factory.d.ts +6 -0
  38. package/build/services/connector/factory.js +24 -0
  39. package/build/services/durable/activity.d.ts +1 -1
  40. package/build/services/durable/activity.js +2 -2
  41. package/build/services/durable/client.d.ts +24 -29
  42. package/build/services/durable/client.js +24 -29
  43. package/build/services/durable/connection.d.ts +13 -7
  44. package/build/services/durable/connection.js +13 -7
  45. package/build/services/durable/handle.d.ts +58 -40
  46. package/build/services/durable/handle.js +60 -40
  47. package/build/services/durable/index.d.ts +148 -286
  48. package/build/services/durable/index.js +157 -292
  49. package/build/services/durable/interceptor.d.ts +43 -33
  50. package/build/services/durable/interceptor.js +59 -39
  51. package/build/services/durable/schemas/factory.d.ts +1 -1
  52. package/build/services/durable/schemas/factory.js +168 -38
  53. package/build/services/durable/telemetry.d.ts +80 -0
  54. package/build/services/durable/telemetry.js +137 -0
  55. package/build/services/durable/worker.d.ts +100 -21
  56. package/build/services/durable/worker.js +304 -63
  57. package/build/services/durable/workflow/all.d.ts +1 -1
  58. package/build/services/durable/workflow/all.js +1 -1
  59. package/build/services/durable/workflow/cancellationScope.d.ts +104 -0
  60. package/build/services/durable/workflow/cancellationScope.js +139 -0
  61. package/build/services/durable/workflow/common.d.ts +5 -4
  62. package/build/services/durable/workflow/common.js +6 -1
  63. package/build/services/durable/workflow/{waitFor.d.ts → condition.d.ts} +9 -8
  64. package/build/services/durable/workflow/{waitFor.js → condition.js} +44 -11
  65. package/build/services/durable/workflow/continueAsNew.d.ts +65 -0
  66. package/build/services/durable/workflow/continueAsNew.js +92 -0
  67. package/build/services/durable/workflow/didRun.d.ts +1 -1
  68. package/build/services/durable/workflow/didRun.js +3 -3
  69. package/build/services/durable/workflow/enrich.d.ts +5 -0
  70. package/build/services/durable/workflow/enrich.js +5 -0
  71. package/build/services/durable/workflow/entityMethods.d.ts +7 -0
  72. package/build/services/durable/workflow/entityMethods.js +7 -0
  73. package/build/services/durable/workflow/execHook.js +3 -3
  74. package/build/services/durable/workflow/execHookBatch.js +2 -2
  75. package/build/services/durable/workflow/{execChild.d.ts → executeChild.d.ts} +4 -40
  76. package/build/services/durable/workflow/{execChild.js → executeChild.js} +36 -45
  77. package/build/services/durable/workflow/hook.d.ts +1 -1
  78. package/build/services/durable/workflow/hook.js +4 -3
  79. package/build/services/durable/workflow/index.d.ts +45 -50
  80. package/build/services/durable/workflow/index.js +46 -51
  81. package/build/services/durable/workflow/interruption.d.ts +7 -6
  82. package/build/services/durable/workflow/interruption.js +11 -7
  83. package/build/services/durable/workflow/patched.d.ts +72 -0
  84. package/build/services/durable/workflow/patched.js +110 -0
  85. package/build/services/durable/workflow/proxyActivities.d.ts +7 -7
  86. package/build/services/durable/workflow/proxyActivities.js +50 -15
  87. package/build/services/durable/workflow/searchMethods.d.ts +7 -0
  88. package/build/services/durable/workflow/searchMethods.js +7 -0
  89. package/build/services/durable/workflow/signal.d.ts +4 -4
  90. package/build/services/durable/workflow/signal.js +4 -4
  91. package/build/services/durable/workflow/{sleepFor.d.ts → sleep.d.ts} +7 -7
  92. package/build/services/durable/workflow/{sleepFor.js → sleep.js} +39 -10
  93. package/build/services/durable/workflow/terminate.d.ts +55 -0
  94. package/build/services/durable/workflow/{interrupt.js → terminate.js} +21 -21
  95. package/build/services/durable/workflow/trace.js +2 -2
  96. package/build/services/durable/workflow/uuid4.d.ts +14 -0
  97. package/build/services/durable/workflow/uuid4.js +39 -0
  98. package/build/services/durable/workflow/{context.d.ts → workflowInfo.d.ts} +5 -5
  99. package/build/services/durable/workflow/{context.js → workflowInfo.js} +7 -7
  100. package/build/services/engine/compiler.d.ts +19 -0
  101. package/build/services/engine/compiler.js +20 -0
  102. package/build/services/engine/completion.d.ts +46 -0
  103. package/build/services/engine/completion.js +145 -0
  104. package/build/services/engine/dispatch.d.ts +24 -0
  105. package/build/services/engine/dispatch.js +98 -0
  106. package/build/services/engine/index.d.ts +49 -81
  107. package/build/services/engine/index.js +175 -573
  108. package/build/services/engine/init.d.ts +42 -0
  109. package/build/services/engine/init.js +74 -0
  110. package/build/services/engine/pubsub.d.ts +50 -0
  111. package/build/services/engine/pubsub.js +118 -0
  112. package/build/services/engine/reporting.d.ts +20 -0
  113. package/build/services/engine/reporting.js +38 -0
  114. package/build/services/engine/schema.d.ts +23 -0
  115. package/build/services/engine/schema.js +62 -0
  116. package/build/services/engine/signal.d.ts +57 -0
  117. package/build/services/engine/signal.js +117 -0
  118. package/build/services/engine/state.d.ts +35 -0
  119. package/build/services/engine/state.js +61 -0
  120. package/build/services/engine/version.d.ts +31 -0
  121. package/build/services/engine/version.js +73 -0
  122. package/build/services/hotmesh/deployment.d.ts +21 -0
  123. package/build/services/hotmesh/deployment.js +25 -0
  124. package/build/services/hotmesh/index.d.ts +141 -532
  125. package/build/services/hotmesh/index.js +222 -673
  126. package/build/services/hotmesh/init.d.ts +42 -0
  127. package/build/services/hotmesh/init.js +93 -0
  128. package/build/services/hotmesh/jobs.d.ts +67 -0
  129. package/build/services/hotmesh/jobs.js +99 -0
  130. package/build/services/hotmesh/pubsub.d.ts +38 -0
  131. package/build/services/hotmesh/pubsub.js +54 -0
  132. package/build/services/hotmesh/quorum.d.ts +30 -0
  133. package/build/services/hotmesh/quorum.js +62 -0
  134. package/build/services/hotmesh/validation.d.ts +6 -0
  135. package/build/services/hotmesh/validation.js +28 -0
  136. package/build/services/quorum/index.js +1 -0
  137. package/build/services/router/consumption/index.d.ts +11 -5
  138. package/build/services/router/consumption/index.js +24 -17
  139. package/build/services/router/error-handling/index.d.ts +2 -2
  140. package/build/services/router/error-handling/index.js +14 -14
  141. package/build/services/router/index.d.ts +1 -1
  142. package/build/services/router/index.js +2 -2
  143. package/build/services/serializer/index.d.ts +22 -0
  144. package/build/services/serializer/index.js +39 -1
  145. package/build/services/store/index.d.ts +1 -0
  146. package/build/services/store/providers/postgres/exporter-sql.d.ts +2 -2
  147. package/build/services/store/providers/postgres/exporter-sql.js +4 -4
  148. package/build/services/store/providers/postgres/kvtables.js +7 -6
  149. package/build/services/store/providers/postgres/kvtypes/hash/basic.js +67 -52
  150. package/build/services/store/providers/postgres/kvtypes/hash/jsonb.js +87 -72
  151. package/build/services/store/providers/postgres/kvtypes/hash/udata.js +106 -79
  152. package/build/services/store/providers/postgres/kvtypes/hash/utils.d.ts +16 -0
  153. package/build/services/store/providers/postgres/kvtypes/hash/utils.js +29 -16
  154. package/build/services/store/providers/postgres/postgres.d.ts +1 -0
  155. package/build/services/store/providers/postgres/postgres.js +14 -4
  156. package/build/services/stream/factory.d.ts +3 -1
  157. package/build/services/stream/factory.js +2 -2
  158. package/build/services/stream/index.d.ts +1 -0
  159. package/build/services/stream/providers/nats/nats.d.ts +1 -0
  160. package/build/services/stream/providers/nats/nats.js +1 -0
  161. package/build/services/stream/providers/postgres/credentials.d.ts +56 -0
  162. package/build/services/stream/providers/postgres/credentials.js +129 -0
  163. package/build/services/stream/providers/postgres/kvtables.js +18 -0
  164. package/build/services/stream/providers/postgres/messages.js +7 -7
  165. package/build/services/stream/providers/postgres/notifications.js +16 -2
  166. package/build/services/stream/providers/postgres/postgres.d.ts +7 -0
  167. package/build/services/stream/providers/postgres/postgres.js +35 -4
  168. package/build/services/stream/providers/postgres/procedures.d.ts +21 -0
  169. package/build/services/stream/providers/postgres/procedures.js +213 -0
  170. package/build/services/stream/providers/postgres/secured.d.ts +34 -0
  171. package/build/services/stream/providers/postgres/secured.js +146 -0
  172. package/build/services/stream/providers/postgres/stats.d.ts +1 -0
  173. package/build/services/stream/providers/postgres/stats.js +1 -0
  174. package/build/services/stream/registry.d.ts +1 -1
  175. package/build/services/stream/registry.js +5 -2
  176. package/build/services/telemetry/index.d.ts +10 -1
  177. package/build/services/telemetry/index.js +40 -7
  178. package/build/services/worker/credentials.d.ts +51 -0
  179. package/build/services/worker/credentials.js +87 -0
  180. package/build/services/worker/index.d.ts +2 -2
  181. package/build/services/worker/index.js +7 -6
  182. package/build/types/codec.d.ts +84 -0
  183. package/build/types/codec.js +2 -0
  184. package/build/types/durable.d.ts +104 -28
  185. package/build/types/error.d.ts +10 -1
  186. package/build/types/hotmesh.d.ts +67 -4
  187. package/build/types/index.d.ts +2 -1
  188. package/build/types/provider.d.ts +2 -2
  189. package/build/types/quorum.d.ts +35 -1
  190. package/build/types/stream.d.ts +12 -6
  191. package/package.json +6 -1
  192. package/build/services/activities/activity.d.ts +0 -192
  193. package/build/services/activities/activity.js +0 -786
  194. package/build/services/durable/workflow/interrupt.d.ts +0 -55
@@ -9,12 +9,18 @@ import { StreamData, StreamError } from './stream';
9
9
  type WorkflowConfig = {
10
10
  /**
11
11
  * Backoff coefficient for retry mechanism.
12
- * @default 10 (HMSH_DURABLE_EXP_BACKOFF)
12
+ * @default 5 (HMSH_DURABLE_EXP_BACKOFF)
13
13
  */
14
14
  backoffCoefficient?: number;
15
+ /**
16
+ * Initial interval before the first retry attempt.
17
+ * Formula: initialInterval * backoffCoefficient^retryCount, clamped by maximumInterval.
18
+ * @default '1s' (HMSH_DURABLE_INITIAL_INTERVAL)
19
+ */
20
+ initialInterval?: string;
15
21
  /**
16
22
  * Maximum number of attempts for retries.
17
- * @default 5 (HMSH_DURABLE_MAX_ATTEMPTS)
23
+ * @default 50 (HMSH_DURABLE_MAX_ATTEMPTS)
18
24
  */
19
25
  maximumAttempts?: number;
20
26
  /**
@@ -114,8 +120,8 @@ type DurableActivityContext = {
114
120
  activityName: string;
115
121
  /** The arguments passed to the activity */
116
122
  arguments: any[];
117
- /** Optional metadata provided via `proxyActivities({ argumentMetadata })` */
118
- argumentMetadata: Record<string, any>;
123
+ /** Optional metadata provided via `proxyActivities({ headers })` */
124
+ headers: Record<string, any>;
119
125
  /** The workflow ID of the parent workflow that dispatched this activity */
120
126
  workflowId: string;
121
127
  /** The workflow topic of the parent workflow */
@@ -371,7 +377,8 @@ type SignalOptions = {
371
377
  type ActivityWorkflowDataType = {
372
378
  activityName: string;
373
379
  arguments: any[];
374
- argumentMetadata?: Record<string, any>;
380
+ headers?: Record<string, any>;
381
+ startToCloseTimeout?: number;
375
382
  workflowId: string;
376
383
  workflowTopic: string;
377
384
  };
@@ -383,6 +390,7 @@ type WorkflowDataType = {
383
390
  originJobId?: string;
384
391
  canRetry?: boolean;
385
392
  expire?: number;
393
+ continueGeneration?: number;
386
394
  };
387
395
  type Connection = ProviderConfig | ProvidersConfig;
388
396
  type ClientConfig = {
@@ -403,6 +411,14 @@ type WorkerConfig = {
403
411
  taskQueue: string;
404
412
  /** Target function or a record type with a name (string) and reference function */
405
413
  workflow: Function | Record<string | symbol, Function>;
414
+ /**
415
+ * Optional activity functions to register with this worker's task queue.
416
+ * When provided, these activities are registered and served on `{taskQueue}-activity`.
417
+ * Workflows can then call them via `proxyActivities()` without passing activities inline.
418
+ *
419
+ * Workflows can then call them via `proxyActivities()` without passing activities inline.
420
+ */
421
+ activities?: Record<string, Function>;
406
422
  /** Additional options for configuring the worker */
407
423
  options?: WorkerOptions;
408
424
  /** Search options for workflow execution details */
@@ -413,6 +429,19 @@ type WorkerConfig = {
413
429
  * when identifying the point of presence within the mesh.
414
430
  */
415
431
  guid?: string;
432
+ /**
433
+ * Scoped Postgres credentials for database-level worker isolation.
434
+ * When provided, the worker connects as a restricted Postgres role
435
+ * that can only dequeue/ack/respond on its allowed stream names
436
+ * via SECURITY DEFINER stored procedures.
437
+ *
438
+ * Provision credentials via `HotMesh.provisionWorkerRole()` (or
439
+ * the convenience alias `Durable.provisionWorkerRole()`).
440
+ */
441
+ workerCredentials?: {
442
+ user: string;
443
+ password: string;
444
+ };
416
445
  };
417
446
  type FindWhereQuery = {
418
447
  field: string;
@@ -455,10 +484,12 @@ type FindJobsOptions = {
455
484
  type WorkerOptions = {
456
485
  /** Log level: debug, info, warn, error */
457
486
  logLevel?: LogLevel;
458
- /** Maximum number of attempts, default 5 (HMSH_DURABLE_MAX_ATTEMPTS) */
487
+ /** Maximum number of attempts, default 50 (HMSH_DURABLE_MAX_ATTEMPTS) */
459
488
  maximumAttempts?: number;
460
489
  /** Backoff coefficient for retry logic, default 10 (HMSH_DURABLE_EXP_BACKOFF) */
461
490
  backoffCoefficient?: number;
491
+ /** Initial interval before the first retry, default '1s' (HMSH_DURABLE_INITIAL_INTERVAL) */
492
+ initialInterval?: string;
462
493
  /** Maximum interval between retries, default 120s (HMSH_DURABLE_MAX_INTERVAL) */
463
494
  maximumInterval?: string;
464
495
  };
@@ -476,7 +507,7 @@ type ProxyType<ACT> = {
476
507
  type ActivityConfig = {
477
508
  /** place holder setting; unused at this time (re: activity workflow expire configuration) */
478
509
  expire?: number;
479
- /** Start to close timeout for the activity; not yet implemented */
510
+ /** Maximum time an activity can run after starting execution. If exceeded, the activity fails with a timeout error. Accepts duration strings (e.g., '30s', '5m', '1h'). */
480
511
  startToCloseTimeout?: string;
481
512
  /** Configuration for specific activities, type not yet specified */
482
513
  activities?: any;
@@ -499,7 +530,7 @@ type ActivityConfig = {
499
530
  * // Default: uses workflow's task queue (backward compatible)
500
531
  * const activities = Durable.workflow.proxyActivities<typeof activities>({
501
532
  * activities,
502
- * retryPolicy: { maximumAttempts: 3 }
533
+ * retry: { maximumAttempts: 3 }
503
534
  * });
504
535
  * // If workflow taskQueue is "orders", uses "orders-activity"
505
536
  *
@@ -507,7 +538,7 @@ type ActivityConfig = {
507
538
  * const { auditLog } = Durable.workflow.proxyActivities<typeof activities>({
508
539
  * activities: { auditLog },
509
540
  * taskQueue: 'shared-activities', // Uses "shared-activities-activity"
510
- * retryPolicy: { maximumAttempts: 3 }
541
+ * retry: { maximumAttempts: 3 }
511
542
  * });
512
543
  * ```
513
544
  */
@@ -515,14 +546,16 @@ type ActivityConfig = {
515
546
  /** Optional metadata to pass alongside activity arguments. This metadata
516
547
  * is transported as a dedicated schema field (not inside args) and made
517
548
  * available to the activity function via `Durable.activity.getContext()`. */
518
- argumentMetadata?: Record<string, any>;
549
+ headers?: Record<string, any>;
519
550
  /** Retry policy configuration for activities */
520
- retryPolicy?: {
521
- /** Maximum number of retry attempts, default is 5 (HMSH_DURABLE_MAX_ATTEMPTS) */
551
+ retry?: {
552
+ /** Maximum number of retry attempts, default is 50 (HMSH_DURABLE_MAX_ATTEMPTS) */
522
553
  maximumAttempts?: number;
523
- /** Factor by which the retry timeout increases, default is 10 (HMSH_DURABLE_MAX_INTERVAL) */
554
+ /** Factor by which the retry timeout increases, default is 10 (HMSH_DURABLE_EXP_BACKOFF) */
524
555
  backoffCoefficient?: number;
525
- /** Maximum interval between retries, default is '120s' (HMSH_DURABLE_EXP_BACKOFF) */
556
+ /** Initial interval before the first retry. Formula: initialInterval * backoffCoefficient^retryCount, clamped by maximumInterval. Default is '1s' */
557
+ initialInterval?: string;
558
+ /** Maximum interval between retries, default is '120s' (HMSH_DURABLE_MAX_INTERVAL) */
526
559
  maximumInterval?: string;
527
560
  /** Whether to throw an error on failure, default is true */
528
561
  throwOnError?: boolean;
@@ -569,7 +602,7 @@ interface ClientWorkflow {
569
602
  * @example
570
603
  * ```typescript
571
604
  * // Simple logging interceptor
572
- * const loggingInterceptor: WorkflowInterceptor = {
605
+ * const loggingInterceptor: WorkflowInboundCallsInterceptor = {
573
606
  * async execute(ctx, next) {
574
607
  * console.log('Before workflow');
575
608
  * try {
@@ -587,7 +620,7 @@ interface ClientWorkflow {
587
620
  * Durable.registerInterceptor(loggingInterceptor);
588
621
  * ```
589
622
  */
590
- export interface WorkflowInterceptor {
623
+ export interface WorkflowInboundCallsInterceptor {
591
624
  /**
592
625
  * Called before workflow execution to wrap the workflow in custom logic
593
626
  *
@@ -628,27 +661,32 @@ export interface WorkflowInterceptor {
628
661
  */
629
662
  export interface InterceptorRegistry {
630
663
  /**
631
- * Array of registered workflow interceptors that will wrap workflow execution
664
+ * Array of registered inbound interceptors that will wrap workflow execution
632
665
  * in the order they were registered (first registered = outermost wrapper).
633
666
  */
634
- interceptors: WorkflowInterceptor[];
667
+ inbound: WorkflowInboundCallsInterceptor[];
635
668
  /**
636
- * Array of registered activity interceptors that will wrap individual
669
+ * Array of registered outbound interceptors that will wrap individual
637
670
  * proxied activity calls in the order they were registered
638
671
  * (first registered = outermost wrapper).
639
672
  */
640
- activityInterceptors: ActivityInterceptor[];
673
+ outbound: WorkflowOutboundCallsInterceptor[];
674
+ /**
675
+ * Array of registered activity inbound interceptors that wrap the actual
676
+ * activity function execution on the activity worker side.
677
+ */
678
+ activityInbound: ActivityInboundCallsInterceptor[];
641
679
  }
642
680
  /**
643
681
  * Context provided to an activity interceptor, containing metadata
644
682
  * about the proxied activity being invoked.
645
683
  */
646
- export interface ActivityInterceptorContext {
684
+ export interface WorkflowOutboundCallsInterceptorContext {
647
685
  /** The name of the activity function being called */
648
686
  activityName: string;
649
687
  /** The arguments passed to the activity call */
650
688
  args: any[];
651
- /** The activity configuration (retryPolicy, taskQueue, etc.) */
689
+ /** The activity configuration (retry, taskQueue, etc.) */
652
690
  options?: ActivityConfig;
653
691
  }
654
692
  /**
@@ -675,13 +713,13 @@ export interface ActivityInterceptorContext {
675
713
  *
676
714
  * @example
677
715
  * ```typescript
678
- * const auditInterceptor: ActivityInterceptor = {
716
+ * const auditInterceptor: WorkflowOutboundCallsInterceptor = {
679
717
  * async execute(activityCtx, workflowCtx, next) {
680
718
  * const { auditLog } = Durable.workflow.proxyActivities<{
681
719
  * auditLog: (id: string, action: string) => Promise<void>;
682
720
  * }>({
683
721
  * taskQueue: 'shared-audit',
684
- * retryPolicy: { maximumAttempts: 3 },
722
+ * retry: { maximumAttempts: 3 },
685
723
  * });
686
724
  *
687
725
  * await auditLog(workflowCtx.get('workflowId'), `before:${activityCtx.activityName}`);
@@ -691,20 +729,58 @@ export interface ActivityInterceptorContext {
691
729
  * },
692
730
  * };
693
731
  *
694
- * Durable.registerActivityInterceptor(auditInterceptor);
732
+ * Durable.registerWorkflowOutboundCallsInterceptor(auditInterceptor);
695
733
  * ```
696
734
  */
697
- export interface ActivityInterceptor {
735
+ export interface WorkflowOutboundCallsInterceptor {
698
736
  /**
699
737
  * Called around each proxied activity invocation. Code before `next()`
700
738
  * runs in the before phase; code after `next()` runs in the after phase
701
739
  * once the activity result is available on replay.
702
740
  *
703
741
  * @param activityCtx - Metadata about the activity being called (args may be modified)
704
- * @param workflowCtx - The workflow context map (same as WorkflowInterceptor receives)
742
+ * @param workflowCtx - The workflow context map (same as WorkflowInboundCallsInterceptor receives)
705
743
  * @param next - Call to proceed to the next interceptor or the core activity function
706
744
  * @returns The activity result (from replay or after interruption/re-execution)
707
745
  */
708
- execute(activityCtx: ActivityInterceptorContext, workflowCtx: Map<string, any>, next: () => Promise<any>): Promise<any>;
746
+ execute(activityCtx: WorkflowOutboundCallsInterceptorContext, workflowCtx: Map<string, any>, next: () => Promise<any>): Promise<any>;
747
+ }
748
+ /**
749
+ * Interceptor for activity function execution on the activity worker side.
750
+ * Runs inside the activity's `activityAsyncLocalStorage` context, wrapping
751
+ * the actual activity function invocation — not the proxy call in the workflow.
752
+ *
753
+ * Unlike workflow-side interceptors, this runs where the activity actually executes.
754
+ * Use it for cross-cutting concerns like logging, metrics, auth validation,
755
+ * or error enrichment at the point where the activity actually executes.
756
+ *
757
+ * @example
758
+ * ```typescript
759
+ * Durable.registerActivityInboundInterceptor({
760
+ * async execute(activityName, args, next) {
761
+ * console.log(`Activity ${activityName} starting with`, args);
762
+ * const start = Date.now();
763
+ * try {
764
+ * const result = await next();
765
+ * console.log(`Activity ${activityName} completed in ${Date.now() - start}ms`);
766
+ * return result;
767
+ * } catch (err) {
768
+ * console.error(`Activity ${activityName} failed`, err);
769
+ * throw err;
770
+ * }
771
+ * }
772
+ * });
773
+ * ```
774
+ */
775
+ export interface ActivityInboundCallsInterceptor {
776
+ /**
777
+ * Called around the actual activity function execution on the worker.
778
+ *
779
+ * @param activityName - The name of the activity being executed
780
+ * @param args - The arguments passed to the activity
781
+ * @param next - Call to execute the next interceptor or the activity itself
782
+ * @returns The activity function's return value
783
+ */
784
+ execute(activityName: string, args: any[], next: () => Promise<any>): Promise<any>;
709
785
  }
710
786
  export { ActivityConfig, DurableActivityContext, ActivityWorkflowDataType, ChildResponseType, ClientConfig, ClientWorkflow, ContextType, Connection, FunctionSignature, ProxyResponseType, ProxyType, Registry, SignalOptions, FindJobsOptions, FindOptions, FindWhereOptions, FindWhereQuery, HookOptions, SearchResults, WorkerConfig, WorkflowConfig, WorkerOptions, WorkflowSearchOptions, WorkflowDataType, WorkflowOptions, WorkflowContext, };
@@ -2,6 +2,7 @@ export type DurableChildErrorType = {
2
2
  arguments: string[];
3
3
  await?: boolean;
4
4
  backoffCoefficient?: number;
5
+ initialInterval?: number;
5
6
  index: number;
6
7
  expire?: number;
7
8
  persistent?: boolean;
@@ -29,11 +30,13 @@ export type DurableWaitForAllErrorType = {
29
30
  };
30
31
  export type DurableProxyErrorType = {
31
32
  arguments: string[];
32
- argumentMetadata?: Record<string, any>;
33
+ headers?: Record<string, any>;
33
34
  activityName: string;
34
35
  backoffCoefficient?: number;
36
+ initialInterval?: number;
35
37
  index: number;
36
38
  expire?: number;
39
+ startToCloseTimeout?: number;
37
40
  maximumAttempts?: number;
38
41
  maximumInterval?: number;
39
42
  originJobId: string | null;
@@ -54,3 +57,9 @@ export type DurableSleepErrorType = {
54
57
  workflowDimension: string;
55
58
  workflowId: string;
56
59
  };
60
+ export type DurableContinueAsNewErrorType = {
61
+ arguments: any[];
62
+ index: number;
63
+ workflowDimension: string;
64
+ workflowId: string;
65
+ };
@@ -122,7 +122,7 @@ type HotMeshEngine = {
122
122
  * @example
123
123
  * ```typescript
124
124
  * {
125
- * retryPolicy: {
125
+ * retry: {
126
126
  * maximumAttempts: 5,
127
127
  * backoffCoefficient: 2,
128
128
  * maximumInterval: '300s'
@@ -130,8 +130,25 @@ type HotMeshEngine = {
130
130
  * }
131
131
  * ```
132
132
  */
133
- retryPolicy?: import('./stream').RetryPolicy;
133
+ retry?: import('./stream').RetryPolicy;
134
134
  };
135
+ /**
136
+ * Configuration for a HotMesh worker that consumes messages from a
137
+ * Postgres stream topic. Workers can run on the same process as the
138
+ * engine or on entirely separate servers — the only coupling is the
139
+ * shared Postgres database.
140
+ *
141
+ * ## Connection Modes
142
+ *
143
+ * **Standard**: Worker uses the same Postgres credentials as the engine.
144
+ * Set `connection` with admin credentials. Suitable for trusted, co-located workers.
145
+ *
146
+ * **Secured**: Worker connects as a restricted Postgres role with
147
+ * `workerCredentials`. The role can only dequeue/ack/respond on its
148
+ * allowed stream topics via SECURITY DEFINER stored procedures — zero
149
+ * direct table access. Use for untrusted workloads: K8s containers,
150
+ * LLM agents, third-party integrations.
151
+ */
135
152
  type HotMeshWorker = {
136
153
  /**
137
154
  * the topic/task queue that the worker subscribes to (stream_name)
@@ -212,7 +229,7 @@ type HotMeshWorker = {
212
229
  * @example
213
230
  * ```typescript
214
231
  * {
215
- * retryPolicy: {
232
+ * retry: {
216
233
  * maximumAttempts: 5,
217
234
  * backoffCoefficient: 2,
218
235
  * maximumInterval: '300s'
@@ -220,7 +237,53 @@ type HotMeshWorker = {
220
237
  * }
221
238
  * ```
222
239
  */
223
- retryPolicy?: import('./stream').RetryPolicy;
240
+ retry?: import('./stream').RetryPolicy;
241
+ /**
242
+ * Scoped Postgres credentials for database-level worker isolation.
243
+ *
244
+ * When provided, the `user` and `password` in the worker's connection
245
+ * options are overridden with these values, and all stream operations
246
+ * route through SECURITY DEFINER stored procedures that validate
247
+ * `app.allowed_streams` before executing. The worker role has **zero
248
+ * direct table access**.
249
+ *
250
+ * Use this for workers running in untrusted environments: pluggable
251
+ * K8s containers, LLM-driven agents (e.g., MCP tool servers),
252
+ * third-party integrations, or any workload that should be isolated
253
+ * from the engine's database surface.
254
+ *
255
+ * Provision credentials via `HotMesh.provisionWorkerRole()` or by
256
+ * creating a Postgres role with `EXECUTE` on the schema's worker
257
+ * stored procedures and `ALTER ROLE ... SET app.allowed_streams`.
258
+ *
259
+ * **Limitations:** Workflows running under scoped credentials cannot
260
+ * use `Durable.workflow.entity()`, `Durable.workflow.search()`, or
261
+ * `Durable.workflow.enrich()` — these write directly to the `jobs`
262
+ * and `jobs_attributes` tables, which the scoped role has no access
263
+ * to. All other workflow primitives (`proxyActivities`, `sleep`,
264
+ * `condition`, `signal`, `emit`, `executeChild`, etc.) work normally.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * // Admin provisions scoped credentials (one-time)
269
+ * const cred = await HotMesh.provisionWorkerRole({
270
+ * connection: { class: Postgres, options: adminOptions },
271
+ * streamNames: ['order.process'],
272
+ * });
273
+ *
274
+ * // Worker connects with restricted role
275
+ * workers: [{
276
+ * topic: 'order.process',
277
+ * connection: { class: Postgres, options: { host: 'pg.prod', database: 'db' } },
278
+ * workerCredentials: { user: cred.roleName, password: cred.password },
279
+ * callback: myCallback,
280
+ * }]
281
+ * ```
282
+ */
283
+ workerCredentials?: {
284
+ user: string;
285
+ password: string;
286
+ };
224
287
  };
225
288
  type HotMeshConfig = {
226
289
  appId: string;
@@ -1,9 +1,10 @@
1
1
  export { ActivityType, ActivityDataType, ActivityContext, ActivityData, ActivityDuplex, ActivityLeg, ActivityMetadata, Consumes, AwaitActivity, BaseActivity, CycleActivity, HookActivity, WorkerActivity, InterruptActivity, SignalActivity, TriggerActivity, TriggerActivityStats, } from './activity';
2
2
  export { App, AppVID, AppTransitions, AppSubscriptions } from './app';
3
3
  export { AsyncSignal } from './async';
4
+ export { PayloadCodec } from './codec';
4
5
  export { CacheMode } from './cache';
5
6
  export { CollationFaultType, CollationStage } from './collator';
6
- export { ActivityConfig, DurableActivityContext, ActivityInterceptor, ActivityInterceptorContext, ActivityWorkflowDataType, ChildResponseType, ClientConfig, ClientWorkflow, ContextType, Connection, ProxyResponseType, ProxyType, Registry, SignalOptions, FindJobsOptions, FindOptions, FindWhereOptions, FindWhereQuery, HookOptions, SearchResults, WorkflowConfig, WorkerConfig, WorkerOptions, WorkflowContext, WorkflowSearchOptions, WorkflowSearchSchema, WorkflowDataType, WorkflowOptions, WorkflowInterceptor, InterceptorRegistry, } from './durable';
7
+ export { ActivityConfig, DurableActivityContext, WorkflowOutboundCallsInterceptor, WorkflowOutboundCallsInterceptorContext, ActivityInboundCallsInterceptor, ActivityWorkflowDataType, ChildResponseType, ClientConfig, ClientWorkflow, ContextType, Connection, ProxyResponseType, ProxyType, Registry, SignalOptions, FindJobsOptions, FindOptions, FindWhereOptions, FindWhereQuery, HookOptions, SearchResults, WorkflowConfig, WorkerConfig, WorkerOptions, WorkflowContext, WorkflowSearchOptions, WorkflowSearchSchema, WorkflowDataType, WorkflowOptions, WorkflowInboundCallsInterceptor, InterceptorRegistry, } from './durable';
7
8
  export { PruneOptions, PruneResult, } from './dba';
8
9
  export { DurableChildErrorType, DurableProxyErrorType, DurableSleepErrorType, DurableWaitForAllErrorType, DurableWaitForErrorType, } from './error';
9
10
  export { ActivityAction, ActivityDetail, ActivityInputMap, ActivityTaskCompletedAttributes, ActivityTaskFailedAttributes, ActivityTaskScheduledAttributes, ChildWorkflowExecutionCompletedAttributes, ChildWorkflowExecutionFailedAttributes, ChildWorkflowExecutionStartedAttributes, DependencyExport, DurableJobExport, ExecutionExportOptions, ExportCycles, ExportFields, ExportItem, ExportMode, ExportOptions, ExportTransitions, JobAction, JobActionExport, JobAttributesRow, JobExport, JobRow, JobTimeline, StreamHistoryEntry, TimelineType, TimerFiredAttributes, TimerStartedAttributes, TransitionType, WorkflowEventAttributes, WorkflowEventCategory, WorkflowEventType, WorkflowExecution, WorkflowExecutionCompletedAttributes, WorkflowExecutionEvent, WorkflowExecutionFailedAttributes, WorkflowExecutionSignaledAttributes, WorkflowExecutionStartedAttributes, WorkflowExecutionStatus, WorkflowExecutionSummary, } from './exporter';
@@ -69,7 +69,7 @@ export type ProviderConfig = {
69
69
  * @example
70
70
  * ```typescript
71
71
  * {
72
- * retryPolicy: {
72
+ * retry: {
73
73
  * maximumAttempts: 5,
74
74
  * backoffCoefficient: 2,
75
75
  * maximumInterval: '300s'
@@ -77,7 +77,7 @@ export type ProviderConfig = {
77
77
  * }
78
78
  * ```
79
79
  */
80
- retryPolicy?: import('./stream').RetryPolicy;
80
+ retry?: import('./stream').RetryPolicy;
81
81
  };
82
82
  export type ProvidersConfig = {
83
83
  sub: ProviderConfig;
@@ -16,7 +16,7 @@ export interface NetworkStat {
16
16
  tx_sec: number;
17
17
  ms: number;
18
18
  }
19
- /** reveals: memory, cpu, network */
19
+ /** Host-level resource snapshot collected at pong time. */
20
20
  export interface SystemHealth {
21
21
  TotalMemoryGB: string;
22
22
  FreeMemoryGB: string;
@@ -36,21 +36,55 @@ export type ThrottleOptions = {
36
36
  /** namespace */
37
37
  namespace?: string;
38
38
  };
39
+ /**
40
+ * Snapshot of a single engine or worker instance, returned by
41
+ * `HotMesh.rollCall()`. Each connected instance responds to the
42
+ * quorum PING with its current profile.
43
+ *
44
+ * **Engines** populate `stream` (the engine stream key).
45
+ * **Workers** populate `worker_topic` (the task queue topic) and `stream`.
46
+ *
47
+ * Use `counts` and `error_count` for throughput and health monitoring.
48
+ */
39
49
  export interface QuorumProfile {
50
+ /** Namespace the instance belongs to. */
40
51
  namespace: string;
52
+ /** Application ID (matches `HotMeshConfig.appId`). */
41
53
  app_id: string;
54
+ /** Unique instance GUID (engine or worker). */
42
55
  engine_id: string;
56
+ /** Entity name (if applicable). */
43
57
  entity?: string;
58
+ /** Worker task queue topic. Present only for worker instances. */
44
59
  worker_topic?: string;
60
+ /** Stream key this instance consumes from. */
45
61
  stream?: string;
62
+ /** Number of pending (unprocessed) messages in the stream. */
46
63
  stream_depth?: number;
64
+ /**
65
+ * Cumulative messages processed, keyed by status code.
66
+ * Common codes: `'200'` (success), `'590'` (child workflow),
67
+ * `'591'` (activity dispatch), `'500'` (error).
68
+ */
47
69
  counts?: Record<string, number>;
70
+ /**
71
+ * Consecutive stream consumption errors. `0` = healthy.
72
+ * Non-zero means the consumer is in exponential backoff recovery.
73
+ */
74
+ error_count?: number;
75
+ /** ISO timestamp of when this instance was initialized. */
48
76
  inited?: string;
77
+ /** ISO timestamp of when this profile was generated. */
49
78
  timestamp?: string;
79
+ /** Current throttle delay in ms (`0` = no throttle). */
50
80
  throttle?: number;
81
+ /** Interval (ms) before reclaiming unacknowledged messages. */
51
82
  reclaimDelay?: number;
83
+ /** Max messages to reclaim per cycle. */
52
84
  reclaimCount?: number;
85
+ /** Host-level memory, CPU, and network stats. */
53
86
  system?: SystemHealth;
87
+ /** Stringified worker callback function (only if `signature: true` in rollcall). */
54
88
  signature?: string;
55
89
  }
56
90
  interface QuorumMessageBase {
@@ -5,7 +5,7 @@ import { ProviderTransaction } from './provider';
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * const retryPolicy: RetryPolicy = {
8
+ * const retry: RetryPolicy = {
9
9
  * maximumAttempts: 5,
10
10
  * backoffCoefficient: 2,
11
11
  * maximumInterval: '300s',
@@ -172,7 +172,7 @@ export type RouterConfig = {
172
172
  /** if true, will not process stream messages; default true */
173
173
  readonly?: boolean;
174
174
  /** Retry policy for worker messages. Applied when worker callback throws an error */
175
- retryPolicy?: RetryPolicy;
175
+ retry?: RetryPolicy;
176
176
  };
177
177
  export type StreamProviderType = 'postgres' | 'nats' | 'sqs';
178
178
  export interface StreamConfig {
@@ -195,7 +195,13 @@ export interface StreamConfig {
195
195
  * }
196
196
  * ```
197
197
  */
198
- retryPolicy?: RetryPolicy;
198
+ retry?: RetryPolicy;
199
+ /**
200
+ * When true, worker stream operations use SECURITY DEFINER stored
201
+ * procedures instead of raw SQL. Enabled automatically when the
202
+ * worker connects with scoped `workerCredentials`.
203
+ */
204
+ securedWorker?: boolean;
199
205
  postgres?: {
200
206
  pollInterval?: number;
201
207
  vacuumInterval?: number;
@@ -227,7 +233,7 @@ export interface StreamMessage {
227
233
  * Retry policy configuration for this message.
228
234
  * Populated from database columns when available.
229
235
  */
230
- retryPolicy?: RetryPolicy;
236
+ retry?: RetryPolicy;
231
237
  }
232
238
  export interface StreamMessageMetadata {
233
239
  timestamp?: number;
@@ -265,7 +271,7 @@ export interface PublishMessageConfig {
265
271
  * @example
266
272
  * ```typescript
267
273
  * await streamService.publishMessages('my-topic', [msg], {
268
- * retryPolicy: {
274
+ * retry: {
269
275
  * maximumAttempts: 10,
270
276
  * backoffCoefficient: 2,
271
277
  * maximumInterval: '600s',
@@ -273,7 +279,7 @@ export interface PublishMessageConfig {
273
279
  * });
274
280
  * ```
275
281
  */
276
- retryPolicy?: RetryPolicy;
282
+ retry?: RetryPolicy;
277
283
  }
278
284
  /**
279
285
  * Notification consumer configuration for PostgreSQL stream provider.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Durable Workflow",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -35,6 +35,7 @@
35
35
  "test:durable:interceptor": "HMSH_LOGLEVEL=info vitest run tests/durable/interceptor/postgres.test.ts",
36
36
  "test:durable:metadata": "HMSH_LOGLEVEL=info vitest run tests/durable/interceptor/postgres.test.ts -t 'argumentMetadata'",
37
37
  "test:durable:entity": "HMSH_LOGLEVEL=debug vitest run tests/durable/entity/postgres.test.ts",
38
+ "test:durable:config": "HMSH_LOGLEVEL=debug vitest run tests/durable/config-parity/postgres.test.ts",
38
39
  "test:durable:agent": "HMSH_LOGLEVEL=debug vitest run tests/durable/agent/postgres.test.ts",
39
40
  "test:durable:hello": "HMSH_TELEMETRY=debug HMSH_LOGLEVEL=info vitest run tests/durable/helloworld/postgres.test.ts",
40
41
  "test:durable:hook": "vitest run tests/durable/hook/postgres.test.ts",
@@ -49,11 +50,15 @@
49
50
  "test:durable:unknown": "vitest run tests/durable/unknown/postgres.test.ts",
50
51
  "test:durable:exporter": "HMSH_LOGLEVEL=info vitest run tests/durable/exporter",
51
52
  "test:durable:exporter:debug": "EXPORT_DEBUG=1 HMSH_LOGLEVEL=error vitest run tests/durable/basic/postgres.test.ts",
53
+ "test:durable:codec": "vitest run tests/durable/codec/postgres.test.ts",
54
+ "test:durable:credentials": "vitest run tests/durable/credentials/postgres.test.ts",
52
55
  "test:dba": "vitest run tests/dba",
53
56
  "test:cycle": "vitest run tests/functional/cycle",
54
57
  "test:functional": "vitest run tests/functional",
55
58
  "test:emit": "vitest run tests/functional/emit",
56
59
  "test:pending": "vitest run tests/functional/pending/index.test.ts",
60
+ "test:codec": "vitest run tests/functional/codec/postgres.test.ts",
61
+ "test:credentials": "vitest run tests/functional/credentials/postgres.test.ts",
57
62
  "test:hmsh": "vitest run tests/functional/postgres.test.ts",
58
63
  "test:hook": "vitest run tests/functional/hook/postgres.test.ts",
59
64
  "test:interrupt": "vitest run tests/functional/interrupt/postgres.test.ts",