@sanity/workflow-engine 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,85 @@
1
1
  # @sanity/workflow-engine
2
2
 
3
+ ## 0.25.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 177d600: Deployed workflow environment tags are now discoverable.
8
+
9
+ The engine gains two cross-partition GROQ builders: `deployedTagsGroq()` lists
10
+ every tag holding a deployed definition in a resource, and
11
+ `definitionTagsGroq()` narrows that to one definition name via `$definition`.
12
+ Both deliberately span tag partitions — every other read is tag-scoped, and
13
+ `workflow.query` refuses GROQ that isn't — so they answer "which environments
14
+ exist here" for a caller holding a resource but no tag. They report what is
15
+ _observed_: a tag with nothing deployed does not appear.
16
+
17
+ The stdio MCP server adds a `list_workflow_tags` tool taking a
18
+ `workflow_resource` and no tag. It is registered by the host rather than exported
19
+ as a tool def, because a def is only ever handed an engine and an engine is
20
+ pinned to one tag. `LIST_WORKFLOW_TAGS_TOOL_NAME` and
21
+ `LIST_WORKFLOW_TAGS_DESCRIPTION` are exported so an embedding host registers the
22
+ same capability under the same name without re-authoring the model-facing
23
+ wording. The `tag` parameter's description now points an agent at that tool where
24
+ a server offers it and at the user otherwise, and requires confirmation either
25
+ way — having the list does not license picking from it.
26
+
27
+ Both registration paths share one outcome path, `withToolTelemetry`, so the
28
+ result envelope, error rendering, and the `Editorial Workflows MCP Tool Called`
29
+ event cannot diverge between a def-backed tool and a host-registered one. Tag
30
+ discovery reports its adoption event like every other tool, and because it names
31
+ a resource it can also initialize the stdio server's deferred telemetry shell —
32
+ which matters when discovery is an agent's first call.
33
+
34
+ The CLI's definition-tags probe runs the engine's builder instead of its own
35
+ copy of the query, so its `params` key is `definition` rather than `name`, and
36
+ the tag partitions it names in an ambiguity error arrive sorted from the lake.
37
+
38
+ ### Patch Changes
39
+
40
+ - fc12989: Fixes actor resolution failing with `principal id "…" is not an account-global
41
+ user id` for a session scoped to a single project, such as a SAML-SSO Studio
42
+ session.
43
+
44
+ `actor.id` is always the account-global user id, and the id's namespace decides
45
+ which read supplies it rather than the host that answered. Whichever `/users/me`
46
+ read returns an already-account-global id supplies it; a project-scoped id is
47
+ bridged to its account-global form first — by string surgery for an
48
+ `e-<globalId>` principal, otherwise through the project's own user directory
49
+ (`/projects/<id>/users/<principal>` → `sanityUserId`). A SAML-SSO session
50
+ resolves through that directory, because the global host holds no
51
+ account-global record for it.
52
+
53
+ A session whose id is already account-global issues no directory request. A
54
+ project-scoped id that no route can bridge is refused, naming both failed
55
+ routes.
56
+
57
+ The project-user directory admits only a row answering the id it asked for,
58
+ matching the batched member join: a row for another principal reports
59
+ inaccessible rather than resolving to that person's identity.
60
+
61
+ ## 0.24.0
62
+
63
+ ### Minor Changes
64
+
65
+ - 0bc4328: Render diagram tooltips in the Studio's own idiom, through one seam instead of six hand-assembled bodies:
66
+ - Pin the chrome once (padding 2, radius 3, shadow 2, 280px sentence cap / 400px for dev mode's label-value grids). Bodies no longer carry their own outer padding, which had stacked a `padding={3}` box inside the tooltip's own padding.
67
+ - A title with nothing under it renders in regular weight — it is the whole message, not a heading. Semibold is reserved for a title that actually heads content, one per tooltip: gate headings now separate from their checklist rows by full-strength versus muted text rather than a second bold.
68
+ - Checklists, the grouped-edge roster, the group vertex's stage list and an activity's causal waits render as real `<ul>`/`<li>` rows, so wrapping and nesting come from the browser. Previously these were flattened into padded strings with `white-space: pre-wrap`, which left a wrapped row's continuation aligned under its own marker. Each row leads with its glyph in a fixed-width column and hangs its wrapped lines back to the text: one column for a bullet and a verdict alike, where a `list-style-type` marker box is sized by its own content and put the two on different left edges within one tooltip. The glyph is inline content rather than a marker, so it is selected and copied with the row it belongs to.
69
+ - Space the body on one three-step rhythm, named by the role a gap plays: independent blocks (the activity roster, each gate) separate furthest, a lead-in sits closer to the list it introduces, and rows within a list sit closest. A stage tooltip nests several of these, and at one flat step the whole explanation read as a single mass.
70
+ - `MetaTable` renders rows only; the title and description come from the shared body, so dev-mode and end-user tooltips head identically.
71
+
72
+ `OUTCOME_MARKS` and `NEUTRAL_MARK` are now exported (from `@sanity/groq-condition-describe`, re-exported by `@sanity/workflow-engine`), so a structured checklist renderer and `checklistLines` draw their verdict glyphs from one vocabulary.
73
+
74
+ - 41a3f02: Add `dueDate` and `dueDatetime` field kinds — elevated aliases of `date` / `datetime` (same stored value and validation) that mark THE due date of a level, so surfaces can identify a deadline by kind instead of guessing which date field means "due". Declarable at workflow, stage, and activity scope; optional (no field becomes required). The kind reserves a level's single due slot, so deploy enforces both halves of that: at most one due-\* (either kind, combined) per scope, and none below scope level — a due-\* nested in an `object`/`array` sub-field or an effect's `outputs` is rejected, naming `date` / `datetime` as the fix, because no deadline reader looks there. A `todoList` row's `dueDate` column is unaffected; it is a `date` named `dueDate`, not the kind. Choice lists (`options`) work on the due kinds exactly as on `date` / `datetime`. Persisted-model version 5 (additive, reader floor unchanged).
75
+
76
+ The Studio plugin edits and renders the new kinds exactly like the base kinds they elevate: the calendar picker in the start dialog, the Overview pills, the inline field editors and the activity row's date control, a locale-formatted face, and the Workflows tool's Date filter. Every date-family branch now routes through one shared kind predicate, so an elevated alias can't drift out of a site.
77
+
78
+ ### Patch Changes
79
+
80
+ - Updated dependencies [0bc4328]
81
+ - @sanity/groq-condition-describe@0.4.0
82
+
3
83
  ## 0.23.0
4
84
 
5
85
  ### Minor Changes
package/DATAMODEL.md CHANGED
@@ -666,6 +666,42 @@ from that snapshot. Definitions are create-only and instance persists retain
666
666
  unknown fields, so model-4 data survives round trips; the floor prevents an
667
667
  older engine from interpreting it in the first place.
668
668
 
669
+ ### Model 5 — the `dueDate` / `dueDatetime` field kinds (reader floor: 4)
670
+
671
+ One additive growth ships as model 5 — model 4 was released before it landed,
672
+ so it mints the next version rather than amending a shipped one. It does not
673
+ raise the reader floor; the writer maximum stays 4.
674
+
675
+ Two elevated scalar aliases mark THE due date for a level (workflow, stage, or
676
+ activity): `dueDate` aliases `date` (same stored `YYYY-MM-DD` value and
677
+ validation) and `dueDatetime` aliases `datetime` (same stored ISO-8601 value
678
+ and validation). The kind lets surfaces identify a level's deadline instead of
679
+ guessing which date field means "due". Both are optional; a deploy invariant
680
+ allows at most one due-\* (either kind, combined) per scope, so "the due date"
681
+ is never ambiguous. Both stamped trees grow the value:
682
+
683
+ - **Definition tree** — `fields[].type` admits `'dueDate'` and `'dueDatetime'`
684
+ on a scope's own entries only. A due-\* nested in an `object`/`array`
685
+ sub-field, or in an effect's `outputs`, is rejected at deploy: the kind names
686
+ the deadline OF A LEVEL, and every deadline reader consults scope entries, so
687
+ a nested one is dead configuration. Nested dates stay `date` / `datetime`.
688
+ Existing `todoList` sugar is unaffected — its `dueDate` row column is a
689
+ `date` named `dueDate`, not the kind.
690
+ - **Instance tree** — resolved `fields[]` entries admit `_type: 'dueDate'` and
691
+ `_type: 'dueDatetime'` (the same arm shapes as `date` / `datetime`).
692
+
693
+ Manifest feature: `due-date-field-kinds` (definition + instance, additive,
694
+ detectable, floor 0).
695
+
696
+ Would an old reader misread the kinds (rule 5)? No — the same loud refusal as
697
+ the `subject` and `progress` kinds: an older engine (model 4 and below) that
698
+ loaded a due-date-carrying instance fails the strict `fields[]` variant with
699
+ `PersistedDocShapeError` before interpreting anything, and cannot deploy or
700
+ evaluate a due-date-declaring definition. The stored value is byte-identical to
701
+ its base `date` / `datetime`, so no older code path can write it while skipping
702
+ validation — there is no silent bypass to fence, and the kinds leave the floor
703
+ at 0.
704
+
669
705
  ## Pending governed changes
670
706
 
671
707
  - **`temp.system.guard` → `system.guard`** — the guard doc type's `temp.`
@@ -150,7 +150,7 @@ function parentRef(instance) {
150
150
  return instance.ancestors.at(-1);
151
151
  }
152
152
 
153
- const DATA_MODEL_VERSION = 4, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
153
+ const DATA_MODEL_VERSION = 5, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
154
154
 
155
155
  class ReaderModelAcknowledgementError extends WorkflowError {
156
156
  code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
@@ -241,6 +241,14 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
241
241
  compatibility: "reader-floor",
242
242
  applicability: "detectable",
243
243
  summary: "Start and activity readiness use named polymorphic requirement arrays."
244
+ }), Object.freeze({
245
+ id: "due-date-field-kinds",
246
+ introducedInModel: 5,
247
+ minReaderModel: 0,
248
+ documentTypes: Object.freeze([ "definition", "instance" ]),
249
+ compatibility: "additive",
250
+ applicability: "detectable",
251
+ summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
244
252
  }) ]);
