@fluidgrids/workflows 2026.1028.2 → 2026.1030.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 (154) hide show
  1. package/README.md +181 -11
  2. package/dist/{activation-BBh1p82z.d.cts → activation-DqUfpHzk.d.cts} +1 -1
  3. package/dist/{activation-DnhG7SmF.d.ts → activation-xpx1oWuo.d.ts} +1 -1
  4. package/dist/{chunk-VRHHBPT6.js → chunk-2D3MYIIF.js} +1212 -128
  5. package/dist/chunk-3U2NU7YC.cjs +124 -0
  6. package/dist/{chunk-NEIUQASE.cjs → chunk-4QKB4ARC.cjs} +3 -3
  7. package/dist/{chunk-GBQ33SIZ.cjs → chunk-54FLQNUM.cjs} +12 -1
  8. package/dist/chunk-5HIVIV53.js +330 -0
  9. package/dist/chunk-5MFVJM76.js +1222 -0
  10. package/dist/{chunk-JD2VQIDZ.cjs → chunk-672KMMBK.cjs} +2 -2
  11. package/dist/{chunk-C5OLWZ42.js → chunk-6A2FGSUS.js} +22 -14
  12. package/dist/{chunk-XKJA7KX3.js → chunk-6OLN6BMB.js} +52 -3
  13. package/dist/{chunk-6FSHT5IL.js → chunk-7EZIANC7.js} +1 -1
  14. package/dist/{chunk-2J6TF7YI.cjs → chunk-A5SXCA62.cjs} +10 -3
  15. package/dist/{chunk-BO6OVILK.js → chunk-AC6ZEXVR.js} +10 -4
  16. package/dist/{chunk-ABFZWYHT.js → chunk-AE5Q6ZAJ.js} +315 -50
  17. package/dist/chunk-C4F5KJTI.js +293 -0
  18. package/dist/{chunk-IISBRUWJ.js → chunk-G5H32GIG.js} +1 -1
  19. package/dist/chunk-GEQDGUGB.cjs +2719 -0
  20. package/dist/{chunk-XHXIDVEC.js → chunk-HCM7ZC7Q.js} +1 -1
  21. package/dist/chunk-HMZUGSMU.cjs +1554 -0
  22. package/dist/{chunk-SAOBPYYJ.cjs → chunk-IQPXHQQQ.cjs} +8 -4
  23. package/dist/{chunk-P6TA5EZT.cjs → chunk-ISOIA7NV.cjs} +335 -58
  24. package/dist/chunk-JSC75O5C.cjs +167 -0
  25. package/dist/chunk-M272AHEX.js +25 -0
  26. package/dist/{chunk-BD7ZPG53.js → chunk-NWQ5WRLE.js} +10 -2
  27. package/dist/chunk-ODZ2IAR2.cjs +1247 -0
  28. package/dist/chunk-Q4MWQNJK.cjs +28 -0
  29. package/dist/{chunk-HWJZVOG7.js → chunk-SR7TR5KX.js} +6 -2
  30. package/dist/{chunk-FEW3JBYA.cjs → chunk-TCTE7DX5.cjs} +3 -3
  31. package/dist/{chunk-623FVQSN.cjs → chunk-TYF56RGB.cjs} +123 -0
  32. package/dist/chunk-VA4OFR72.cjs +324 -0
  33. package/dist/chunk-VU5S5A7V.js +150 -0
  34. package/dist/chunk-YEHR4NNE.js +1522 -0
  35. package/dist/{chunk-FMSW2HDF.cjs → chunk-ZCGKGDCL.cjs} +23 -15
  36. package/dist/codegen/index.d.cts +2 -2
  37. package/dist/codegen/index.d.ts +2 -2
  38. package/dist/collect-6NIEufHd.d.ts +103 -0
  39. package/dist/collect-CcTCKqx6.d.cts +103 -0
  40. package/dist/{file-BOoHZgoQ.d.cts → file-BxYpwjRQ.d.cts} +1007 -21
  41. package/dist/{file-yuPCFU5b.d.ts → file-CFdPQJI9.d.ts} +1007 -21
  42. package/dist/history/index.cjs +375 -86
  43. package/dist/history/index.d.cts +590 -12
  44. package/dist/history/index.d.ts +590 -12
  45. package/dist/history/index.js +50 -4
  46. package/dist/index.cjs +156 -50
  47. package/dist/index.d.cts +38 -58
  48. package/dist/index.d.ts +38 -58
  49. package/dist/index.js +6 -4
  50. package/dist/interceptors-CNcr2dlk.d.ts +159 -0
  51. package/dist/interceptors-CqkNZVfI.d.cts +159 -0
  52. package/dist/ir/index.cjs +362 -38
  53. package/dist/ir/index.d.cts +282 -7
  54. package/dist/ir/index.d.ts +282 -7
  55. package/dist/ir/index.js +329 -23
  56. package/dist/{lower-BzmUz0sq.d.cts → lower-BtRfIW2A.d.cts} +56 -8
  57. package/dist/{lower-_-iT4HYs.d.ts → lower-CpsMFOFX.d.ts} +56 -8
  58. package/dist/{manifest-C8N6HDYl.d.ts → manifest-D-I_twys.d.ts} +1 -1
  59. package/dist/{manifest-0OLw0i7k.d.cts → manifest-DahBQVM8.d.cts} +1 -1
  60. package/dist/node-evaluator-DGQDPSPI.cjs +24 -0
  61. package/dist/node-evaluator-LEEVD7H7.js +14 -0
  62. package/dist/payload-fields-BVRQn2yH.d.cts +122 -0
  63. package/dist/payload-fields-oOBWxDiG.d.ts +122 -0
  64. package/dist/quickjs/index.cjs +28 -27
  65. package/dist/quickjs/index.d.cts +6 -6
  66. package/dist/quickjs/index.d.ts +6 -6
  67. package/dist/quickjs/index.js +10 -9
  68. package/dist/roundtrip/index.cjs +259 -51
  69. package/dist/roundtrip/index.d.cts +100 -9
  70. package/dist/roundtrip/index.d.ts +100 -9
  71. package/dist/roundtrip/index.js +177 -11
  72. package/dist/runtime/index.cjs +21 -20
  73. package/dist/runtime/index.d.cts +184 -15
  74. package/dist/runtime/index.d.ts +184 -15
  75. package/dist/runtime/index.js +8 -7
  76. package/dist/testing/index.cjs +1122 -115
  77. package/dist/testing/index.d.cts +294 -13
  78. package/dist/testing/index.d.ts +294 -13
  79. package/dist/testing/index.js +1086 -84
  80. package/dist/{types-DV-HX_Gt.d.ts → types-Bv2i4cBX.d.cts} +244 -33
  81. package/dist/{types-CpBBjaGX.d.cts → types-DGx-b9eq.d.ts} +244 -33
  82. package/dist/{types-BGoPzgcl.d.ts → types-V7jEEUaL.d.cts} +20 -1
  83. package/dist/{types-BGoPzgcl.d.cts → types-V7jEEUaL.d.ts} +20 -1
  84. package/dist/{workflow-Bpr3vnA_.d.ts → workflow-B18OeF7g.d.ts} +2 -2
  85. package/dist/workflow-BGnv8SS6.d.ts +803 -0
  86. package/dist/{workflow-FXUkpIBc.d.cts → workflow-BJPFv3cp.d.cts} +2 -2
  87. package/dist/workflow-DS32Gtws.d.cts +803 -0
  88. package/fixtures/histories/activity-options-updated.history.json +159 -0
  89. package/fixtures/histories/activity-paused-unpaused.history.json +160 -0
  90. package/fixtures/histories/auto-upgrade-patched.history.json +276 -0
  91. package/fixtures/histories/benign-failure.history.json +146 -0
  92. package/fixtures/histories/cancel-activity-try-cancel.history.json +150 -0
  93. package/fixtures/histories/child-cancel-wait-requested.history.json +217 -0
  94. package/fixtures/histories/child-options-roundtrip.history.json +192 -0
  95. package/fixtures/histories/codec-opaque.history.json +229 -0
  96. package/fixtures/histories/continue-as-new-last-result.history.json +86 -0
  97. package/fixtures/histories/continue-as-new-options.history.json +99 -0
  98. package/fixtures/histories/continue-as-new-r1-long-task-queue.history.json +78 -0
  99. package/fixtures/histories/continue-as-new-r1-retry-options.history.json +83 -0
  100. package/fixtures/histories/dynamic-workflow.history.json +150 -0
  101. package/fixtures/histories/execution-timeout-chain.history.json +98 -0
  102. package/fixtures/histories/external-cancel-resolved.history.json +123 -0
  103. package/fixtures/histories/external-cancel-unknown-target.history.json +127 -0
  104. package/fixtures/histories/failure-error-types-fails-run.history.json +144 -0
  105. package/fixtures/histories/handler-drain-warn.history.json +222 -0
  106. package/fixtures/histories/heartbeat-details-on-retry.history.json +145 -0
  107. package/fixtures/histories/interceptor-headers.history.json +339 -0
  108. package/fixtures/histories/local-activity-abandoned-at-completion.history.json +73 -0
  109. package/fixtures/histories/local-activity-cancelled-in-scope.history.json +118 -0
  110. package/fixtures/histories/local-activity-completed.history.json +157 -0
  111. package/fixtures/histories/local-activity-failed.history.json +93 -0
  112. package/fixtures/histories/local-activity-retry-in-task.history.json +88 -0
  113. package/fixtures/histories/query-custom.history.json +213 -0
  114. package/fixtures/histories/query-default-handler.history.json +120 -0
  115. package/fixtures/histories/reset-forked-reapplied-signals.history.json +239 -0
  116. package/fixtures/histories/reset-reapplied-update-admitted.history.json +228 -0
  117. package/fixtures/histories/run-retry-last-failure.history.json +90 -0
  118. package/fixtures/histories/run-timeout.history.json +159 -0
  119. package/fixtures/histories/schedule-to-start-timeout.history.json +132 -0
  120. package/fixtures/histories/search-attributes-upserted.history.json +177 -0
  121. package/fixtures/histories/start-delay-signal-ends-delay.history.json +155 -0
  122. package/fixtures/histories/typeerror-task-retry-100.history.json +137 -0
  123. package/fixtures/histories/update-accepted-completed.history.json +45 -30
  124. package/fixtures/histories/update-default-handler.history.json +246 -0
  125. package/fixtures/histories/update-handler-awaits-activity.history.json +196 -0
  126. package/fixtures/histories/update-not-handled.history.json +138 -0
  127. package/fixtures/histories/update-rejected-no-event.history.json +190 -0
  128. package/fixtures/histories/update-with-start-admitted.history.json +150 -0
  129. package/fixtures/histories/user-activity-cancel.history.json +149 -0
  130. package/fixtures/histories/user-activity-retry.history.json +143 -0
  131. package/fixtures/histories/user-activity.history.json +149 -0
  132. package/package.json +1 -1
  133. package/schema/bridge-v2.schema.json +1062 -0
  134. package/schema/history-file.schema.json +538 -83
  135. package/schema/ir-v2.schema.json +290 -0
  136. package/schema/payload-fields.json +162 -0
  137. package/schema/run-event.schema.json +503 -82
  138. package/schema/workflow-command.schema.json +372 -69
  139. package/schema/workflow-task.schema.json +924 -171
  140. package/dist/assemble-BLqQ8lSu.d.cts +0 -39
  141. package/dist/assemble-DWgaXHd-.d.ts +0 -39
  142. package/dist/chunk-DHTLALBL.cjs +0 -80
  143. package/dist/chunk-DJYMDLV5.js +0 -227
  144. package/dist/chunk-I5LR3D2K.js +0 -869
  145. package/dist/chunk-M4BBAERY.cjs +0 -1635
  146. package/dist/chunk-N23SKIG4.js +0 -73
  147. package/dist/chunk-PZCVF76Q.cjs +0 -868
  148. package/dist/chunk-QQ6ULXHI.cjs +0 -885
  149. package/dist/chunk-UK3WM7YZ.cjs +0 -75
  150. package/dist/chunk-VOKMAAJP.js +0 -848
  151. package/dist/node-evaluator-4MSDKWOG.cjs +0 -22
  152. package/dist/node-evaluator-SX4LEYQC.js +0 -12
  153. package/dist/workflow-C2a05WUJ.d.ts +0 -444
  154. package/dist/workflow-J-yYixny.d.cts +0 -444
