@fluidgrids/workflows 2026.1029.1 → 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 (118) hide show
  1. package/README.md +112 -4
  2. package/dist/{activation-CESehfYi.d.cts → activation-DqUfpHzk.d.cts} +1 -1
  3. package/dist/{activation-BnVQMv9y.d.ts → activation-xpx1oWuo.d.ts} +1 -1
  4. package/dist/{chunk-MJ5TGYVG.js → chunk-2D3MYIIF.js} +969 -153
  5. package/dist/{chunk-2B37XAFQ.cjs → chunk-3U2NU7YC.cjs} +24 -11
  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-2DDULZFM.js → chunk-5HIVIV53.js} +86 -75
  9. package/dist/chunk-5MFVJM76.js +1222 -0
  10. package/dist/{chunk-EWYADREB.cjs → chunk-672KMMBK.cjs} +2 -2
  11. package/dist/{chunk-KXJDRQ6G.js → chunk-6A2FGSUS.js} +22 -2
  12. package/dist/{chunk-OIX4O6UR.js → chunk-6OLN6BMB.js} +16 -3
  13. package/dist/{chunk-6FSHT5IL.js → chunk-7EZIANC7.js} +1 -1
  14. package/dist/chunk-A5SXCA62.cjs +93 -0
  15. package/dist/chunk-AC6ZEXVR.js +85 -0
  16. package/dist/{chunk-FWBRQWRX.js → chunk-AE5Q6ZAJ.js} +167 -10
  17. package/dist/{chunk-7ILGCUI6.js → chunk-C4F5KJTI.js} +142 -3
  18. package/dist/{chunk-WXXNCHUY.js → chunk-G5H32GIG.js} +1 -1
  19. package/dist/{chunk-OMY3CKUZ.cjs → chunk-GEQDGUGB.cjs} +1042 -226
  20. package/dist/{chunk-25BKWR2O.js → chunk-HCM7ZC7Q.js} +1 -1
  21. package/dist/{chunk-I47EENR4.cjs → chunk-HMZUGSMU.cjs} +673 -156
  22. package/dist/{chunk-NXFBVDOI.cjs → chunk-IQPXHQQQ.cjs} +8 -4
  23. package/dist/{chunk-RUQIMTN5.cjs → chunk-ISOIA7NV.cjs} +178 -15
  24. package/dist/chunk-JSC75O5C.cjs +167 -0
  25. package/dist/{chunk-BD7ZPG53.js → chunk-NWQ5WRLE.js} +10 -2
  26. package/dist/chunk-ODZ2IAR2.cjs +1247 -0
  27. package/dist/{chunk-FQSJI5NV.js → chunk-SR7TR5KX.js} +6 -2
  28. package/dist/{chunk-OKX3FYIM.cjs → chunk-TCTE7DX5.cjs} +3 -3
  29. package/dist/{chunk-3FIDHONL.cjs → chunk-TYF56RGB.cjs} +99 -80
  30. package/dist/{chunk-J3PYFGKA.cjs → chunk-VA4OFR72.cjs} +162 -4
  31. package/dist/chunk-VU5S5A7V.js +150 -0
  32. package/dist/{chunk-A36CCOWS.js → chunk-YEHR4NNE.js} +633 -128
  33. package/dist/{chunk-ELL2RBML.cjs → chunk-ZCGKGDCL.cjs} +23 -1
  34. package/dist/codegen/index.d.cts +2 -2
  35. package/dist/codegen/index.d.ts +2 -2
  36. package/dist/{collect-BTHjQaSp.d.ts → collect-6NIEufHd.d.ts} +20 -3
  37. package/dist/{collect-CSyOg5XC.d.cts → collect-CcTCKqx6.d.cts} +20 -3
  38. package/dist/{file-cgL9l9l8.d.cts → file-BxYpwjRQ.d.cts} +250 -15
  39. package/dist/{file-olQudcx5.d.ts → file-CFdPQJI9.d.ts} +250 -15
  40. package/dist/history/index.cjs +283 -106
  41. package/dist/history/index.d.cts +549 -10
  42. package/dist/history/index.d.ts +549 -10
  43. package/dist/history/index.js +5 -4
  44. package/dist/index.cjs +146 -53
  45. package/dist/index.d.cts +38 -14
  46. package/dist/index.d.ts +38 -14
  47. package/dist/index.js +6 -5
  48. package/dist/interceptors-CNcr2dlk.d.ts +159 -0
  49. package/dist/interceptors-CqkNZVfI.d.cts +159 -0
  50. package/dist/ir/index.cjs +339 -36
  51. package/dist/ir/index.d.cts +244 -8
  52. package/dist/ir/index.d.ts +244 -8
  53. package/dist/ir/index.js +306 -21
  54. package/dist/{lower-3S6PsqjJ.d.cts → lower-BtRfIW2A.d.cts} +23 -9
  55. package/dist/{lower-DmZpQ8hJ.d.ts → lower-CpsMFOFX.d.ts} +23 -9
  56. package/dist/{manifest-BJjrQt77.d.ts → manifest-D-I_twys.d.ts} +1 -1
  57. package/dist/{manifest-gRI2Q5Fj.d.cts → manifest-DahBQVM8.d.cts} +1 -1
  58. package/dist/node-evaluator-DGQDPSPI.cjs +24 -0
  59. package/dist/node-evaluator-LEEVD7H7.js +14 -0
  60. package/dist/payload-fields-BVRQn2yH.d.cts +122 -0
  61. package/dist/payload-fields-oOBWxDiG.d.ts +122 -0
  62. package/dist/quickjs/index.cjs +27 -27
  63. package/dist/quickjs/index.d.cts +6 -6
  64. package/dist/quickjs/index.d.ts +6 -6
  65. package/dist/quickjs/index.js +9 -9
  66. package/dist/roundtrip/index.cjs +72 -66
  67. package/dist/roundtrip/index.d.cts +25 -11
  68. package/dist/roundtrip/index.d.ts +25 -11
  69. package/dist/roundtrip/index.js +13 -11
  70. package/dist/runtime/index.cjs +19 -19
  71. package/dist/runtime/index.d.cts +139 -12
  72. package/dist/runtime/index.d.ts +139 -12
  73. package/dist/runtime/index.js +6 -6
  74. package/dist/testing/index.cjs +688 -121
  75. package/dist/testing/index.d.cts +174 -10
  76. package/dist/testing/index.d.ts +174 -10
  77. package/dist/testing/index.js +646 -82
  78. package/dist/{types-CnIOinoz.d.ts → types-Bv2i4cBX.d.cts} +126 -23
  79. package/dist/{types-CQKOhPTa.d.cts → types-DGx-b9eq.d.ts} +126 -23
  80. package/dist/{types-Bb2wRnJ5.d.cts → types-V7jEEUaL.d.cts} +1 -1
  81. package/dist/{types-Bb2wRnJ5.d.ts → types-V7jEEUaL.d.ts} +1 -1
  82. package/dist/{workflow-8uRU9rhL.d.ts → workflow-B18OeF7g.d.ts} +2 -2
  83. package/dist/{workflow-DWTPHFbt.d.ts → workflow-BGnv8SS6.d.ts} +261 -14
  84. package/dist/{workflow-CZOXUlQ5.d.cts → workflow-BJPFv3cp.d.cts} +2 -2
  85. package/dist/{workflow-O6e64ZcG.d.cts → workflow-DS32Gtws.d.cts} +261 -14
  86. package/fixtures/histories/activity-options-updated.history.json +159 -0
  87. package/fixtures/histories/activity-paused-unpaused.history.json +160 -0
  88. package/fixtures/histories/codec-opaque.history.json +229 -0
  89. package/fixtures/histories/dynamic-workflow.history.json +150 -0
  90. package/fixtures/histories/interceptor-headers.history.json +339 -0
  91. package/fixtures/histories/query-custom.history.json +213 -0
  92. package/fixtures/histories/query-default-handler.history.json +120 -0
  93. package/fixtures/histories/reset-forked-reapplied-signals.history.json +239 -0
  94. package/fixtures/histories/reset-reapplied-update-admitted.history.json +228 -0
  95. package/fixtures/histories/search-attributes-upserted.history.json +177 -0
  96. package/fixtures/histories/update-accepted-completed.history.json +45 -30
  97. package/fixtures/histories/update-default-handler.history.json +246 -0
  98. package/fixtures/histories/update-handler-awaits-activity.history.json +196 -0
  99. package/fixtures/histories/update-not-handled.history.json +138 -0
  100. package/fixtures/histories/update-rejected-no-event.history.json +190 -0
  101. package/fixtures/histories/update-with-start-admitted.history.json +150 -0
  102. package/fixtures/histories/user-activity-cancel.history.json +149 -0
  103. package/fixtures/histories/user-activity-retry.history.json +143 -0
  104. package/fixtures/histories/user-activity.history.json +149 -0
  105. package/package.json +1 -1
  106. package/schema/bridge-v2.schema.json +1062 -0
  107. package/schema/history-file.schema.json +255 -81
  108. package/schema/ir-v2.schema.json +246 -1
  109. package/schema/payload-fields.json +162 -0
  110. package/schema/run-event.schema.json +239 -80
  111. package/schema/workflow-command.schema.json +210 -84
  112. package/schema/workflow-task.schema.json +532 -167
  113. package/dist/chunk-6QPOJZT6.cjs +0 -1180
  114. package/dist/chunk-A2OHX3UQ.js +0 -1156
  115. package/dist/chunk-PWIUEWC3.js +0 -81
  116. package/dist/chunk-YHBVMOMK.cjs +0 -87
  117. package/dist/node-evaluator-SOADN23V.js +0 -14
  118. package/dist/node-evaluator-YGDEXK4U.cjs +0 -24
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
  },
