@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.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkNEIUQASE_cjs = require('../chunk-NEIUQASE.cjs');
3
+ var chunk4QKB4ARC_cjs = require('../chunk-4QKB4ARC.cjs');
4
4
  var chunkCPDK3K5N_cjs = require('../chunk-CPDK3K5N.cjs');
5
- var chunkGBQ33SIZ_cjs = require('../chunk-GBQ33SIZ.cjs');
5
+ var chunk54FLQNUM_cjs = require('../chunk-54FLQNUM.cjs');
6
6
  var chunkG4UEPUGO_cjs = require('../chunk-G4UEPUGO.cjs');
7
7
  var chunkQKZL3ONM_cjs = require('../chunk-QKZL3ONM.cjs');
8
8
  var chunkTBDXTV22_cjs = require('../chunk-TBDXTV22.cjs');
@@ -12,8 +12,41 @@ require('../chunk-Z2Y65YOY.cjs');
12
12
  var _2020_js = require('ajv/dist/2020.js');
13
13
  var cronParser = require('cron-parser');
14
14
 
15
+ // src/ir/schedule-fields.ts
16
+ var SCHEDULE_OVERLAP_POLICIES = [
17
+ "SKIP",
18
+ "BUFFER_ONE",
19
+ "BUFFER_ALL",
20
+ "CANCEL_OTHER",
21
+ "TERMINATE_OTHER",
22
+ "ALLOW_ALL"
23
+ ];
24
+ var DEFAULT_NEW_SCHEDULE_OVERLAP_POLICY = "SKIP";
25
+ var DEFAULT_SCHEDULE_CATCHUP_WINDOW_SECONDS = 3600;
26
+ var SCHEDULE_POLICY_FIELDS = [
27
+ "overlapPolicy",
28
+ "catchupWindow",
29
+ "pauseOnFailure",
30
+ "limitedActions",
31
+ "scheduleContext",
32
+ "scheduleSearchAttributes"
33
+ ];
34
+ var SCHEDULE_SPEC_FIELDS = [
35
+ "excludeCalendars",
36
+ "startAt",
37
+ "endAt",
38
+ "timezone",
39
+ "jitter"
40
+ ];
41
+
15
42
  // src/ir/schema.ts
16
43
  var JSON_SCHEMA_OBJECT = { type: "object" };
44
+ var DURATION = {
45
+ oneOf: [
46
+ { type: "number", minimum: 0 },
47
+ { type: "string", minLength: 1 }
48
+ ]
49
+ };
17
50
  var IR_V2_SCHEMA_ID = "https://docs.fluidgrids.ai/schemas/workflow-ir-v2.schema.json";
18
51
  var IR_V2_SCHEMA = {
19
52
  $schema: "https://json-schema.org/draft/2020-12/schema",
@@ -181,6 +214,118 @@ var IR_V2_SCHEMA = {
181
214
  }
182
215
  }
183
216
  }