package/dist/ir/index.js CHANGED
@@ -1,8 +1,8 @@
1
- export { diffDefinitions } from '../chunk-6FSHT5IL.js';
1
+ export { diffDefinitions } from '../chunk-7EZIANC7.js';
2
2
  import { findManifest, operationsOf, fieldsSchema } from '../chunk-QAN5MZEM.js';
3
3
  export { fieldSchema, fieldsSchema, findManifest, isTriggerOperation, operationsOf } from '../chunk-QAN5MZEM.js';
4
- import { usesMergedParameters, CODE_WORKFLOW_NODE_TYPE, WAIT_FOR_SIGNAL_NODE_TYPE, INTERNAL_TRIGGER_TYPES, V2_NODE_TYPES, normalizeDefinition } from '../chunk-BD7ZPG53.js';
5
- export { CODE_WORKFLOW_NODE_TYPE, INTERNAL_TRIGGER_TYPES, WAIT_FOR_SIGNAL_NODE_TYPE, buildIdOf, hashedProjection, irHash, normalizeDefinition, sourceHash, usesMergedParameters } from '../chunk-BD7ZPG53.js';
4
+ import { usesMergedParameters, CODE_WORKFLOW_NODE_TYPE, WAIT_FOR_SIGNAL_NODE_TYPE, INTERNAL_TRIGGER_TYPES, SIGNAL_RUN_NODE_TYPE, SET_SEARCH_ATTRIBUTES_NODE_TYPE, V2_NODE_TYPES, normalizeDefinition } from '../chunk-NWQ5WRLE.js';
5
+ export { CODE_WORKFLOW_NODE_TYPE, INTERNAL_TRIGGER_TYPES, PHASE_C_NODE_TYPES, SET_SEARCH_ATTRIBUTES_NODE_TYPE, SIGNAL_RUN_NODE_TYPE, WAIT_FOR_SIGNAL_NODE_TYPE, buildIdOf, hashedProjection, irHash, normalizeDefinition, sourceHash, usesMergedParameters } from '../chunk-NWQ5WRLE.js';
6
6
  export { LAYOUT_COLUMN_WIDTH, LAYOUT_ROW_HEIGHT, autoLayout } from '../chunk-5LUIDMF4.js';