@@ -323,7 +468,7 @@ var IR_V2_SCHEMA = {
323
468
  type: "array",
324
469
  items: { type: "string", minLength: 1 },
325
470
  uniqueItems: true,
326
- description: "Runtime features the bundle uses (C-FEATURES, SDK R2): localActivity, externalCancel, childOptions, canOptions, autoUpgrade, runRetry, timeouts; Phase C adds userActivity, updates, queries, searchAttributes, dynamic and interceptors. A bundle without the field was built before R2 and uses none."
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."
327
472
  }
328
473
  }
329
474
  },
@@ -468,23 +613,71 @@ function cronTimes(expression, now, tz, accept) {
468
613
  for (let i = 0; i < MAX_ITERATIONS && out.length < FIRE_TIMES; i++) {
469
614
  if (!interval.hasNext()) break;
470
615
  const date = interval.next().toDate();
471
- 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());
472
619
  }
473
620
  return out;
474
621
  }
475
- function localParts(date, tz) {
476
- 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
+ };
477
634
  const parts = new Intl.DateTimeFormat("en-US", {
478
635
  timeZone: tz,
479
636
  weekday: "short",
480
- year: "numeric"
637
+ year: "numeric",
638
+ month: "numeric",
639
+ day: "numeric",
640
+ hour: "numeric",
641
+ minute: "numeric",
642
+ second: "numeric",
643
+ hourCycle: "h23"
481
644
  }).formatToParts(date);