245
253
 
246
254
  function recordOf(value) {
@@ -315,7 +323,8 @@ const featureDetectors = {
315
323
  "progress-field-kind": document => hasFieldKind(document, "progress"),
316
324
  "effect-claim-tokens": hasClaimTokens,
317
325
  "classified-principal-ids": () => !0,
318
- "readiness-requirements": hasReadinessRequirements
326
+ "readiness-requirements": hasReadinessRequirements,
327
+ "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime")
319
328
  };
320
329
 
321
330
  function requiredModelFeatures(documentType, document) {
@@ -1845,6 +1854,18 @@ function classifyPrincipalId(id) {
1845
1854
  };
1846
1855
  }
1847
1856
 
1857
+ function directoryBridgeId(sanityUserId) {
1858
+ if (typeof sanityUserId == "string") return classifyPrincipalId(sanityUserId).namespace === "global" ? sanityUserId : void 0;
1859
+ }
1860
+
1861
+ function firstCarriedGlobalId(candidates) {
1862
+ for (const candidate of candidates) {
1863
+ if (candidate === void 0) continue;
1864
+ const {globalId: globalId} = classifyPrincipalId(candidate);
1865
+ if (globalId !== void 0) return globalId;
1866
+ }
1867
+ }
1868
+
1848
1869
  function lakePrincipalId(args) {
1849
1870
  return args.localPrincipalId ?? args.actor.id;
1850
1871
  }