7
7
  export { CanonicalJsonError, canonicalJson, sha256Hex, sha256Tagged, stableStringify } from '../chunk-E2VK7J2C.js';
8
8
  import { hasLegacyTemplate } from '../chunk-7AAZGVKD.js';
@@ -13,8 +13,41 @@ export { durationMs } from '../chunk-LNUQE6D6.js';
13
13
  import { Ajv2020 } from 'ajv/dist/2020.js';
14
14
  import { CronExpressionParser } from 'cron-parser';
15
15
 
16
+ // src/ir/schedule-fields.ts
17
+ var SCHEDULE_OVERLAP_POLICIES = [
18
+ "SKIP",
19
+ "BUFFER_ONE",
20
+ "BUFFER_ALL",
21
+ "CANCEL_OTHER",
22
+ "TERMINATE_OTHER",
23
+ "ALLOW_ALL"
24
+ ];
25
+ var DEFAULT_NEW_SCHEDULE_OVERLAP_POLICY = "SKIP";
26
+ var DEFAULT_SCHEDULE_CATCHUP_WINDOW_SECONDS = 3600;
27
+ var SCHEDULE_POLICY_FIELDS = [
28
+ "overlapPolicy",
29
+ "catchupWindow",
30
+ "pauseOnFailure",
31
+ "limitedActions",
32
+ "scheduleContext",
33
+ "scheduleSearchAttributes"
34
+ ];
35
+ var SCHEDULE_SPEC_FIELDS = [
36
+ "excludeCalendars",
37
+ "startAt",
38
+ "endAt",
39
+ "timezone",
40
+ "jitter"
41
+ ];
42
+
16
43
  // src/ir/schema.ts
17
44
  var JSON_SCHEMA_OBJECT = { type: "object" };
45
+ var DURATION = {
46
+ oneOf: [
47
+ { type: "number", minimum: 0 },
48
+ { type: "string", minLength: 1 }
49
+ ]
50
+ };
18
51
  var IR_V2_SCHEMA_ID = "https://docs.fluidgrids.ai/schemas/workflow-ir-v2.schema.json";
19
52
  var IR_V2_SCHEMA = {
20
53
  $schema: "https://json-schema.org/draft/2020-12/schema",
@@ -182,6 +215,118 @@ var IR_V2_SCHEMA = {
182
215
  }
183
216
  }
184
217
  }