482
- const weekdayName = parts.find((part) => part.type === "weekday")?.value ?? "Sun";
483
- const year = Number(parts.find((part) => part.type === "year")?.value ?? date.getUTCFullYear());
484
- const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].indexOf(weekdayName);
485
- 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
+ });
486
676
  }
487
- function calendarTimes(entries, now, tz) {
677
+ function matches(matcher, fields) {
678
+ return matcher.every(([name, values]) => values === void 0 || values.has(fields[name] ?? -1));
679
+ }
680
+ function calendarTimes(entries, now, tz, accept) {
488
681
  const all = [];
489
682
  for (const entry of entries) {
490
683
  if (!isRecord(entry)) throw new Error("each calendar entry must be an object");
@@ -497,13 +690,15 @@ function calendarTimes(entries, now, tz) {
497
690
  all.push(
498
691
  ...cronTimes(`${expression} *`, now, tz, (date) => {
499
692
  const local = localParts(date, tz);
500
- 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);
501
696
  })
502
697
  );
503
698
  }
504
699
  return [...new Set(all)].sort().slice(0, FIRE_TIMES);
505
700
  }
506
- function intervalTimes(entries, now) {
701
+ function intervalTimes(entries, now, accept) {
507
702
  const all = [];
508
703
  for (const entry of entries) {
509
704
  if (!isRecord(entry)) throw new Error("each interval entry must be an object");
@@ -515,10 +710,24 @@ function intervalTimes(entries, now) {
515
710
  throw new Error("interval.offset must be a duration below every");
516
711
  let next = Math.floor((now.getTime() - offset) / every) * every + offset;
517
712
  if (next <= now.getTime()) next += every;
518
- 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
+ }
519
721
  }
520
722
  return [...new Set(all)].sort((a, b) => a - b).slice(0, FIRE_TIMES).map((time) => new Date(time).toISOString());
521
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
+ }
522
731
  function checkScheduleSpec(spec, options = {}) {
523
732
  const now = options.now ?? /* @__PURE__ */ new Date();
524
733
  if (!isRecord(spec)) return { ok: false, problem: "spec must be an object", nextFireTimes: [] };
@@ -532,20 +741,37 @@ function checkScheduleSpec(spec, options = {}) {
532
741
  }
533
742
  const tz = timezoneOf(spec, options.timezone);
534
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
+ };
535
761
  let times;
536
762
  if (kinds[0] === "cron") {
537
763
  if (typeof spec["cron"] !== "string") throw new Error("cron must be a string");
538
- times = cronTimes(spec["cron"], now, tz, () => true);
764
+ times = cronTimes(spec["cron"], from, tz, accept);
539
765
  } else if (kinds[0] === "calendar") {
540
766
  if (!Array.isArray(spec["calendar"]) || spec["calendar"].length === 0) {
541
767
  throw new Error("calendar must be a non-empty list");
542
768
  }
543
- times = calendarTimes(spec["calendar"], now, tz);
769
+ times = calendarTimes(spec["calendar"], from, tz, accept);
544
770
  } else {
545
771
  if (!Array.isArray(spec["interval"]) || spec["interval"].length === 0) {
546
772
  throw new Error("interval must be a non-empty list");
547
773
  }
548
- times = intervalTimes(spec["interval"], now);
774
+ times = intervalTimes(spec["interval"], from, accept);
549
775
  }
550
776
  if (times.length === 0)
551
777
  return { ok: false, problem: "the spec never fires", nextFireTimes: [] };
@@ -558,6 +784,26 @@ function checkScheduleSpec(spec, options = {}) {
558
784
  };
559
785
  }
560
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
+ }
561
807
 