@@ -1879,7 +1900,7 @@ const GdrUriSchema = v__namespace.custom(s => typeof s == "string" && isGdrUri(s
1879
1900
  }), tolerantObject()({
1880
1901
  type: v__namespace.literal("role"),
1881
1902
  role: NonEmptyString
1882
- }) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableProgress = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.number(), v__namespace.finite("progress must be a finite number"), v__namespace.minValue(0, "progress must be at least 0"), v__namespace.maxValue(100, "progress must be at most 100")) ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "datetime", "dateTime" ]);
1903
+ }) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableProgress = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.number(), v__namespace.finite("progress must be a finite number"), v__namespace.minValue(0, "progress must be at least 0"), v__namespace.maxValue(100, "progress must be at most 100")) ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "dueDate", "datetime", "dueDatetime", "dateTime" ]);
1883
1904
 
1884
1905
  function normalizedChoiceKind(kind) {
1885
1906
  return kind === "dateTime" ? "datetime" : kind;
@@ -1914,7 +1935,9 @@ const fieldValueSchemas = {
1914
1935
  progress: NullableProgress,
1915
1936
  boolean: NullableBoolean,
1916
1937
  date: NullableDate,
1938
+ dueDate: NullableDate,
1917
1939
  datetime: NullableDateTime,
1940
+ dueDatetime: NullableDateTime,
1918
1941
  url: NullableUrl,
1919
1942
  actor: v__namespace.union([ v__namespace.null(), ActorShape ]),
1920
1943
  assignee: v__namespace.union([ v__namespace.null(), AssigneeShape ]),
@@ -2279,7 +2302,7 @@ function groupMembershipNames(group) {
2279
2302
  return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
2280
2303
  }
2281
2304
 
2282
- const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v__namespace.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v__namespace.pipe(v__namespace.number(), v__namespace.finite("must be finite")), ScalarValidationSchema = v__namespace.pipe(v__namespace.strictObject({
2305
+ const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "dueDate", "datetime", "dueDatetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v__namespace.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v__namespace.pipe(v__namespace.number(), v__namespace.finite("must be finite")), ScalarValidationSchema = v__namespace.pipe(v__namespace.strictObject({
2283
2306
  min: v__namespace.optional(FiniteNumber),
2284
2307
  max: v__namespace.optional(FiniteNumber)
2285
2308
  }), v__namespace.check(validation => validation.min !== void 0 || validation.max !== void 0, "declare at least one bound, or omit `validation`"), v__namespace.check(validation => validation.min === void 0 || validation.max === void 0 || validation.min <= validation.max, "`min` must be less than or equal to `max`")), ChoiceOptionsSchema = v__namespace.strictObject({
@@ -2669,6 +2692,10 @@ function isSubjectEntry(entry) {
2669
2692
  return entry.type === "subject";
2670
2693
  }
2671
2694
 
2695
+ function isDueDateEntry(entry) {
2696
+ return entry.type === "dueDate" || entry.type === "dueDatetime";
2697
+ }
2698
+
2672
2699
  function isInputSourced(entry) {
2673
2700
  return entry.initialValue?.type === "input";
2674
2701
  }
@@ -3175,25 +3202,79 @@ function checkAssigneesEntries(def, issues) {
3175
3202
  });
3176
3203
  }
3177
3204
 
3178
- function nestedSubjectPaths(shapes, base) {
3179
- return (shapes ?? []).flatMap((shape, i) => isSubjectEntry(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedSubjectPaths(shape.fields, [ ...base, i, "fields" ]), ...nestedSubjectPaths(shape.of, [ ...base, i, "of" ]) ]);
3205
+ function checkDueDateEntries(def, issues) {
3206
+ for (const {entries: entries, path: path, label: label} of fieldScopes(def)) {
3207
+ (entries ?? []).filter(isDueDateEntry).length > 1 && issues.push({
3208
+ path: path,
3209
+ message: "at most one due-date field entry per scope (dueDate or dueDatetime combined) — surfaces identify the deadline by kind"
3210
+ });
3211
+ for (const site of belowScopeNestedSites({
3212
+ entries: entries,
3213
+ path: path,
3214
+ isKind: isDueDateEntry
3215
+ })) issues.push({
3216
+ path: site.path,
3217
+ message: `${label} entry "${site.entry.name}" declares a due-date sub-field — a due-* kind marks THE deadline of a level, so nothing reads one below scope level. Declare \`date\` or \`datetime\` for a nested date`
3218
+ });
3219
+ }
3220
+ }
3221
+
3222
+ function nestedKindPaths(args) {
3223
+ const {shapes: shapes, base: base, isKind: isKind} = args;
3224
+ return (shapes ?? []).flatMap((shape, i) => isKind(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedKindPaths({
3225
+ shapes: shape.fields,
3226
+ base: [ ...base, i, "fields" ],
3227
+ isKind: isKind
3228
+ }), ...nestedKindPaths({
3229
+ shapes: shape.of,
3230
+ base: [ ...base, i, "of" ],
3231
+ isKind: isKind
3232
+ }) ]);
3180
3233
  }
3181
3234
 
3182
- function checkSubjectEffectOutputs(def, issues) {
3183
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushSubjectOutputIssues({
3235
+ function belowScopeNestedSites(args) {
3236
+ const {entries: entries, path: path, isKind: isKind} = args;
3237
+ return (entries ?? []).flatMap((entry, n) => [ ...nestedKindPaths({
3238
+ shapes: entry.fields,
3239
+ base: [ ...path, n, "fields" ],
3240
+ isKind: isKind
3241
+ }), ...nestedKindPaths({
3242
+ shapes: entry.of,
3243
+ base: [ ...path, n, "of" ],
3244
+ isKind: isKind
3245
+ }) ].map(nestedPath => ({
3246
+ path: nestedPath,
3247
+ entry: entry
3248
+ })));
3249
+ }
3250
+
3251
+ function checkLevelKindEffectOutputs(def, issues) {
3252
+ for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushOutputIssues({
3184
3253
  action: action,
3185
3254
  path: [ "stages", i, "activities", j, "actions", a ],
3186
3255
  issues: issues
3187
3256
  });
3188
3257
  }
3189
3258
 
3190
- function pushSubjectOutputIssues(args) {
3259
+ const LEVEL_KIND_OUTPUT_RULES = [ {
3260
+ isKind: isSubjectEntry,
3261
+ message: name => `effect "${name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
3262
+ }, {
3263
+ isKind: isDueDateEntry,
3264
+ message: name => `effect "${name}" declares a due-date output shape — a due-* kind marks THE deadline of a level, and no deadline reader looks at effect outputs. Declare \`date\` or \`datetime\` for a dated output`
3265
+ } ];
3266
+
3267
+ function pushOutputIssues(args) {
3191
3268
  const {action: action, path: path, issues: issues} = args;
3192
3269
  for (const [e, effect] of (action.effects ?? []).entries()) {
3193
3270
  const base = [ ...path, "effects", e, "outputs" ];
3194
- for (const nestedPath of nestedSubjectPaths(effect.outputs, base)) issues.push({
3271
+ for (const {isKind: isKind, message: message} of LEVEL_KIND_OUTPUT_RULES) for (const nestedPath of nestedKindPaths({
3272
+ shapes: effect.outputs,
3273
+ base: base,
3274
+ isKind: isKind
3275
+ })) issues.push({
3195
3276
  path: nestedPath,
3196
- message: `effect "${effect.name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
3277
+ message: message(effect.name)
3197
3278
  });
3198
3279
  }
3199
3280
  }
@@ -3211,13 +3292,14 @@ function checkSubjectEntries(def, issues) {
3211
3292
  path: [ ...path, n ],
3212
3293
  message: "at most one subject-kind field entry per workflow — the runtime identifies THE subject by kind, and a second one makes it ambiguous"
3213
3294
  });
3214
- for (const [n, entry] of (entries ?? []).entries()) {
3215
- const nested = [ ...nestedSubjectPaths(entry.fields, [ ...path, n, "fields" ]), ...nestedSubjectPaths(entry.of, [ ...path, n, "of" ]) ];
3216
- for (const nestedPath of nested) issues.push({
3217
- path: nestedPath,
3218
- message: `${label} entry "${entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
3219
- });
3220
- }
3295
+ for (const site of belowScopeNestedSites({
3296
+ entries: entries,
3297
+ path: path,
3298
+ isKind: isSubjectEntry
3299
+ })) issues.push({
3300
+ path: site.path,
3301
+ message: `${label} entry "${site.entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
3302
+ });
3221
3303
  }
3222
3304
  }
3223
3305
 
@@ -3853,7 +3935,9 @@ const SCALAR = {
3853
3935
  progress: () => SCALAR,
3854
3936
  boolean: () => SCALAR,
3855
3937
  date: () => SCALAR,
3938
+ dueDate: () => SCALAR,
3856
3939
  datetime: () => SCALAR,
3940
+ dueDatetime: () => SCALAR,
3857
3941
  url: () => SCALAR,
3858
3942
  actor: () => ACTOR_VALUE,
3859
3943
  assignee: () => ASSIGNEE_VALUE,
@@ -3944,10 +4028,10 @@ function checkWorkflowInvariants(def) {
3944
4028
  checkRequiredField(def, issues), checkStart(def, issues), checkPredicates(def, issues),
3945
4029
  checkUnboundConditionVars(def, issues), checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues),
3946
4030
  checkFieldReadOpValues(def, issues), checkUpdateWhereOps(def, issues), checkGuardFieldReads(def, issues),
3947
- checkAssigneesEntries(def, issues), checkSubjectEntries(def, issues), checkSubjectEffectOutputs(def, issues),
3948
- checkActivityTerminalPaths(def, issues), checkTerminalStageActivities(def, issues),
3949
- checkTriggeredActionParams(def, issues), checkStoredRolesPlacement(def, issues),
3950
- checkGroups(def, issues), issues;
4031
+ checkAssigneesEntries(def, issues), checkDueDateEntries(def, issues), checkSubjectEntries(def, issues),
4032
+ checkLevelKindEffectOutputs(def, issues), checkActivityTerminalPaths(def, issues),
4033
+ checkTerminalStageActivities(def, issues), checkTriggeredActionParams(def, issues),
4034
+ checkStoredRolesPlacement(def, issues), checkGroups(def, issues), issues;
3951
4035
  }
3952
4036
 
3953
4037
  exports.ACTION_SEMANTICS = ACTION_SEMANTICS;
@@ -4100,6 +4184,8 @@ exports.deriveExecutorClassification = deriveExecutorClassification;
4100
4184
 
4101
4185
  exports.desugarWorkflow = desugarWorkflow;
4102
4186
 
4187
+ exports.directoryBridgeId = directoryBridgeId;
4188
+
4103
4189
  exports.driverKind = driverKind;
4104
4190
 
4105
4191
  exports.errorMessage = errorMessage;
@@ -4116,6 +4202,8 @@ exports.fieldTreeShape = fieldTreeShape;
4116
4202
 
4117
4203
  exports.fieldValueSchemas = fieldValueSchemas;
4118
4204
 
4205
+ exports.firstCarriedGlobalId = firstCarriedGlobalId;
4206
+
4119
4207
  exports.formatIssuePath = formatIssuePath;
4120
4208
 
4121
4209
  exports.formatIssues = formatIssues;
@@ -136,7 +136,7 @@ function parentRef(instance) {
136
136
  return instance.ancestors.at(-1);
137
137
  }
138
138
 
139
- const DATA_MODEL_VERSION = 4, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
139
+ const DATA_MODEL_VERSION = 5, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
140
140
 
141
141
  class ReaderModelAcknowledgementError extends WorkflowError {
142
142
  code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
@@ -227,6 +227,14 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
227
227
  compatibility: "reader-floor",
228
228
  applicability: "detectable",
229
229
  summary: "Start and activity readiness use named polymorphic requirement arrays."
230
+ }), Object.freeze({
231
+ id: "due-date-field-kinds",
232
+ introducedInModel: 5,
233
+ minReaderModel: 0,
234
+ documentTypes: Object.freeze([ "definition", "instance" ]),
235
+ compatibility: "additive",
236
+ applicability: "detectable",
237
+ summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
230
238
  }) ]);
231
239
 
232
240
  function recordOf(value) {
@@ -301,7 +309,8 @@ const featureDetectors = {
301
309
  "progress-field-kind": document => hasFieldKind(document, "progress"),
302
310
  "effect-claim-tokens": hasClaimTokens,
303
311
  "classified-principal-ids": () => !0,
304
- "readiness-requirements": hasReadinessRequirements
312
+ "readiness-requirements": hasReadinessRequirements,
313
+ "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime")
305
314
  };
306
315
 
307
316
  function requiredModelFeatures(documentType, document) {
@@ -1831,6 +1840,18 @@ function classifyPrincipalId(id) {
1831
1840
  };
1832
1841
  }
1833
1842
 
1843
+ function directoryBridgeId(sanityUserId) {
1844
+ if (typeof sanityUserId == "string") return classifyPrincipalId(sanityUserId).namespace === "global" ? sanityUserId : void 0;
1845
+ }
1846
+
1847
+ function firstCarriedGlobalId(candidates) {
1848
+ for (const candidate of candidates) {
1849
+ if (candidate === void 0) continue;
1850
+ const {globalId: globalId} = classifyPrincipalId(candidate);
1851
+ if (globalId !== void 0) return globalId;
1852
+ }
1853
+ }
1854
+
1834
1855
  function lakePrincipalId(args) {
1835
1856
  return args.localPrincipalId ?? args.actor.id;
1836
1857
  }
@@ -1865,7 +1886,7 @@ const GdrUriSchema = v.custom(s => typeof s == "string" && isGdrUri(s), "must be
1865
1886
  }), tolerantObject()({
1866
1887
  type: v.literal("role"),
1867
1888
  role: NonEmptyString
1868
- }) ]), NullableString = v.union([ v.null(), v.string() ]), NullableNumber = v.union([ v.null(), v.number() ]), NullableBoolean = v.union([ v.null(), v.boolean() ]), NullableProgress = v.union([ v.null(), v.pipe(v.number(), v.finite("progress must be a finite number"), v.minValue(0, "progress must be at least 0"), v.maxValue(100, "progress must be at most 100")) ]), NullableDateTime = v.union([ v.null(), IsoTimestamp ]), NullableDate = v.union([ v.null(), v.pipe(v.string(), v.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "datetime", "dateTime" ]);
1889
+ }) ]), NullableString = v.union([ v.null(), v.string() ]), NullableNumber = v.union([ v.null(), v.number() ]), NullableBoolean = v.union([ v.null(), v.boolean() ]), NullableProgress = v.union([ v.null(), v.pipe(v.number(), v.finite("progress must be a finite number"), v.minValue(0, "progress must be at least 0"), v.maxValue(100, "progress must be at most 100")) ]), NullableDateTime = v.union([ v.null(), IsoTimestamp ]), NullableDate = v.union([ v.null(), v.pipe(v.string(), v.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "dueDate", "datetime", "dueDatetime", "dateTime" ]);
1869
1890
 
1870
1891
  function normalizedChoiceKind(kind) {
1871
1892
  return kind === "dateTime" ? "datetime" : kind;
@@ -1900,7 +1921,9 @@ const fieldValueSchemas = {
1900
1921
  progress: NullableProgress,
1901
1922
  boolean: NullableBoolean,
1902
1923
  date: NullableDate,
1924
+ dueDate: NullableDate,
1903
1925
  datetime: NullableDateTime,
1926
+ dueDatetime: NullableDateTime,
1904
1927
  url: NullableUrl,
1905
1928
  actor: v.union([ v.null(), ActorShape ]),
1906
1929
  assignee: v.union([ v.null(), AssigneeShape ]),
@@ -2265,7 +2288,7 @@ function groupMembershipNames(group) {
2265
2288
  return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
2266
2289
  }
2267
2290
 
2268
- const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v.pipe(v.number(), v.finite("must be finite")), ScalarValidationSchema = v.pipe(v.strictObject({
2291
+ const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "dueDate", "datetime", "dueDatetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v.pipe(v.number(), v.finite("must be finite")), ScalarValidationSchema = v.pipe(v.strictObject({
2269
2292
  min: v.optional(FiniteNumber),
2270
2293
  max: v.optional(FiniteNumber)
2271
2294
  }), v.check(validation => validation.min !== void 0 || validation.max !== void 0, "declare at least one bound, or omit `validation`"), v.check(validation => validation.min === void 0 || validation.max === void 0 || validation.min <= validation.max, "`min` must be less than or equal to `max`")), ChoiceOptionsSchema = v.strictObject({
@@ -2655,6 +2678,10 @@ function isSubjectEntry(entry) {
2655
2678
  return entry.type === "subject";
2656
2679
  }
2657
2680
 
2681
+ function isDueDateEntry(entry) {
2682
+ return entry.type === "dueDate" || entry.type === "dueDatetime";
2683
+ }
2684
+
2658
2685
  function isInputSourced(entry) {
2659
2686
  return entry.initialValue?.type === "input";
2660
2687
  }
@@ -3161,25 +3188,79 @@ function checkAssigneesEntries(def, issues) {
3161
3188
  });
3162
3189
  }
3163
3190
 
3164
- function nestedSubjectPaths(shapes, base) {
3165
- return (shapes ?? []).flatMap((shape, i) => isSubjectEntry(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedSubjectPaths(shape.fields, [ ...base, i, "fields" ]), ...nestedSubjectPaths(shape.of, [ ...base, i, "of" ]) ]);
3191
+ function checkDueDateEntries(def, issues) {
3192
+ for (const {entries: entries, path: path, label: label} of fieldScopes(def)) {
3193
+ (entries ?? []).filter(isDueDateEntry).length > 1 && issues.push({
3194
+ path: path,
3195
+ message: "at most one due-date field entry per scope (dueDate or dueDatetime combined) — surfaces identify the deadline by kind"
3196
+ });
3197
+ for (const site of belowScopeNestedSites({
3198
+ entries: entries,
3199
+ path: path,
3200
+ isKind: isDueDateEntry
3201
+ })) issues.push({
3202
+ path: site.path,
3203
+ message: `${label} entry "${site.entry.name}" declares a due-date sub-field — a due-* kind marks THE deadline of a level, so nothing reads one below scope level. Declare \`date\` or \`datetime\` for a nested date`
3204
+ });
3205
+ }
3206
+ }
3207
+
3208
+ function nestedKindPaths(args) {
3209
+ const {shapes: shapes, base: base, isKind: isKind} = args;
3210
+ return (shapes ?? []).flatMap((shape, i) => isKind(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedKindPaths({
3211
+ shapes: shape.fields,
3212
+ base: [ ...base, i, "fields" ],
3213
+ isKind: isKind
3214
+ }), ...nestedKindPaths({
3215
+ shapes: shape.of,
3216
+ base: [ ...base, i, "of" ],
3217
+ isKind: isKind
3218
+ }) ]);
3219
+ }
3220
+
3221
+ function belowScopeNestedSites(args) {
3222
+ const {entries: entries, path: path, isKind: isKind} = args;
3223
+ return (entries ?? []).flatMap((entry, n) => [ ...nestedKindPaths({
3224
+ shapes: entry.fields,
3225
+ base: [ ...path, n, "fields" ],
3226
+ isKind: isKind
3227
+ }), ...nestedKindPaths({
3228
+ shapes: entry.of,
3229
+ base: [ ...path, n, "of" ],
3230
+ isKind: isKind
3231
+ }) ].map(nestedPath => ({
3232
+ path: nestedPath,
3233
+ entry: entry
3234
+ })));
3166
3235
  }
3167
3236
 
3168
- function checkSubjectEffectOutputs(def, issues) {
3169
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushSubjectOutputIssues({
3237
+ function checkLevelKindEffectOutputs(def, issues) {
3238
+ for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushOutputIssues({
3170
3239
  action: action,
3171
3240
  path: [ "stages", i, "activities", j, "actions", a ],
3172
3241
  issues: issues
3173
3242
  });
3174
3243
  }
3175
3244
 
3176
- function pushSubjectOutputIssues(args) {
3245
+ const LEVEL_KIND_OUTPUT_RULES = [ {
3246
+ isKind: isSubjectEntry,
3247
+ message: name => `effect "${name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
3248
+ }, {
3249
+ isKind: isDueDateEntry,
3250
+ message: name => `effect "${name}" declares a due-date output shape — a due-* kind marks THE deadline of a level, and no deadline reader looks at effect outputs. Declare \`date\` or \`datetime\` for a dated output`
3251
+ } ];
3252
+
3253
+ function pushOutputIssues(args) {
3177
3254
  const {action: action, path: path, issues: issues} = args;
3178
3255
  for (const [e, effect] of (action.effects ?? []).entries()) {
3179
3256
  const base = [ ...path, "effects", e, "outputs" ];
3180
- for (const nestedPath of nestedSubjectPaths(effect.outputs, base)) issues.push({
3257
+ for (const {isKind: isKind, message: message} of LEVEL_KIND_OUTPUT_RULES) for (const nestedPath of nestedKindPaths({
3258
+ shapes: effect.outputs,
3259
+ base: base,
3260
+ isKind: isKind
3261
+ })) issues.push({
3181
3262
  path: nestedPath,
3182
- message: `effect "${effect.name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
3263
+ message: message(effect.name)
3183
3264
  });
3184
3265
  }
3185
3266
  }
@@ -3197,13 +3278,14 @@ function checkSubjectEntries(def, issues) {
3197
3278
  path: [ ...path, n ],
3198
3279
  message: "at most one subject-kind field entry per workflow — the runtime identifies THE subject by kind, and a second one makes it ambiguous"
3199
3280
  });
3200
- for (const [n, entry] of (entries ?? []).entries()) {
3201
- const nested = [ ...nestedSubjectPaths(entry.fields, [ ...path, n, "fields" ]), ...nestedSubjectPaths(entry.of, [ ...path, n, "of" ]) ];
3202
- for (const nestedPath of nested) issues.push({
3203
- path: nestedPath,
3204
- message: `${label} entry "${entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
3205
- });
3206
- }
3281
+ for (const site of belowScopeNestedSites({
3282
+ entries: entries,
3283
+ path: path,
3284
+ isKind: isSubjectEntry
3285
+ })) issues.push({
3286
+ path: site.path,
3287
+ message: `${label} entry "${site.entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
3288
+ });
3207
3289
  }
3208
3290
  }
3209
3291
 
@@ -3839,7 +3921,9 @@ const SCALAR = {
3839
3921
  progress: () => SCALAR,
3840
3922
  boolean: () => SCALAR,
3841
3923
  date: () => SCALAR,
3924
+ dueDate: () => SCALAR,
3842
3925
  datetime: () => SCALAR,
3926
+ dueDatetime: () => SCALAR,
3843
3927
  url: () => SCALAR,
3844
3928
  actor: () => ACTOR_VALUE,
3845
3929
  assignee: () => ASSIGNEE_VALUE,
@@ -3930,10 +4014,10 @@ function checkWorkflowInvariants(def) {
3930
4014
  checkRequiredField(def, issues), checkStart(def, issues), checkPredicates(def, issues),
3931
4015
  checkUnboundConditionVars(def, issues), checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues),
3932
4016
  checkFieldReadOpValues(def, issues), checkUpdateWhereOps(def, issues), checkGuardFieldReads(def, issues),
3933
- checkAssigneesEntries(def, issues), checkSubjectEntries(def, issues), checkSubjectEffectOutputs(def, issues),
3934
- checkActivityTerminalPaths(def, issues), checkTerminalStageActivities(def, issues),
3935
- checkTriggeredActionParams(def, issues), checkStoredRolesPlacement(def, issues),
3936
- checkGroups(def, issues), issues;
4017
+ checkAssigneesEntries(def, issues), checkDueDateEntries(def, issues), checkSubjectEntries(def, issues),
4018
+ checkLevelKindEffectOutputs(def, issues), checkActivityTerminalPaths(def, issues),
4019
+ checkTerminalStageActivities(def, issues), checkTriggeredActionParams(def, issues),
4020
+ checkStoredRolesPlacement(def, issues), checkGroups(def, issues), issues;
3937
4021
  }
3938
4022
 
3939
- export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_STATUSES, ACTOR_KINDS, ANONYMOUS_IDENTITY, ActorShape, AuthoringActionSchema, AuthoringActivitySchema, AuthoringFieldEntrySchema, AuthoringGuardSchema, AuthoringOpSchema, AuthoringStageSchema, AuthoringTransitionSchema, AuthoringWorkflowSchema, CALLER_BOUND_VARS, CONDITION_VARS, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, DOCUMENT_VALUE_PERMISSIONS, DRIVER_KINDS, DefinitionInUseError, DefinitionNotFoundError, EFFECTS_READ, EXECUTOR_CLASSIFICATIONS, EffectNotFoundError, EffectSchema, FIELD_READ, FIELD_SCOPES, FIELD_VALUE_KINDS, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GUARD_PREDICATE_VARS, GdrShape, GroupSchema, InstanceNotFoundError, IsoTimestamp, MUTATION_GUARD_ACTIONS, ModelVersionAheadError, NonEmptyString, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, RESOURCE_ALIAS_NAME_SOURCE, ReaderModelAcknowledgementError, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StoredFieldOpSchema, VersionSpecificDatasetGdrError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowConfigSchema, WorkflowError, actorFulfillsRole, andConditions, assertReadableModel, assertReaderModelAcknowledgement, checkWorkflowInvariants, choiceValueIssues, classifyPrincipalId, clientConfigFromResource, conditionEffectReads, conditionFieldReadNames, conditionParameterNames, conditionSyntaxIssues, datasetResourceParts, definitionDocId, deriveActivityKind, deriveExecutorClassification, desugarWorkflow, driverKind, errorMessage, evaluateCondition, evaluateConditionOutcome, evaluatePredicates, extractDocumentId, fieldTreeShape, fieldValueSchemas, formatIssuePath, formatIssues, formatValidationError, gdrFromResource, gdrRef, gdrResourcePrefix, gdrUri, groq, groupMembershipNames, isBareSeedId, isCascadeFired, isGdr, isGdrUri, isGuardReadExpr, isInputSourced, isNotesEntry, isParseableInstant, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTerminalActivityStatus, isTodoListEntry, isTodoListItem, isUnevaluable, isUnprimed, labelFor, lakePrincipalId, minReaderModelOf, modelStampFor, modelVersionOf, parentRef, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseFieldValue, parseGdr, parseOrThrow, parsePersistedDoc, parseResourceGdr, parseStoredDefinition, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refTypeIssues, rejectedRefTypes, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, resourceFromGdrUri, resourceFromParsed, resourceGdr, rethrowWithContext, runGroq, sameResource, scalarValidationIssues, schemaTreeShape, selfGdr, startKindOf, tagScopeFilter, terminalState, toBareId, toPhysicalGdr, tolerantEntries, tolerantObject, tryParseGdr, validateFieldAppendItem, validateFieldValue, validateResourceAliasName, validateTag };
4023
+ export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_STATUSES, ACTOR_KINDS, ANONYMOUS_IDENTITY, ActorShape, AuthoringActionSchema, AuthoringActivitySchema, AuthoringFieldEntrySchema, AuthoringGuardSchema, AuthoringOpSchema, AuthoringStageSchema, AuthoringTransitionSchema, AuthoringWorkflowSchema, CALLER_BOUND_VARS, CONDITION_VARS, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, DOCUMENT_VALUE_PERMISSIONS, DRIVER_KINDS, DefinitionInUseError, DefinitionNotFoundError, EFFECTS_READ, EXECUTOR_CLASSIFICATIONS, EffectNotFoundError, EffectSchema, FIELD_READ, FIELD_SCOPES, FIELD_VALUE_KINDS, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GUARD_PREDICATE_VARS, GdrShape, GroupSchema, InstanceNotFoundError, IsoTimestamp, MUTATION_GUARD_ACTIONS, ModelVersionAheadError, NonEmptyString, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, RESOURCE_ALIAS_NAME_SOURCE, ReaderModelAcknowledgementError, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StoredFieldOpSchema, VersionSpecificDatasetGdrError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowConfigSchema, WorkflowError, actorFulfillsRole, andConditions, assertReadableModel, assertReaderModelAcknowledgement, checkWorkflowInvariants, choiceValueIssues, classifyPrincipalId, clientConfigFromResource, conditionEffectReads, conditionFieldReadNames, conditionParameterNames, conditionSyntaxIssues, datasetResourceParts, definitionDocId, deriveActivityKind, deriveExecutorClassification, desugarWorkflow, directoryBridgeId, driverKind, errorMessage, evaluateCondition, evaluateConditionOutcome, evaluatePredicates, extractDocumentId, fieldTreeShape, fieldValueSchemas, firstCarriedGlobalId, formatIssuePath, formatIssues, formatValidationError, gdrFromResource, gdrRef, gdrResourcePrefix, gdrUri, groq, groupMembershipNames, isBareSeedId, isCascadeFired, isGdr, isGdrUri, isGuardReadExpr, isInputSourced, isNotesEntry, isParseableInstant, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTerminalActivityStatus, isTodoListEntry, isTodoListItem, isUnevaluable, isUnprimed, labelFor, lakePrincipalId, minReaderModelOf, modelStampFor, modelVersionOf, parentRef, parseDefinitionSnapshot, parseDefinitionSnapshotValue, parseFieldValue, parseGdr, parseOrThrow, parsePersistedDoc, parseResourceGdr, parseStoredDefinition, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refTypeIssues, rejectedRefTypes, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, resourceFromGdrUri, resourceFromParsed, resourceGdr, rethrowWithContext, runGroq, sameResource, scalarValidationIssues, schemaTreeShape, selfGdr, startKindOf, tagScopeFilter, terminalState, toBareId, toPhysicalGdr, tolerantEntries, tolerantObject, tryParseGdr, validateFieldAppendItem, validateFieldValue, validateResourceAliasName, validateTag };
package/dist/define.d.cts CHANGED
@@ -1148,7 +1148,9 @@ declare const FIELD_VALUE_KINDS: readonly [
1148
1148
  "progress",
1149
1149
  "boolean",
1150
1150
  "date",
1151
+ "dueDate",
1151
1152
  "datetime",
1153
+ "dueDatetime",
1152
1154
  "url",
1153
1155
  "actor",
1154
1156
  "assignee",
@@ -1879,6 +1881,10 @@ declare type TerminalActivityStatus =
1879
1881
  * `todoList` — ad-hoc, status-tracked work items. Sugar over `array of object
1880
1882
  * { label, status, assignee?, dueDate? }`; a plain checklist is this used with
1881
1883
  * `{label, status}` only (open ↔ done). Never a stored kind.
1884
+ *
1885
+ * The `dueDate` column is a `date` NAMED `dueDate`, not the {@link
1886
+ * FieldValueMap.dueDate} kind — that kind reserves one deadline slot per level,
1887
+ * and a repeating row has nothing to reserve.
1882
1888
  */
1883
1889
  declare type TodoListField = FieldBase<AuthoringEditable, GroupMembership> & {
1884
1890
  type: "todoList";