218
+ },
219
+ {
220
+ if: { properties: { type: { const: "internal:signal-run" } }, required: ["type"] },
221
+ then: {
222
+ description: "Phase C (fluidgrids.run-control): signal another run of the workspace (05 \xA74). A retried node delivers once (dedupe key signal-node:<nodeStateId>:<attempt>).",
223
+ required: ["args"],
224
+ properties: {
225
+ args: {
226
+ required: ["state"],
227
+ properties: {
228
+ state: {
229
+ type: "object",
230
+ required: ["signalName", "target"],
231
+ properties: {
232
+ signalName: { type: "string", minLength: 1 },
233
+ target: {
234
+ description: "The run to signal: { runId }, { workflowKey, workflowId, firstRunId? } (the open run of that workflow id) or { parent: true }. Values may be expressions.",
235
+ oneOf: [
236
+ {
237
+ type: "object",
238
+ required: ["runId"],
239
+ properties: { runId: { type: "string", minLength: 1 } },
240
+ additionalProperties: false
241
+ },
242
+ {
243
+ type: "object",
244
+ required: ["workflowKey", "workflowId"],
245
+ properties: {
246
+ workflowKey: { type: "string", minLength: 1 },
247
+ workflowId: { type: "string", minLength: 1 },
248
+ firstRunId: { type: "string", minLength: 1 }
249
+ },
250
+ additionalProperties: false
251
+ },
252
+ {
253
+ type: "object",
254
+ required: ["parent"],
255
+ properties: { parent: { const: true } },
256
+ additionalProperties: false
257
+ }
258
+ ]
259
+ },
260
+ payload: {},
261
+ failOnUndelivered: {
262
+ type: "boolean",
263
+ description: "Default true: an undelivered signal fails the node."
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ }
271
+ },
272
+ {
273
+ if: {
274
+ properties: { type: { const: "internal:set-search-attributes" } },
275
+ required: ["type"]
276
+ },
277
+ then: {
278
+ description: "Phase C (fluidgrids.search-attributes): upsert the run search attributes (11 \xA72.8); a null value removes one. Values may be expressions; the service validates them against the workspace definitions.",
279
+ required: ["args"],
280
+ properties: {
281
+ args: {
282
+ required: ["state"],
283
+ properties: {
284
+ state: {
285
+ type: "object",
286
+ required: ["attributes"],
287
+ properties: {
288
+ attributes: { type: "object", minProperties: 1 }
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }
295
+ },
296
+ {
297
+ if: { properties: { type: { const: "internal:schedule" } }, required: ["type"] },
298
+ then: {
299
+ properties: {
300
+ args: {
301
+ properties: {
302
+ state: {
303
+ description: "Phase C schedule policies (11 \xA72.16, \xA72.33; fluidgrids.schedule-policies). Every field is optional; a trigger without overlapPolicy keeps the ALLOW_ALL behaviour of earlier versions.",
304
+ properties: {
305
+ overlapPolicy: { enum: [...SCHEDULE_OVERLAP_POLICIES] },
306
+ catchupWindow: DURATION,
307
+ pauseOnFailure: { type: "boolean" },
308
+ limitedActions: { type: "integer", minimum: 1 },
309
+ scheduleContext: { type: "object" },
310
+ scheduleSearchAttributes: { type: "object" },
311
+ spec: {
312
+ description: "One of cron, calendar or interval, plus excludeCalendars (calendar entries whose matches are skipped), startAt, endAt (ISO 8601), timezone and jitter.",
313
+ properties: {
314
+ cron: { type: "string" },
315
+ calendar: { type: "array", items: { type: "object" } },
316
+ interval: { type: "array", items: { type: "object" } },
317
+ excludeCalendars: { type: "array", items: { type: "object" } },
318
+ startAt: { type: "string", minLength: 1 },
319
+ endAt: { type: "string", minLength: 1 },
320
+ timezone: { type: "string" },
321
+ jitter: DURATION
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+ }
185
330
  }
186
331
  ]
187
332
  },
@@ -213,7 +358,18 @@ var IR_V2_SCHEMA = {
213
358
  type: ["number", "string"],
214
359
  description: "Seconds or a duration string."
215
360
  },
216
- versioningBehavior: { enum: ["PINNED", "AUTO_UPGRADE"] }
361
+ versioningBehavior: { enum: ["PINNED", "AUTO_UPGRADE"] },
362
+ retry: {
363
+ type: "object",
364
+ description: "Run-level retry of DURABLE_FN runs (11 \xA72.17); delays are seconds or duration strings. Graph runs keep their own meaning of retry.",
365
+ properties: {
366
+ maxAttempts: { type: "integer", minimum: 1 },
367
+ initialDelay: { type: ["number", "string"] },
368
+ backoffMultiplier: { type: "number", minimum: 1 },
369
+ maxDelay: { type: ["number", "string"] },
370
+ nonRetryableErrorTypes: { type: "array", items: { type: "string" } }
371
+ }
372
+ }
217
373
  }
218
374
  },
219
375
  interface: {
@@ -286,7 +442,11 @@ var IR_V2_SCHEMA = {
286
442
  type: "object",
287
443
  properties: {
288
444
  interface: { $ref: "#/$defs/interface" },
289
- taskQueue: { type: "string" }
445
+ taskQueue: { type: "string" },
446
+ config: {
447
+ $ref: "#/$defs/config",
448
+ description: "R2: the run-level settings of this function's workflow() declaration (retry, timeout, executionTimeout, workflowTaskTimeout, versioningBehavior). The service resolves run options per workflowFn from this table, never from the definition-level config, so a same-bundle child started on its parent's definition gets its own settings. Absent: the function declares none."
449
+ }
290
450
  }
291
451
  }
292
452
  },
@@ -303,7 +463,13 @@ var IR_V2_SCHEMA = {
303
463
  }
304
464
  }
305
465
  },
306
- determinism: { enum: ["isolate", "worker"] }
466
+ determinism: { enum: ["isolate", "worker"] },
467
+ features: {
468
+ type: "array",
469
+ items: { type: "string", minLength: 1 },
470
+ uniqueItems: true,
471
+ description: "Runtime features the bundle uses (C-FEATURES): localActivity, externalCancel, childOptions, canOptions, autoUpgrade, runRetry, timeouts (SDK R2); userActivity, updates, queries, searchAttributes, dynamic and interceptors (Phase C, C-R1). A bundle without the field was built before R2 and uses none."
472
+ }
307
473
  }
308
474
  },
309
475
  authoring: {
@@ -447,23 +613,71 @@ function cronTimes(expression, now, tz, accept) {
447
613
  for (let i = 0; i < MAX_ITERATIONS && out.length < FIRE_TIMES; i++) {
448
614
  if (!interval.hasNext()) break;
449
615
  const date = interval.next().toDate();
450
- if (accept(date)) out.push(date.toISOString());
616
+ const verdict = accept(date);
617
+ if (verdict === "stop") break;
618
+ if (verdict === "keep") out.push(date.toISOString());
451
619
  }
452
620
  return out;
453
621
  }
454
- function localParts(date, tz) {
455
- if (!tz) return { weekday: date.getUTCDay(), year: date.getUTCFullYear() };
622
+ var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
623
+ function localFields(date, tz) {
624
+ if (!tz)
625
+ return {
626
+ second: date.getUTCSeconds(),
627
+ minute: date.getUTCMinutes(),
628
+ hour: date.getUTCHours(),
629
+ dayOfMonth: date.getUTCDate(),
630
+ month: date.getUTCMonth() + 1,
631
+ dayOfWeek: date.getUTCDay(),
632
+ year: date.getUTCFullYear()
633
+ };
456
634
  const parts = new Intl.DateTimeFormat("en-US", {
457
635
  timeZone: tz,
458
636
  weekday: "short",
459
- year: "numeric"
637
+ year: "numeric",
638
+ month: "numeric",
639
+ day: "numeric",
640
+ hour: "numeric",
641
+ minute: "numeric",
642
+ second: "numeric",
643
+ hourCycle: "h23"
460
644
  }).formatToParts(date);
461
- const weekdayName = parts.find((part) => part.type === "weekday")?.value ?? "Sun";
462
- const year = Number(parts.find((part) => part.type === "year")?.value ?? date.getUTCFullYear());
463
- const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].indexOf(weekdayName);
464
- return { weekday, year };
645
+ const part = (type) => parts.find((entry) => entry.type === type)?.value ?? "0";
646
+ return {
647
+ second: Number(part("second")),
648
+ minute: Number(part("minute")),
649
+ hour: Number(part("hour")) % 24,
650
+ dayOfMonth: Number(part("day")),
651
+ month: Number(part("month")),
652
+ dayOfWeek: WEEKDAYS.indexOf(part("weekday")),
653
+ year: Number(part("year"))
654
+ };
655
+ }
656
+ function localParts(date, tz) {
657
+ const fields = localFields(date, tz);
658
+ return { weekday: fields["dayOfWeek"] ?? 0, year: fields["year"] ?? 0 };
659
+ }
660
+ var MATCH_FIELDS = [
661
+ { name: "second", min: 0, max: 59, fallback: "0", defaultZero: true },
662
+ { name: "minute", min: 0, max: 59, fallback: "0", defaultZero: true },
663
+ { name: "hour", min: 0, max: 23, fallback: "0", defaultZero: true },
664
+ { name: "dayOfMonth", min: 1, max: 31, fallback: "*", defaultZero: false },
665
+ { name: "month", min: 1, max: 12, fallback: "*", defaultZero: false },
666
+ { name: "dayOfWeek", min: 0, max: 6, fallback: "*", defaultZero: false },
667
+ { name: "year", min: 1970, max: 9999, fallback: "*", defaultZero: false }
668
+ ];
669
+ function calendarMatcher(entry) {
670
+ if (!isRecord(entry)) throw new Error("each excludeCalendars entry must be an object");
671
+ return MATCH_FIELDS.map((field) => {
672
+ const value = entry[field.name];
673
+ if (value === void 0) return [field.name, field.defaultZero ? /* @__PURE__ */ new Set([0]) : void 0];
674
+ return [field.name, new Set(rangeValues(value, field.min, field.max, field.name))];
675
+ });
676
+ }
677
+ function matches(matcher, fields) {
678
+ return matcher.every(([name, values]) => values === void 0 || values.has(fields[name] ?? -1));
465
679
  }
466
- function calendarTimes(entries, now, tz) {
680
+ function calendarTimes(entries, now, tz, accept) {
467
681
  const all = [];
468
682
  for (const entry of entries) {
469
683
  if (!isRecord(entry)) throw new Error("each calendar entry must be an object");
@@ -476,13 +690,15 @@ function calendarTimes(entries, now, tz) {
476
690
  all.push(
477
691
  ...cronTimes(`${expression} *`, now, tz, (date) => {
478
692
  const local = localParts(date, tz);
479
- return (!weekdays || weekdays.has(local.weekday)) && (!years || years.has(local.year));
693
+ if (!((!weekdays || weekdays.has(local.weekday)) && (!years || years.has(local.year))))
694
+ return "skip";
695
+ return accept(date);
480
696
  })
481
697
  );
482
698
  }
483
699
  return [...new Set(all)].sort().slice(0, FIRE_TIMES);
484
700
  }
485
- function intervalTimes(entries, now) {
701
+ function intervalTimes(entries, now, accept) {
486
702
  const all = [];
487
703
  for (const entry of entries) {
488
704
  if (!isRecord(entry)) throw new Error("each interval entry must be an object");
@@ -494,10 +710,24 @@ function intervalTimes(entries, now) {
494
710
  throw new Error("interval.offset must be a duration below every");
495
711
  let next = Math.floor((now.getTime() - offset) / every) * every + offset;
496
712
  if (next <= now.getTime()) next += every;
497
- for (let i = 0; i < FIRE_TIMES; i++) all.push(next + i * every);
713
+ let kept = 0;
714
+ for (let i = 0; i < MAX_ITERATIONS && kept < FIRE_TIMES; i++, next += every) {
715
+ const verdict = accept(new Date(next));
716
+ if (verdict === "stop") break;
717
+ if (verdict === "skip") continue;
718
+ all.push(next);
719
+ kept += 1;
720
+ }
498
721
  }
499
722
  return [...new Set(all)].sort((a, b) => a - b).slice(0, FIRE_TIMES).map((time) => new Date(time).toISOString());
500
723
  }
724
+ function dateField(spec, field) {
725
+ const value = spec[field];
726
+ if (value === void 0) return void 0;
727
+ const ms = typeof value === "string" ? Date.parse(value) : Number.NaN;
728
+ if (Number.isNaN(ms)) throw new Error(`${field} must be an ISO 8601 date-time`);
729
+ return new Date(ms);
730
+ }
501
731
  function checkScheduleSpec(spec, options = {}) {
502
732
  const now = options.now ?? /* @__PURE__ */ new Date();
503
733
  if (!isRecord(spec)) return { ok: false, problem: "spec must be an object", nextFireTimes: [] };
@@ -511,20 +741,37 @@ function checkScheduleSpec(spec, options = {}) {
511
741
  }
512
742
  const tz = timezoneOf(spec, options.timezone);
513
743
  try {
744
+ const startAt = dateField(spec, "startAt");
745
+ const endAt = dateField(spec, "endAt");
746
+ if (startAt && endAt && endAt.getTime() <= startAt.getTime())
747
+ throw new Error("endAt must be after startAt");
748
+ if (spec["jitter"] !== void 0 && durationMs(spec["jitter"], "s") === void 0)
749
+ throw new Error("jitter must be a duration");
750
+ const excludes = spec["excludeCalendars"];
751
+ if (excludes !== void 0 && !Array.isArray(excludes))
752
+ throw new Error("excludeCalendars must be a list");
753
+ const matchers = (excludes ?? []).map(calendarMatcher);
754
+ const from = startAt && startAt.getTime() > now.getTime() ? new Date(startAt.getTime() - 1) : now;
755
+ const accept = (date) => {
756
+ if (endAt && date.getTime() > endAt.getTime()) return "stop";
757
+ if (matchers.length === 0) return "keep";
758
+ const fields = localFields(date, tz);
759
+ return matchers.some((matcher) => matches(matcher, fields)) ? "skip" : "keep";
760
+ };
514
761
  let times;
515
762
  if (kinds[0] === "cron") {
516
763
  if (typeof spec["cron"] !== "string") throw new Error("cron must be a string");
517
- times = cronTimes(spec["cron"], now, tz, () => true);
764
+ times = cronTimes(spec["cron"], from, tz, accept);
518
765
  } else if (kinds[0] === "calendar") {
519
766
  if (!Array.isArray(spec["calendar"]) || spec["calendar"].length === 0) {
520
767
  throw new Error("calendar must be a non-empty list");
521
768
  }
522
- times = calendarTimes(spec["calendar"], now, tz);
769
+ times = calendarTimes(spec["calendar"], from, tz, accept);
523
770
  } else {
524
771
  if (!Array.isArray(spec["interval"]) || spec["interval"].length === 0) {
525
772
  throw new Error("interval must be a non-empty list");
526
773
  }
527
- times = intervalTimes(spec["interval"], now);
774
+ times = intervalTimes(spec["interval"], from, accept);
528
775
  }
529
776
  if (times.length === 0)
530
777
  return { ok: false, problem: "the spec never fires", nextFireTimes: [] };
@@ -537,6 +784,26 @@ function checkScheduleSpec(spec, options = {}) {
537
784
  };
538
785
  }
539
786
  }
787
+ function checkSchedulePolicy(state) {
788
+ const policy = state["overlapPolicy"];
789
+ if (policy !== void 0 && !(typeof policy === "string" && SCHEDULE_OVERLAP_POLICIES.includes(policy)))
790
+ return {
791
+ field: "overlapPolicy",
792
+ message: `overlapPolicy must be one of ${SCHEDULE_OVERLAP_POLICIES.join(", ")}`
793
+ };
794
+ const window = state["catchupWindow"];
795
+ if (window !== void 0 && durationMs(window, "s") === void 0)
796
+ return { field: "catchupWindow", message: "catchupWindow must be a duration" };
797
+ if (state["pauseOnFailure"] !== void 0 && typeof state["pauseOnFailure"] !== "boolean")
798
+ return { field: "pauseOnFailure", message: "pauseOnFailure must be true or false" };
799
+ const limited = state["limitedActions"];
800
+ if (limited !== void 0 && !(typeof limited === "number" && Number.isInteger(limited) && limited >= 1))
801
+ return { field: "limitedActions", message: "limitedActions must be a positive integer" };
802
+ for (const field of ["scheduleContext", "scheduleSearchAttributes"])
803
+ if (state[field] !== void 0 && !isRecord(state[field]))
804
+ return { field, message: `${field} must be an object` };
805
+ return void 0;
806
+ }
540
807
 
541
808
  // src/ir/validate.ts
542
809
  var SLUG = /^[a-z][a-z0-9-]{0,62}$/;
@@ -778,7 +1045,8 @@ function validate(definition, options = {}) {
778
1045
  message: "A code-workflow node needs a code bundle on the definition",
779
1046
  ...at
780
1047
  });
781
- } else if (typeof workflowFn !== "string" || !Object.hasOwn(workflowExports, workflowFn)) {
1048
+ } else if (typeof workflowFn !== "string" || workflowFn === "" || // A dynamic workflow ("*", 11 §2.29) serves every other name.
1049
+ !(Object.hasOwn(workflowExports, workflowFn) || Object.hasOwn(workflowExports, "*"))) {
782
1050
  fail({
783
1051
  code: "codeWorkflow.unknownFunction",
784
1052
  message: `workflowFn "${String(workflowFn)}" is not exported by the bundle`,
@@ -846,6 +1114,44 @@ function validate(definition, options = {}) {
846
1114
  });
847
1115
  }
848
1116
  }
1117
+ if (type === "internal:schedule" && state !== void 0) {
1118
+ const problem = checkSchedulePolicy(state);
1119
+ if (problem !== void 0)
1120
+ fail({
1121
+ code: "schedule.invalidPolicy",
1122
+ message: `Schedule policy: ${problem.message}`,
1123
+ ...at,
1124
+ path: `args.state.${problem.field}`
1125
+ });
1126
+ }
1127
+ if (type === SIGNAL_RUN_NODE_TYPE) {
1128
+ const target = state?.["target"];
1129
+ const valid = isRecord(target) && (typeof target["runId"] === "string" || target["parent"] === true || typeof target["workflowKey"] === "string" && typeof target["workflowId"] === "string");
1130
+ if (typeof state?.["signalName"] !== "string" || state["signalName"] === "")
1131
+ fail({
1132
+ code: "signalRun.signalNameRequired",
1133
+ message: "A signal-run node needs a signalName",
1134
+ ...at,
1135
+ path: "args.state.signalName"
1136
+ });
1137
+ if (!valid)
1138
+ fail({
1139
+ code: "signalRun.invalidTarget",
1140
+ message: "A signal-run node needs a target: { runId }, { workflowKey, workflowId } or { parent: true }",
1141
+ ...at,
1142
+ path: "args.state.target"
1143
+ });
1144
+ }
1145
+ if (type === SET_SEARCH_ATTRIBUTES_NODE_TYPE) {
1146
+ const attributes = state?.["attributes"];
1147
+ if (!isRecord(attributes) || Object.keys(attributes).length === 0)
1148
+ fail({
1149
+ code: "setSearchAttributes.attributesRequired",
1150
+ message: "A set-search-attributes node needs at least one attribute",
1151
+ ...at,
1152
+ path: "args.state.attributes"
1153
+ });
1154
+ }
849
1155
  if (strict) {
850
1156
  if (id && !SLUG.test(id)) {
851
1157
  fail({
@@ -1110,4 +1416,4 @@ function deriveInterface(definition, options = {}) {
1110
1416
  return derived;
1111
1417
  }
1112
1418
 
1113
- export { IR_V2_SCHEMA, IR_V2_SCHEMA_ID, WORKFLOW_DOCUMENT_FORMAT, buildExportDocument, checkScheduleSpec, deriveInterface, envelopeSchemaVersion, executorNodeView, executorView, exportDefinition, isV2Definition, isValidJsonSchema, parseWorkflowDocument, readWorkflowDocument, serializeWorkflowDocument, validate, workflowInputsSchema };
1419
+ export { DEFAULT_NEW_SCHEDULE_OVERLAP_POLICY, DEFAULT_SCHEDULE_CATCHUP_WINDOW_SECONDS, IR_V2_SCHEMA, IR_V2_SCHEMA_ID, SCHEDULE_OVERLAP_POLICIES, SCHEDULE_POLICY_FIELDS, SCHEDULE_SPEC_FIELDS, WORKFLOW_DOCUMENT_FORMAT, buildExportDocument, checkSchedulePolicy, checkScheduleSpec, deriveInterface, envelopeSchemaVersion, executorNodeView, executorView, exportDefinition, isV2Definition, isValidJsonSchema, parseWorkflowDocument, readWorkflowDocument, serializeWorkflowDocument, validate, workflowInputsSchema };
@@ -1,6 +1,6 @@
1
1
  import { S as SourceFile } from './hash-CZkTXPCX.cjs';
2
- import { b as WorkflowDefinition, W as WorkflowInterface } from './types-BGoPzgcl.cjs';
3
- import { C as ConnectionResolver } from './assemble-BLqQ8lSu.cjs';
2
+ import { W as WorkflowDefinition, b as WorkflowInterface, k as WorkflowConfig } from './types-V7jEEUaL.cjs';
3
+ import { d as ConnectionResolver, a as CollectedDurableWorkflow } from './collect-CcTCKqx6.cjs';
4
4
  import { E as EsbuildApi, L as LowerError } from './lower-types-DQNBfWQn.cjs';
5
5
 
6
6
  /** One vendored package: its version and its files (paths relative to the package root). */
@@ -20,6 +20,12 @@ interface BuildBundleOptions {
20
20
  maxSourceBytes?: number;
21
21
  /** Largest bundle, in UTF-8 bytes. Default 1.5 MiB (4 MiB with vendored deps). */
22
22
  maxBundleBytes?: number;
23
+ /**
24
+ * `external` also returns a source map of the bundle (C-SOURCEMAP) in
25
+ * `map`. The bundle bytes, and so `buildId`, are the same as without it:
26
+ * no `sourceMappingURL` comment is added.
27
+ */
28
+ sourcemap?: 'external';
23
29
  }
24
30
  interface BuiltBundle {
25
31
  /** The ES module. */
@@ -33,6 +39,18 @@ interface BuiltBundle {
33
39
  */
34
40
  sourceHash: string;
35
41
  entries: string[];
42
+ /**
43
+ * The project modules (`workflows/order.ts`) and vendored files
44
+ * (`node_modules/<package>/<path>`) the bundle contains, sorted.
45
+ */
46
+ modules: string[];
47
+ /**
48
+ * With `sourcemap: 'external'`: the source map (version 3 JSON) of the
49
+ * bundle. Sources are named like build messages (`workflows/order.ts`,
50
+ * `node_modules/<package>/<path>`, `@fluidgrids/workflows`); the map holds
51
+ * no source contents, which the source archive already has.
52
+ */
53
+ map?: string;
36
54
  }
37
55
  /** Node built-in module names (without the `node:` prefix). */
38
56
  declare const NODE_BUILTINS: ReadonlySet<string>;
@@ -87,7 +105,7 @@ interface LowerOptions {
87
105
  }
88
106
  /** A problem `lower()` found in tier-2 sources without running them. */
89
107
  interface LowerIssue {
90
- code: 'durable.phaseC' | 'durable.activityTypeNotAllowed';
108
+ code: 'durable.phaseC' | 'durable.activityTypeNotAllowed' | 'durable.localActivityTimeout' | 'durable.activityImplInBundle';
91
109
  message: string;
92
110
  module: string;
93
111
  }
@@ -108,22 +126,52 @@ interface LowerResult {
108
126
  durableExports: Record<string, {
109
127
  interface: WorkflowInterface;
110
128
  taskQueue: string;
129
+ config?: WorkflowConfig;
111
130
  }>;
112
131
  /** Findings in tier-2 sources (Phase C features, refused activity node types). */
113
132
  issues: LowerIssue[];
133
+ /**
134
+ * Runtime features the bundle uses (C-FEATURES), sorted; written as
135
+ * `code.features` when not empty. The service refuses a feature its
136
+ * workspace flags do not enable.
137
+ */
138
+ features: string[];
114
139
  }
115
140
  /**
116
141
  * Bundle a project. Exported so services can compute `buildId` without
117
142
  * evaluating; `buildBundle()` is the full form (vendored packages, limits).
118
143
  */
119
144
  declare function bundleProject(files: ReadonlyMap<string, string>, entries: readonly string[], esbuild: EsbuildApi): Promise<string>;
145
+ /** The `code.exports.workflows` key of a dynamic workflow (11 §2.29). */
146
+ declare const DYNAMIC_EXPORT = "*";
147
+ /**
148
+ * Find user local activities (not run yet), refused activity node types and
149
+ * local-activity timeouts over the cap in the modules a tier-2 workflow may
150
+ * run (see {@link durableScanModules}), without running them. The runtime and
151
+ * the service refuse them as well; this reports them before a push. The
152
+ * Phase C features (queries, updates, user activities, search attributes,
153
+ * dynamic workflows, interceptors and sinks) are no longer findings: they are
154
+ * written to `code.features` and gated by the service (C-FEATURES).
155
+ *
156
+ * With `bundled` (the modules `buildBundle` put into the bundle), a
157
+ * user-activity implementation in one of them is reported as
158
+ * `durable.activityImplInBundle`: it belongs on a worker (CWD9).
159
+ */
160
+ declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>, bundled?: readonly string[]): LowerIssue[];
161
+ /**
162
+ * The modules a tier-2 workflow may run code from: every source module of a
163
+ * project that declares one (the declaring modules and every helper they may
164
+ * import), sorted. A project without tier-2 workflows has none.
165
+ */
166
+ declare function durableScanModules(files: ReadonlyMap<string, string>, durable: readonly Pick<CollectedDurableWorkflow, 'module'>[]): string[];
120
167
  /**
121
- * Find Phase C features and refused activity node types in the modules that
122
- * declare tier-2 functions, without running them. The runtime and the service
123
- * refuse both as well; this reports them before a push.
168
+ * The runtime features (C-FEATURES) of a bundle: what the call sites of every
169
+ * module a tier-2 workflow may run show (project helpers and vendored
170
+ * packages included), and what its declarations' options use, sorted and
171
+ * without duplicates.
124
172
  */
125
- declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>): LowerIssue[];
173
+ declare function durableFeatures(files: ReadonlyMap<string, string>, durable: readonly CollectedDurableWorkflow[], deps?: VendoredDeps): string[];
126
174
  /** Lower TypeScript sources (tier 1 and tier 2) to IR v2. */
127
175
  declare function lower(files: readonly SourceFile[] | Readonly<Record<string, string>>, options?: LowerOptions): Promise<LowerResult>;
128
176
 
129
- export { type BuildBundleOptions as B, DeterminismViolationError as D, type Evaluator as E, type LowerIssue as L, NODE_BUILTINS as N, type VendoredDeps as V, type VendoredPackage as a, type BuiltBundle as b, ESBUILD_VERSION as c, EVALUATION_GLOBAL as d, type LowerOptions as e, type LowerResult as f, type LoweredWorkflow as g, buildBundle as h, bundleProject as i, bundleSourceHash as j, defaultEntries as k, lower as l, splitSpecifier as m, resolvePackageEntry as r, scanDurableSources as s };
177
+ export { type BuildBundleOptions as B, DYNAMIC_EXPORT as D, type Evaluator as E, type LowerIssue as L, NODE_BUILTINS as N, type VendoredDeps as V, type VendoredPackage as a, type BuiltBundle as b, DeterminismViolationError as c, ESBUILD_VERSION as d, EVALUATION_GLOBAL as e, type LowerOptions as f, type LowerResult as g, type LoweredWorkflow as h, buildBundle as i, bundleProject as j, bundleSourceHash as k, defaultEntries as l, durableFeatures as m, durableScanModules as n, lower as o, splitSpecifier as p, resolvePackageEntry as r, scanDurableSources as s };