562
808
  // src/ir/validate.ts
563
809
  var SLUG = /^[a-z][a-z0-9-]{0,62}$/;
@@ -799,7 +1045,8 @@ function validate(definition, options = {}) {
799
1045
  message: "A code-workflow node needs a code bundle on the definition",
800
1046
  ...at
801
1047
  });
802
- } 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, "*"))) {
803
1050
  fail({
804
1051
  code: "codeWorkflow.unknownFunction",
805
1052
  message: `workflowFn "${String(workflowFn)}" is not exported by the bundle`,
@@ -867,6 +1114,44 @@ function validate(definition, options = {}) {
867
1114
  });
868
1115
  }
869
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
+ }
870
1155
  if (strict) {
871
1156
  if (id && !SLUG.test(id)) {
872
1157
  fail({
@@ -1131,4 +1416,4 @@ function deriveInterface(definition, options = {}) {
1131
1416
  return derived;
1132
1417
  }
1133
1418
 
1134
- 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 { W as WorkflowDefinition, b as WorkflowInterface, k as WorkflowConfig } from './types-Bb2wRnJ5.cjs';
3
- import { d as ConnectionResolver, a as CollectedDurableWorkflow } from './collect-CSyOg5XC.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). */
@@ -39,6 +39,11 @@ interface BuiltBundle {
39
39
  */
40
40
  sourceHash: string;
41
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[];
42
47
  /**
43
48
  * With `sourcemap: 'external'`: the source map (version 3 JSON) of the
44
49
  * bundle. Sources are named like build messages (`workflows/order.ts`,
@@ -100,7 +105,7 @@ interface LowerOptions {
100
105
  }
101
106
  /** A problem `lower()` found in tier-2 sources without running them. */
102
107
  interface LowerIssue {
103
- code: 'durable.phaseC' | 'durable.activityTypeNotAllowed' | 'durable.localActivityTimeout';
108
+ code: 'durable.phaseC' | 'durable.activityTypeNotAllowed' | 'durable.localActivityTimeout' | 'durable.activityImplInBundle';
104
109
  message: string;
105
110
  module: string;
106
111
  }
@@ -137,13 +142,22 @@ interface LowerResult {
137
142
  * evaluating; `buildBundle()` is the full form (vendored packages, limits).
138
143
  */
139
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 = "*";
140
147
  /**
141
- * Find Phase C features, refused activity node types and local-activity
142
- * timeouts over the cap in the modules a tier-2 workflow may run (see
143
- * {@link durableScanModules}), without running them. The runtime and the service
144
- * refuse both as well; this reports them before a push.
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).
145
159
  */
146
- declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>): LowerIssue[];
160
+ declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>, bundled?: readonly string[]): LowerIssue[];
147
161
  /**
148
162
  * The modules a tier-2 workflow may run code from: every source module of a
149
163
  * project that declares one (the declaring modules and every helper they may
@@ -160,4 +174,4 @@ declare function durableFeatures(files: ReadonlyMap<string, string>, durable: re
160
174
  /** Lower TypeScript sources (tier 1 and tier 2) to IR v2. */
161
175
  declare function lower(files: readonly SourceFile[] | Readonly<Record<string, string>>, options?: LowerOptions): Promise<LowerResult>;
162
176
 
163
- 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, durableFeatures as l, durableScanModules as m, lower as n, splitSpecifier as o, 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 };
@@ -1,6 +1,6 @@
1
1
  import { S as SourceFile } from './hash-CZkTXPCX.js';
2
- import { W as WorkflowDefinition, b as WorkflowInterface, k as WorkflowConfig } from './types-Bb2wRnJ5.js';
3
- import { d as ConnectionResolver, a as CollectedDurableWorkflow } from './collect-BTHjQaSp.js';
2
+ import { W as WorkflowDefinition, b as WorkflowInterface, k as WorkflowConfig } from './types-V7jEEUaL.js';
3
+ import { d as ConnectionResolver, a as CollectedDurableWorkflow } from './collect-6NIEufHd.js';
4
4
  import { E as EsbuildApi, L as LowerError } from './lower-types-DQNBfWQn.js';
5
5
 
6
6
  /** One vendored package: its version and its files (paths relative to the package root). */
@@ -39,6 +39,11 @@ interface BuiltBundle {
39
39
  */
40
40
  sourceHash: string;
41
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[];
42
47
  /**
43
48
  * With `sourcemap: 'external'`: the source map (version 3 JSON) of the
44
49
  * bundle. Sources are named like build messages (`workflows/order.ts`,
@@ -100,7 +105,7 @@ interface LowerOptions {
100
105
  }
101
106
  /** A problem `lower()` found in tier-2 sources without running them. */
102
107
  interface LowerIssue {
103
- code: 'durable.phaseC' | 'durable.activityTypeNotAllowed' | 'durable.localActivityTimeout';
108
+ code: 'durable.phaseC' | 'durable.activityTypeNotAllowed' | 'durable.localActivityTimeout' | 'durable.activityImplInBundle';
104
109
  message: string;
105
110
  module: string;
106
111
  }
@@ -137,13 +142,22 @@ interface LowerResult {
137
142
  * evaluating; `buildBundle()` is the full form (vendored packages, limits).
138
143
  */
139
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 = "*";
140
147
  /**
141
- * Find Phase C features, refused activity node types and local-activity
142
- * timeouts over the cap in the modules a tier-2 workflow may run (see
143
- * {@link durableScanModules}), without running them. The runtime and the service
144
- * refuse both as well; this reports them before a push.
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).
145
159
  */
146
- declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>): LowerIssue[];
160
+ declare function scanDurableSources(files: ReadonlyMap<string, string>, modules: Iterable<string>, bundled?: readonly string[]): LowerIssue[];
147
161
  /**
148
162
  * The modules a tier-2 workflow may run code from: every source module of a
149
163
  * project that declares one (the declaring modules and every helper they may
@@ -160,4 +174,4 @@ declare function durableFeatures(files: ReadonlyMap<string, string>, durable: re
160
174
  /** Lower TypeScript sources (tier 1 and tier 2) to IR v2. */
161
175
  declare function lower(files: readonly SourceFile[] | Readonly<Record<string, string>>, options?: LowerOptions): Promise<LowerResult>;
162
176
 
163
- 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, durableFeatures as l, durableScanModules as m, lower as n, splitSpecifier as o, 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 };
@@ -1,4 +1,4 @@
1
- import { a as JsonObject } from './types-Bb2wRnJ5.js';
1
+ import { J as JsonObject } from './types-V7jEEUaL.js';
2
2
 
3
3
  /** One input or output field. Output fields may also be a bare type name. */
4
4
  interface ManifestField {
@@ -1,4 +1,4 @@
1
- import { a as JsonObject } from './types-Bb2wRnJ5.cjs';
1
+ import { J as JsonObject } from './types-V7jEEUaL.cjs';
2
2
 
3
3
  /** One input or output field. Output fields may also be a bare type name. */
4
4
  interface ManifestField {
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var chunkTCTE7DX5_cjs = require('./chunk-TCTE7DX5.cjs');
4
+ require('./chunk-ODZ2IAR2.cjs');
5
+ require('./chunk-3U2NU7YC.cjs');
6
+ require('./chunk-IQPXHQQQ.cjs');
7
+ require('./chunk-54FLQNUM.cjs');
8
+ require('./chunk-G4UEPUGO.cjs');
9
+ require('./chunk-GVTZMA5C.cjs');
10
+ require('./chunk-QKZL3ONM.cjs');
11
+ require('./chunk-TBDXTV22.cjs');
12
+ require('./chunk-SAENRNBJ.cjs');
13
+ require('./chunk-VA4OFR72.cjs');
14
+ require('./chunk-FR7KYWRO.cjs');
15
+ require('./chunk-A5SXCA62.cjs');
16
+ require('./chunk-TYF56RGB.cjs');
17
+ require('./chunk-Z2Y65YOY.cjs');
18
+
19
+
20
+
21
+ Object.defineProperty(exports, "createNodeVmEvaluator", {
22
+ enumerable: true,
23
+ get: function () { return chunkTCTE7DX5_cjs.createNodeVmEvaluator; }
24
+ });
@@ -0,0 +1,14 @@
1
+ export { createNodeVmEvaluator } from './chunk-HCM7ZC7Q.js';
2
+ import './chunk-5MFVJM76.js';
3
+ import './chunk-6OLN6BMB.js';
4
+ import './chunk-SR7TR5KX.js';
5
+ import './chunk-NWQ5WRLE.js';
6
+ import './chunk-5LUIDMF4.js';
7
+ import './chunk-JZ4TOOLN.js';
8
+ import './chunk-E2VK7J2C.js';
9
+ import './chunk-7AAZGVKD.js';
10
+ import './chunk-PMCM2OH4.js';
11
+ import './chunk-C4F5KJTI.js';
12
+ import './chunk-LNUQE6D6.js';
13
+ import './chunk-AC6ZEXVR.js';
14
+ import './chunk-5HIVIV53.js';