217
+ },
218
+ {
219
+ if: { properties: { type: { const: "internal:signal-run" } }, required: ["type"] },
220
+ then: {
221
+ 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>).",
222
+ required: ["args"],
223
+ properties: {
224
+ args: {
225
+ required: ["state"],
226
+ properties: {
227
+ state: {
228
+ type: "object",
229
+ required: ["signalName", "target"],
230
+ properties: {
231
+ signalName: { type: "string", minLength: 1 },
232
+ target: {
233
+ description: "The run to signal: { runId }, { workflowKey, workflowId, firstRunId? } (the open run of that workflow id) or { parent: true }. Values may be expressions.",
234
+ oneOf: [
235
+ {
236
+ type: "object",
237
+ required: ["runId"],
238
+ properties: { runId: { type: "string", minLength: 1 } },
239
+ additionalProperties: false
240
+ },
241
+ {
242
+ type: "object",
243
+ required: ["workflowKey", "workflowId"],
244
+ properties: {
245
+ workflowKey: { type: "string", minLength: 1 },
246
+ workflowId: { type: "string", minLength: 1 },
247
+ firstRunId: { type: "string", minLength: 1 }
248
+ },
249
+ additionalProperties: false
250
+ },
251
+ {
252
+ type: "object",
253
+ required: ["parent"],
254
+ properties: { parent: { const: true } },
255
+ additionalProperties: false
256
+ }
257
+ ]
258
+ },
259
+ payload: {},
260
+ failOnUndelivered: {
261
+ type: "boolean",
262
+ description: "Default true: an undelivered signal fails the node."
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ },
271
+ {
272
+ if: {
273
+ properties: { type: { const: "internal:set-search-attributes" } },
274
+ required: ["type"]
275
+ },
276
+ then: {
277
+ 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.",
278
+ required: ["args"],
279
+ properties: {
280
+ args: {
281
+ required: ["state"],
282
+ properties: {
283
+ state: {
284
+ type: "object",
285
+ required: ["attributes"],
286
+ properties: {
287
+ attributes: { type: "object", minProperties: 1 }
288
+ }
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
294
+ },
295
+ {
296
+ if: { properties: { type: { const: "internal:schedule" } }, required: ["type"] },
297
+ then: {
298
+ properties: {
299
+ args: {
300
+ properties: {
301
+ state: {
302
+ 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.",
303
+ properties: {
304
+ overlapPolicy: { enum: [...SCHEDULE_OVERLAP_POLICIES] },
305
+ catchupWindow: DURATION,
306
+ pauseOnFailure: { type: "boolean" },
307
+ limitedActions: { type: "integer", minimum: 1 },
308
+ scheduleContext: { type: "object" },
309
+ scheduleSearchAttributes: { type: "object" },
310
+ spec: {
311
+ description: "One of cron, calendar or interval, plus excludeCalendars (calendar entries whose matches are skipped), startAt, endAt (ISO 8601), timezone and jitter.",
312
+ properties: {
313
+ cron: { type: "string" },
314
+ calendar: { type: "array", items: { type: "object" } },
315
+ interval: { type: "array", items: { type: "object" } },
316
+ excludeCalendars: { type: "array", items: { type: "object" } },
317
+ startAt: { type: "string", minLength: 1 },
318
+ endAt: { type: "string", minLength: 1 },
319
+ timezone: { type: "string" },
320
+ jitter: DURATION
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
184
329
  }
185
330
  ]
186
331
  },
@@ -322,7 +467,7 @@ var IR_V2_SCHEMA = {
322
467
  type: "array",
323
468
  items: { type: "string", minLength: 1 },
324
469
  uniqueItems: true,
325
- 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."
470
+ 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."
326
471
  }
327
472
  }
328
473
  },
@@ -367,7 +512,7 @@ function executorNodeView(node) {
367
512
  const args = chunkSAENRNBJ_cjs.isRecord(record["args"]) ? record["args"] : void 0;
368
513
  const dataArgs = chunkSAENRNBJ_cjs.isRecord(data?.["args"]) ? data["args"] : void 0;
369
514
  const type = typeof record["type"] === "string" ? record["type"] : "";
370
- const merged = chunkGBQ33SIZ_cjs.usesMergedParameters(type);
515
+ const merged = chunk54FLQNUM_cjs.usesMergedParameters(type);
371
516
  let parameters;
372
517
  if (merged) {
373
518
  const config = chunkSAENRNBJ_cjs.isRecord(record["config"]) ? record["config"] : {};
@@ -467,23 +612,71 @@ function cronTimes(expression, now, tz, accept) {
467
612
  for (let i = 0; i < MAX_ITERATIONS && out.length < FIRE_TIMES; i++) {
468
613
  if (!interval.hasNext()) break;
469
614
  const date = interval.next().toDate();
470
- if (accept(date)) out.push(date.toISOString());
615
+ const verdict = accept(date);
616
+ if (verdict === "stop") break;
617
+ if (verdict === "keep") out.push(date.toISOString());
471
618
  }
472
619
  return out;
473
620
  }
474
- function localParts(date, tz) {
475
- if (!tz) return { weekday: date.getUTCDay(), year: date.getUTCFullYear() };
621
+ var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
622
+ function localFields(date, tz) {
623
+ if (!tz)
624
+ return {
625
+ second: date.getUTCSeconds(),
626
+ minute: date.getUTCMinutes(),
627
+ hour: date.getUTCHours(),
628
+ dayOfMonth: date.getUTCDate(),
629
+ month: date.getUTCMonth() + 1,
630
+ dayOfWeek: date.getUTCDay(),
631
+ year: date.getUTCFullYear()
632
+ };
476
633
  const parts = new Intl.DateTimeFormat("en-US", {
477
634
  timeZone: tz,
478
635
  weekday: "short",
479
- year: "numeric"
636
+ year: "numeric",
637
+ month: "numeric",
638
+ day: "numeric",
639
+ hour: "numeric",
640
+ minute: "numeric",
641
+ second: "numeric",
642
+ hourCycle: "h23"
480
643
  }).formatToParts(date);
481
- const weekdayName = parts.find((part) => part.type === "weekday")?.value ?? "Sun";
482
- const year = Number(parts.find((part) => part.type === "year")?.value ?? date.getUTCFullYear());
483
- const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].indexOf(weekdayName);
484
- return { weekday, year };
644
+ const part = (type) => parts.find((entry) => entry.type === type)?.value ?? "0";
645
+ return {
646
+ second: Number(part("second")),
647
+ minute: Number(part("minute")),
648
+ hour: Number(part("hour")) % 24,
649
+ dayOfMonth: Number(part("day")),
650
+ month: Number(part("month")),
651
+ dayOfWeek: WEEKDAYS.indexOf(part("weekday")),
652
+ year: Number(part("year"))
653
+ };
654
+ }
655
+ function localParts(date, tz) {
656
+ const fields = localFields(date, tz);
657
+ return { weekday: fields["dayOfWeek"] ?? 0, year: fields["year"] ?? 0 };
658
+ }
659
+ var MATCH_FIELDS = [
660
+ { name: "second", min: 0, max: 59, fallback: "0", defaultZero: true },
661
+ { name: "minute", min: 0, max: 59, fallback: "0", defaultZero: true },
662
+ { name: "hour", min: 0, max: 23, fallback: "0", defaultZero: true },
663
+ { name: "dayOfMonth", min: 1, max: 31, fallback: "*", defaultZero: false },
664
+ { name: "month", min: 1, max: 12, fallback: "*", defaultZero: false },
665
+ { name: "dayOfWeek", min: 0, max: 6, fallback: "*", defaultZero: false },
666
+ { name: "year", min: 1970, max: 9999, fallback: "*", defaultZero: false }
667
+ ];
668
+ function calendarMatcher(entry) {
669
+ if (!chunkSAENRNBJ_cjs.isRecord(entry)) throw new Error("each excludeCalendars entry must be an object");
670
+ return MATCH_FIELDS.map((field) => {
671
+ const value = entry[field.name];
672
+ if (value === void 0) return [field.name, field.defaultZero ? /* @__PURE__ */ new Set([0]) : void 0];
673
+ return [field.name, new Set(rangeValues(value, field.min, field.max, field.name))];
674
+ });
675
+ }
676
+ function matches(matcher, fields) {
677
+ return matcher.every(([name, values]) => values === void 0 || values.has(fields[name] ?? -1));
485
678
  }
486
- function calendarTimes(entries, now, tz) {
679
+ function calendarTimes(entries, now, tz, accept) {
487
680
  const all = [];
488
681
  for (const entry of entries) {
489
682
  if (!chunkSAENRNBJ_cjs.isRecord(entry)) throw new Error("each calendar entry must be an object");
@@ -496,13 +689,15 @@ function calendarTimes(entries, now, tz) {
496
689
  all.push(
497
690
  ...cronTimes(`${expression} *`, now, tz, (date) => {
498
691
  const local = localParts(date, tz);
499
- return (!weekdays || weekdays.has(local.weekday)) && (!years || years.has(local.year));
692
+ if (!((!weekdays || weekdays.has(local.weekday)) && (!years || years.has(local.year))))
693
+ return "skip";
694
+ return accept(date);
500
695
  })
501
696
  );
502
697
  }
503
698
  return [...new Set(all)].sort().slice(0, FIRE_TIMES);
504
699
  }
505
- function intervalTimes(entries, now) {
700
+ function intervalTimes(entries, now, accept) {
506
701
  const all = [];
507
702
  for (const entry of entries) {
508
703
  if (!chunkSAENRNBJ_cjs.isRecord(entry)) throw new Error("each interval entry must be an object");
@@ -514,10 +709,24 @@ function intervalTimes(entries, now) {
514
709
  throw new Error("interval.offset must be a duration below every");
515
710
  let next = Math.floor((now.getTime() - offset) / every) * every + offset;
516
711
  if (next <= now.getTime()) next += every;
517
- for (let i = 0; i < FIRE_TIMES; i++) all.push(next + i * every);
712
+ let kept = 0;
713
+ for (let i = 0; i < MAX_ITERATIONS && kept < FIRE_TIMES; i++, next += every) {
714
+ const verdict = accept(new Date(next));
715
+ if (verdict === "stop") break;
716
+ if (verdict === "skip") continue;
717
+ all.push(next);
718
+ kept += 1;
719
+ }
518
720
  }
519
721
  return [...new Set(all)].sort((a, b) => a - b).slice(0, FIRE_TIMES).map((time) => new Date(time).toISOString());
520
722
  }
723
+ function dateField(spec, field) {
724
+ const value = spec[field];
725
+ if (value === void 0) return void 0;
726
+ const ms = typeof value === "string" ? Date.parse(value) : Number.NaN;
727
+ if (Number.isNaN(ms)) throw new Error(`${field} must be an ISO 8601 date-time`);
728
+ return new Date(ms);
729
+ }
521
730
  function checkScheduleSpec(spec, options = {}) {
522
731
  const now = options.now ?? /* @__PURE__ */ new Date();
523
732
  if (!chunkSAENRNBJ_cjs.isRecord(spec)) return { ok: false, problem: "spec must be an object", nextFireTimes: [] };
@@ -531,20 +740,37 @@ function checkScheduleSpec(spec, options = {}) {
531
740
  }
532
741
  const tz = timezoneOf(spec, options.timezone);
533
742
  try {
743
+ const startAt = dateField(spec, "startAt");
744
+ const endAt = dateField(spec, "endAt");
745
+ if (startAt && endAt && endAt.getTime() <= startAt.getTime())
746
+ throw new Error("endAt must be after startAt");
747
+ if (spec["jitter"] !== void 0 && chunkFR7KYWRO_cjs.durationMs(spec["jitter"], "s") === void 0)
748
+ throw new Error("jitter must be a duration");
749
+ const excludes = spec["excludeCalendars"];
750
+ if (excludes !== void 0 && !Array.isArray(excludes))
751
+ throw new Error("excludeCalendars must be a list");
752
+ const matchers = (excludes ?? []).map(calendarMatcher);
753
+ const from = startAt && startAt.getTime() > now.getTime() ? new Date(startAt.getTime() - 1) : now;
754
+ const accept = (date) => {
755
+ if (endAt && date.getTime() > endAt.getTime()) return "stop";
756
+ if (matchers.length === 0) return "keep";
757
+ const fields = localFields(date, tz);
758
+ return matchers.some((matcher) => matches(matcher, fields)) ? "skip" : "keep";
759
+ };
534
760
  let times;
535
761
  if (kinds[0] === "cron") {
536
762
  if (typeof spec["cron"] !== "string") throw new Error("cron must be a string");
537
- times = cronTimes(spec["cron"], now, tz, () => true);
763
+ times = cronTimes(spec["cron"], from, tz, accept);
538
764
  } else if (kinds[0] === "calendar") {
539
765
  if (!Array.isArray(spec["calendar"]) || spec["calendar"].length === 0) {
540
766
  throw new Error("calendar must be a non-empty list");
541
767
  }
542
- times = calendarTimes(spec["calendar"], now, tz);
768
+ times = calendarTimes(spec["calendar"], from, tz, accept);
543
769
  } else {
544
770
  if (!Array.isArray(spec["interval"]) || spec["interval"].length === 0) {
545
771
  throw new Error("interval must be a non-empty list");
546
772
  }
547
- times = intervalTimes(spec["interval"], now);
773
+ times = intervalTimes(spec["interval"], from, accept);
548
774
  }
549
775
  if (times.length === 0)
550
776
  return { ok: false, problem: "the spec never fires", nextFireTimes: [] };
@@ -557,6 +783,26 @@ function checkScheduleSpec(spec, options = {}) {
557
783
  };
558
784
  }
559
785
  }
786
+ function checkSchedulePolicy(state) {
787
+ const policy = state["overlapPolicy"];
788
+ if (policy !== void 0 && !(typeof policy === "string" && SCHEDULE_OVERLAP_POLICIES.includes(policy)))
789
+ return {
790
+ field: "overlapPolicy",
791
+ message: `overlapPolicy must be one of ${SCHEDULE_OVERLAP_POLICIES.join(", ")}`
792
+ };
793
+ const window = state["catchupWindow"];
794
+ if (window !== void 0 && chunkFR7KYWRO_cjs.durationMs(window, "s") === void 0)
795
+ return { field: "catchupWindow", message: "catchupWindow must be a duration" };
796
+ if (state["pauseOnFailure"] !== void 0 && typeof state["pauseOnFailure"] !== "boolean")
797
+ return { field: "pauseOnFailure", message: "pauseOnFailure must be true or false" };
798
+ const limited = state["limitedActions"];
799
+ if (limited !== void 0 && !(typeof limited === "number" && Number.isInteger(limited) && limited >= 1))
800
+ return { field: "limitedActions", message: "limitedActions must be a positive integer" };
801
+ for (const field of ["scheduleContext", "scheduleSearchAttributes"])
802
+ if (state[field] !== void 0 && !chunkSAENRNBJ_cjs.isRecord(state[field]))
803
+ return { field, message: `${field} must be an object` };
804
+ return void 0;
805
+ }
560
806
 
561
807
  // src/ir/validate.ts
562
808
  var SLUG = /^[a-z][a-z0-9-]{0,62}$/;
@@ -626,7 +872,7 @@ function isHardSchemaError(error) {
626
872
  function legacyMirrors(node) {
627
873
  const found = [];
628
874
  const type = typeof node["type"] === "string" ? node["type"] : "";
629
- const merged = chunkGBQ33SIZ_cjs.usesMergedParameters(type);
875
+ const merged = chunk54FLQNUM_cjs.usesMergedParameters(type);
630
876
  const data = chunkSAENRNBJ_cjs.isRecord(node["data"]) ? node["data"] : void 0;
631
877
  const dataArgs = chunkSAENRNBJ_cjs.isRecord(data?.["args"]) ? data["args"] : void 0;
632
878
  if (data) {
@@ -790,7 +1036,7 @@ function validate(definition, options = {}) {
790
1036
  const type = typeof node["type"] === "string" ? node["type"] : "";
791
1037
  const args = chunkSAENRNBJ_cjs.isRecord(node["args"]) ? node["args"] : void 0;
792
1038
  const state = chunkSAENRNBJ_cjs.isRecord(args?.["state"]) ? args["state"] : void 0;
793
- if (type === chunkGBQ33SIZ_cjs.CODE_WORKFLOW_NODE_TYPE) {
1039
+ if (type === chunk54FLQNUM_cjs.CODE_WORKFLOW_NODE_TYPE) {
794
1040
  const workflowFn = state?.["workflowFn"];
795
1041
  if (!code) {
796
1042
  fail({
@@ -798,7 +1044,8 @@ function validate(definition, options = {}) {
798
1044
  message: "A code-workflow node needs a code bundle on the definition",
799
1045
  ...at
800
1046
  });
801
- } else if (typeof workflowFn !== "string" || !Object.hasOwn(workflowExports, workflowFn)) {
1047
+ } else if (typeof workflowFn !== "string" || workflowFn === "" || // A dynamic workflow ("*", 11 §2.29) serves every other name.
1048
+ !(Object.hasOwn(workflowExports, workflowFn) || Object.hasOwn(workflowExports, "*"))) {
802
1049
  fail({
803
1050
  code: "codeWorkflow.unknownFunction",
804
1051
  message: `workflowFn "${String(workflowFn)}" is not exported by the bundle`,
@@ -823,7 +1070,7 @@ function validate(definition, options = {}) {
823
1070
  path: "args.state.timeout"
824
1071
  });
825
1072
  }
826
- if (type === chunkGBQ33SIZ_cjs.WAIT_FOR_SIGNAL_NODE_TYPE) {
1073
+ if (type === chunk54FLQNUM_cjs.WAIT_FOR_SIGNAL_NODE_TYPE) {
827
1074
  const until = state?.["limitWaitUntil"];
828
1075
  if (until !== void 0 && (typeof until !== "string" || Number.isNaN(Date.parse(until))))
829
1076
  fail({
@@ -833,7 +1080,7 @@ function validate(definition, options = {}) {
833
1080
  path: "args.state.limitWaitUntil"
834
1081
  });
835
1082
  }
836
- const isTrigger = chunkGBQ33SIZ_cjs.INTERNAL_TRIGGER_TYPES.has(type) || id !== void 0 && (incoming.get(id) ?? 0) === 0;
1083
+ const isTrigger = chunk54FLQNUM_cjs.INTERNAL_TRIGGER_TYPES.has(type) || id !== void 0 && (incoming.get(id) ?? 0) === 0;
837
1084
  if (isTrigger && state?.["startDelay"] !== void 0) {
838
1085
  const delay = chunkFR7KYWRO_cjs.durationMs(state["startDelay"], "s");
839
1086
  if (delay === void 0) {
@@ -866,6 +1113,44 @@ function validate(definition, options = {}) {
866
1113
  });
867
1114
  }
868
1115
  }
1116
+ if (type === "internal:schedule" && state !== void 0) {
1117
+ const problem = checkSchedulePolicy(state);
1118
+ if (problem !== void 0)
1119
+ fail({
1120
+ code: "schedule.invalidPolicy",
1121
+ message: `Schedule policy: ${problem.message}`,
1122
+ ...at,
1123
+ path: `args.state.${problem.field}`
1124
+ });
1125
+ }
1126
+ if (type === chunk54FLQNUM_cjs.SIGNAL_RUN_NODE_TYPE) {
1127
+ const target = state?.["target"];
1128
+ const valid = chunkSAENRNBJ_cjs.isRecord(target) && (typeof target["runId"] === "string" || target["parent"] === true || typeof target["workflowKey"] === "string" && typeof target["workflowId"] === "string");
1129
+ if (typeof state?.["signalName"] !== "string" || state["signalName"] === "")
1130
+ fail({
1131
+ code: "signalRun.signalNameRequired",
1132
+ message: "A signal-run node needs a signalName",
1133
+ ...at,
1134
+ path: "args.state.signalName"
1135
+ });
1136
+ if (!valid)
1137
+ fail({
1138
+ code: "signalRun.invalidTarget",
1139
+ message: "A signal-run node needs a target: { runId }, { workflowKey, workflowId } or { parent: true }",
1140
+ ...at,
1141
+ path: "args.state.target"
1142
+ });
1143
+ }
1144
+ if (type === chunk54FLQNUM_cjs.SET_SEARCH_ATTRIBUTES_NODE_TYPE) {
1145
+ const attributes = state?.["attributes"];
1146
+ if (!chunkSAENRNBJ_cjs.isRecord(attributes) || Object.keys(attributes).length === 0)
1147
+ fail({
1148
+ code: "setSearchAttributes.attributesRequired",
1149
+ message: "A set-search-attributes node needs at least one attribute",
1150
+ ...at,
1151
+ path: "args.state.attributes"
1152
+ });
1153
+ }
869
1154
  if (strict) {
870
1155
  if (id && !SLUG.test(id)) {
871
1156
  fail({
@@ -1023,14 +1308,14 @@ function isV2Definition(definition) {
1023
1308
  const data = definition["data"];
1024
1309
  const nodes = chunkSAENRNBJ_cjs.isRecord(data) && Array.isArray(data["nodes"]) ? data["nodes"] : [];
1025
1310
  return nodes.some(
1026
- (node) => chunkSAENRNBJ_cjs.isRecord(node) && typeof node["type"] === "string" && chunkGBQ33SIZ_cjs.V2_NODE_TYPES.has(node["type"])
1311
+ (node) => chunkSAENRNBJ_cjs.isRecord(node) && typeof node["type"] === "string" && chunk54FLQNUM_cjs.V2_NODE_TYPES.has(node["type"])
1027
1312
  );
1028
1313
  }
1029
1314
  function envelopeSchemaVersion(definition) {
1030
1315
  return isV2Definition(definition) ? 2 : 1;
1031
1316
  }
1032
1317
  function exportDefinition(definition) {
1033
- return isV2Definition(definition) ? chunkGBQ33SIZ_cjs.normalizeDefinition(definition) : definition;
1318
+ return isV2Definition(definition) ? chunk54FLQNUM_cjs.normalizeDefinition(definition) : definition;
1034
1319
  }
1035
1320
  function buildExportDocument(input) {
1036
1321
  return {
@@ -1132,7 +1417,7 @@ function deriveInterface(definition, options = {}) {
1132
1417
 
1133
1418
  Object.defineProperty(exports, "diffDefinitions", {
1134
1419
  enumerable: true,
1135
- get: function () { return chunkNEIUQASE_cjs.diffDefinitions; }
1420
+ get: function () { return chunk4QKB4ARC_cjs.diffDefinitions; }
1136
1421
  });
1137
1422
  Object.defineProperty(exports, "fieldSchema", {
1138
1423
  enumerable: true,
@@ -1156,39 +1441,51 @@ Object.defineProperty(exports, "operationsOf", {
1156
1441
  });
1157
1442
  Object.defineProperty(exports, "CODE_WORKFLOW_NODE_TYPE", {
1158
1443
  enumerable: true,
1159
- get: function () { return chunkGBQ33SIZ_cjs.CODE_WORKFLOW_NODE_TYPE; }
1444
+ get: function () { return chunk54FLQNUM_cjs.CODE_WORKFLOW_NODE_TYPE; }
1160
1445
  });
1161
1446
  Object.defineProperty(exports, "INTERNAL_TRIGGER_TYPES", {
1162
1447
  enumerable: true,
1163
- get: function () { return chunkGBQ33SIZ_cjs.INTERNAL_TRIGGER_TYPES; }
1448
+ get: function () { return chunk54FLQNUM_cjs.INTERNAL_TRIGGER_TYPES; }
1449
+ });
1450
+ Object.defineProperty(exports, "PHASE_C_NODE_TYPES", {
1451
+ enumerable: true,
1452
+ get: function () { return chunk54FLQNUM_cjs.PHASE_C_NODE_TYPES; }
1453
+ });
1454
+ Object.defineProperty(exports, "SET_SEARCH_ATTRIBUTES_NODE_TYPE", {
1455
+ enumerable: true,
1456
+ get: function () { return chunk54FLQNUM_cjs.SET_SEARCH_ATTRIBUTES_NODE_TYPE; }
1457
+ });
1458
+ Object.defineProperty(exports, "SIGNAL_RUN_NODE_TYPE", {
1459
+ enumerable: true,
1460
+ get: function () { return chunk54FLQNUM_cjs.SIGNAL_RUN_NODE_TYPE; }
1164
1461
  });
1165
1462
  Object.defineProperty(exports, "WAIT_FOR_SIGNAL_NODE_TYPE", {
1166
1463
  enumerable: true,
1167
- get: function () { return chunkGBQ33SIZ_cjs.WAIT_FOR_SIGNAL_NODE_TYPE; }
1464
+ get: function () { return chunk54FLQNUM_cjs.WAIT_FOR_SIGNAL_NODE_TYPE; }
1168
1465
  });
1169
1466
  Object.defineProperty(exports, "buildIdOf", {
1170
1467
  enumerable: true,
1171
- get: function () { return chunkGBQ33SIZ_cjs.buildIdOf; }
1468
+ get: function () { return chunk54FLQNUM_cjs.buildIdOf; }
1172
1469
  });
1173
1470
  Object.defineProperty(exports, "hashedProjection", {
1174
1471
  enumerable: true,
1175
- get: function () { return chunkGBQ33SIZ_cjs.hashedProjection; }
1472
+ get: function () { return chunk54FLQNUM_cjs.hashedProjection; }
1176
1473
  });
1177
1474
  Object.defineProperty(exports, "irHash", {
1178
1475
  enumerable: true,
1179
- get: function () { return chunkGBQ33SIZ_cjs.irHash; }
1476
+ get: function () { return chunk54FLQNUM_cjs.irHash; }
1180
1477
  });
1181
1478
  Object.defineProperty(exports, "normalizeDefinition", {
1182
1479
  enumerable: true,
1183
- get: function () { return chunkGBQ33SIZ_cjs.normalizeDefinition; }
1480
+ get: function () { return chunk54FLQNUM_cjs.normalizeDefinition; }
1184
1481
  });
1185
1482
  Object.defineProperty(exports, "sourceHash", {
1186
1483
  enumerable: true,
1187
- get: function () { return chunkGBQ33SIZ_cjs.sourceHash; }
1484
+ get: function () { return chunk54FLQNUM_cjs.sourceHash; }
1188
1485
  });
1189
1486
  Object.defineProperty(exports, "usesMergedParameters", {
1190
1487
  enumerable: true,
1191
- get: function () { return chunkGBQ33SIZ_cjs.usesMergedParameters; }
1488
+ get: function () { return chunk54FLQNUM_cjs.usesMergedParameters; }
1192
1489
  });
1193
1490
  Object.defineProperty(exports, "LAYOUT_COLUMN_WIDTH", {
1194
1491
  enumerable: true,
@@ -1242,10 +1539,16 @@ Object.defineProperty(exports, "durationMs", {
1242
1539
  enumerable: true,
1243
1540
  get: function () { return chunkFR7KYWRO_cjs.durationMs; }
1244
1541
  });
1542
+ exports.DEFAULT_NEW_SCHEDULE_OVERLAP_POLICY = DEFAULT_NEW_SCHEDULE_OVERLAP_POLICY;
1543
+ exports.DEFAULT_SCHEDULE_CATCHUP_WINDOW_SECONDS = DEFAULT_SCHEDULE_CATCHUP_WINDOW_SECONDS;
1245
1544
  exports.IR_V2_SCHEMA = IR_V2_SCHEMA;
1246
1545
  exports.IR_V2_SCHEMA_ID = IR_V2_SCHEMA_ID;
1546
+ exports.SCHEDULE_OVERLAP_POLICIES = SCHEDULE_OVERLAP_POLICIES;
1547
+ exports.SCHEDULE_POLICY_FIELDS = SCHEDULE_POLICY_FIELDS;
1548
+ exports.SCHEDULE_SPEC_FIELDS = SCHEDULE_SPEC_FIELDS;
1247
1549
  exports.WORKFLOW_DOCUMENT_FORMAT = WORKFLOW_DOCUMENT_FORMAT;
1248
1550
  exports.buildExportDocument = buildExportDocument;
1551
+ exports.checkSchedulePolicy = checkSchedulePolicy;
1249
1552
  exports.checkScheduleSpec = checkScheduleSpec;
1250
1553
  exports.deriveInterface = deriveInterface;
1251
1554
  exports.envelopeSchemaVersion = envelopeSchemaVersion;