@sanity/workflow-engine 0.13.0 → 0.15.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.
@@ -0,0 +1,2461 @@
1
+ "use strict";
2
+
3
+ var v = require("valibot"), groqConditionDescribe = require("@sanity/groq-condition-describe"), groqJs = require("groq-js");
4
+
5
+ function _interopNamespaceCompat(e) {
6
+ if (e && typeof e == "object" && "default" in e) return e;
7
+ var n = /* @__PURE__ */ Object.create(null);
8
+ return e && Object.keys(e).forEach(function(k) {
9
+ if (k !== "default") {
10
+ var d = Object.getOwnPropertyDescriptor(e, k);
11
+ Object.defineProperty(n, k, d.get ? d : {
12
+ enumerable: !0,
13
+ get: function() {
14
+ return e[k];
15
+ }
16
+ });
17
+ }
18
+ }), n.default = e, Object.freeze(n);
19
+ }
20
+
21
+ var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
22
+
23
+ function errorMessage(err) {
24
+ return (err instanceof Error ? err.message : String(err)).replace(/[^\P{Cc}\n\t]/gu, "");
25
+ }
26
+
27
+ function rethrowWithContext(err, context) {
28
+ throw new Error(`${context}: ${errorMessage(err)}`, {
29
+ cause: err
30
+ });
31
+ }
32
+
33
+ function andConditions(parts) {
34
+ const present = parts.filter(p => p !== void 0);
35
+ if (present.length !== 0) return present.length === 1 ? present[0] : present.map(p => `(${p})`).join(" && ");
36
+ }
37
+
38
+ const KNOWN_SCHEMES = /* @__PURE__ */ new Set([ "dataset", "canvas", "media-library", "dashboard" ]), KNOWN_SCHEMES_TEXT = [ ...KNOWN_SCHEMES ].join(", ");
39
+
40
+ function parseGdr(uri) {
41
+ const colon = uri.indexOf(":");
42
+ if (colon < 0) throw new Error(`Invalid GDR "${uri}": must be a URI of form "<scheme>:<...id-parts>". Known schemes: ${KNOWN_SCHEMES_TEXT}.`);
43
+ const scheme = uri.slice(0, colon), rest = uri.slice(colon + 1);
44
+ if (!KNOWN_SCHEMES.has(scheme)) throw new Error(`Invalid GDR "${uri}": unknown scheme "${scheme}". Known: ${KNOWN_SCHEMES_TEXT}.`);
45
+ const parts = rest.split(":");
46
+ if (parts.some(part => part.length === 0)) throw new Error(`Invalid GDR "${uri}": id parts must be non-empty (no leading, trailing, or doubled ":").`);
47
+ if (scheme === "dataset") {
48
+ if (parts.length !== 3) throw new Error(`Invalid GDR "${uri}": dataset scheme requires <projectId>:<dataset>:<documentId> (3 parts after scheme); got ${parts.length}.`);
49
+ return {
50
+ scheme: "dataset",
51
+ projectId: parts[0],
52
+ dataset: parts[1],
53
+ documentId: parts[2]
54
+ };
55
+ }
56
+ if (parts.length !== 2) throw new Error(`Invalid GDR "${uri}": ${scheme} scheme requires <resourceId>:<documentId> (2 parts after scheme); got ${parts.length}.`);
57
+ return {
58
+ scheme: scheme,
59
+ resourceId: parts[0],
60
+ documentId: parts[1]
61
+ };
62
+ }
63
+
64
+ function tryParseGdr(uri) {
65
+ try {
66
+ return parseGdr(uri);
67
+ } catch {
68
+ return;
69
+ }
70
+ }
71
+
72
+ function gdrUri(parts) {
73
+ return parts.scheme === "dataset" ? `dataset:${parts.projectId}:${parts.dataset}:${parts.documentId}` : `${parts.scheme}:${parts.resourceId}:${parts.documentId}`;
74
+ }
75
+
76
+ function extractDocumentId(gdrUriString) {
77
+ return parseGdr(gdrUriString).documentId;
78
+ }
79
+
80
+ const RESOURCE_ALIAS_NAME_SOURCE = "[a-z0-9][a-z0-9-]*", RESOURCE_ALIAS_NAME_RE = new RegExp(`^${RESOURCE_ALIAS_NAME_SOURCE}$`);
81
+
82
+ function validateResourceAliasName(name) {
83
+ if (!RESOURCE_ALIAS_NAME_RE.test(name)) throw new Error(`Invalid resource alias name "${name}": expected lowercase letters, digits, and dashes (no leading dash).`);
84
+ }
85
+
86
+ function toPhysicalGdr(id, home) {
87
+ return isGdrUri(id) ? id : gdrFromResource(home, id);
88
+ }
89
+
90
+ function refDataset({projectId: projectId, dataset: dataset, documentId: documentId, type: type}) {
91
+ return {
92
+ id: gdrUri({
93
+ scheme: "dataset",
94
+ projectId: projectId,
95
+ dataset: dataset,
96
+ documentId: documentId
97
+ }),
98
+ type: type
99
+ };
100
+ }
101
+
102
+ function refCanvas({resourceId: resourceId, documentId: documentId, type: type}) {
103
+ return {
104
+ id: gdrUri({
105
+ scheme: "canvas",
106
+ resourceId: resourceId,
107
+ documentId: documentId
108
+ }),
109
+ type: type
110
+ };
111
+ }
112
+
113
+ function refMediaLibrary({resourceId: resourceId, documentId: documentId, type: type}) {
114
+ return {
115
+ id: gdrUri({
116
+ scheme: "media-library",
117
+ resourceId: resourceId,
118
+ documentId: documentId
119
+ }),
120
+ type: type
121
+ };
122
+ }
123
+
124
+ function refDashboard({resourceId: resourceId, documentId: documentId, type: type}) {
125
+ return {
126
+ id: gdrUri({
127
+ scheme: "dashboard",
128
+ resourceId: resourceId,
129
+ documentId: documentId
130
+ }),
131
+ type: type
132
+ };
133
+ }
134
+
135
+ function datasetResourceParts(id) {
136
+ const dot = id.indexOf(".");
137
+ if (dot <= 0 || dot === id.length - 1) throw new Error(`Invalid dataset resource id "${id}": expected "<projectId>.<dataset>".`);
138
+ return {
139
+ projectId: id.slice(0, dot),
140
+ dataset: id.slice(dot + 1)
141
+ };
142
+ }
143
+
144
+ function clientConfigFromResource(res) {
145
+ return res.type === "dataset" ? datasetResourceParts(res.id) : {
146
+ resource: res
147
+ };
148
+ }
149
+
150
+ function gdrFromResource(res, documentId) {
151
+ if (res.type === "dataset") {
152
+ const {projectId: projectId, dataset: dataset} = datasetResourceParts(res.id);
153
+ return gdrUri({
154
+ scheme: "dataset",
155
+ projectId: projectId,
156
+ dataset: dataset,
157
+ documentId: documentId
158
+ });
159
+ }
160
+ return gdrUri({
161
+ scheme: res.type,
162
+ resourceId: res.id,
163
+ documentId: documentId
164
+ });
165
+ }
166
+
167
+ function resourceGdr(res) {
168
+ return `${res.type}:${res.id}`;
169
+ }
170
+
171
+ function parseResourceGdr(uri) {
172
+ const expected = 'expected "<type>:<id>" with no document part, e.g. "dataset:<projectId>.<dataset>" or "media-library:<resourceId>"', parts = uri.split(":");
173
+ if (parts.length !== 2 || parts.some(part => part.length === 0)) throw new Error(`Invalid resource GDR "${uri}": ${expected}.`);
174
+ const [type, id] = parts;
175
+ if (!KNOWN_SCHEMES.has(type)) throw new Error(`Invalid resource GDR "${uri}": unknown resource type "${type}". Known: ${KNOWN_SCHEMES_TEXT}.`);
176
+ return type === "dataset" && datasetResourceParts(id), {
177
+ type: type,
178
+ id: id
179
+ };
180
+ }
181
+
182
+ function gdrResourcePrefix(res) {
183
+ const full = gdrFromResource(res, "x");
184
+ return full.slice(0, full.length - 1);
185
+ }
186
+
187
+ function resourceFromParsed(parsed) {
188
+ return parsed.scheme === "dataset" ? {
189
+ type: "dataset",
190
+ id: `${parsed.projectId}.${parsed.dataset}`
191
+ } : {
192
+ type: parsed.scheme,
193
+ id: parsed.resourceId ?? ""
194
+ };
195
+ }
196
+
197
+ function resourceFromGdrUri(uri) {
198
+ const parsed = tryParseGdr(uri);
199
+ return parsed === void 0 ? void 0 : resourceFromParsed(parsed);
200
+ }
201
+
202
+ function sameResource(a, b) {
203
+ return a.type === b.type && a.id === b.id;
204
+ }
205
+
206
+ function selfGdr(doc) {
207
+ return gdrFromResource(doc.workflowResource, doc._id);
208
+ }
209
+
210
+ function definitionDocId({tag: tag, definition: definition, version: version}) {
211
+ return `${tag}.${definition}.v${version}`;
212
+ }
213
+
214
+ function isGdrUri(value) {
215
+ return typeof value == "string" && tryParseGdr(value) !== void 0;
216
+ }
217
+
218
+ function toBareId(id) {
219
+ return isGdrUri(id) ? extractDocumentId(id) : id;
220
+ }
221
+
222
+ function gdrRef({res: res, documentId: documentId, type: type}) {
223
+ return {
224
+ id: gdrFromResource(res, documentId),
225
+ type: type
226
+ };
227
+ }
228
+
229
+ function isGdr(value) {
230
+ return typeof value == "object" && value !== null && typeof value.id == "string" && typeof value.type == "string";
231
+ }
232
+
233
+ class WorkflowError extends Error {
234
+ kind;
235
+ constructor(kind, message, options) {
236
+ super(message, options), this.kind = kind;
237
+ }
238
+ }
239
+
240
+ class ContractViolationError extends WorkflowError {
241
+ constructor(message) {
242
+ super("contract-violation", message), this.name = "ContractViolationError";
243
+ }
244
+ }
245
+
246
+ class InstanceNotFoundError extends WorkflowError {
247
+ instanceId;
248
+ constructor(args) {
249
+ super("instance-not-found", `Workflow instance ${args.instanceId} not found${args.detail ? ` (${args.detail})` : ""}`),
250
+ this.name = "InstanceNotFoundError", this.instanceId = args.instanceId;
251
+ }
252
+ }
253
+
254
+ class DefinitionNotFoundError extends WorkflowError {
255
+ definition;
256
+ version;
257
+ constructor(args) {
258
+ super("definition-not-found", args.version !== void 0 ? `Workflow definition ${args.definition} v${args.version} not deployed` : `Workflow definition ${args.definition} has no deployed versions`),
259
+ this.name = "DefinitionNotFoundError", this.definition = args.definition, args.version !== void 0 && (this.version = args.version);
260
+ }
261
+ }
262
+
263
+ class DefinitionInUseError extends WorkflowError {
264
+ definition;
265
+ blockedBy;
266
+ constructor(args) {
267
+ super("definition-in-use", definitionInUseMessage(args.definition, args.blockedBy)),
268
+ this.name = "DefinitionInUseError", this.definition = args.definition, this.blockedBy = args.blockedBy;
269
+ }
270
+ }
271
+
272
+ function definitionInUseMessage(definition, blockedBy) {
273
+ if (blockedBy.reason === "non-terminal-instances") {
274
+ const head = blockedBy.instanceIds.slice(0, 3).join(", "), preview = blockedBy.instanceIds.length > 3 ? `${head}, …` : head;
275
+ return `Cannot delete ${definition}: ${blockedBy.instanceIds.length} non-terminal instance(s) exist (${preview}). Pass cascade to abort them first — instances are aborted in place, never deleted.`;
276
+ }
277
+ const names = blockedBy.referrers.map(r => `${r.definition} v${r.version}`).join(", ");
278
+ return `Cannot delete ${definition}: still spawn-referenced by deployed definition(s) ${names}. Delete or redeploy the referrer(s) first.`;
279
+ }
280
+
281
+ class EffectNotFoundError extends WorkflowError {
282
+ instanceId;
283
+ effectKey;
284
+ settled;
285
+ constructor(args) {
286
+ super("effect-not-found", effectNotFoundMessage(args)), this.name = "EffectNotFoundError",
287
+ this.instanceId = args.instanceId, this.effectKey = args.effectKey, args.settled !== void 0 && (this.settled = args.settled);
288
+ }
289
+ }
290
+
291
+ function effectNotFoundMessage(args) {
292
+ const base = `Pending effect "${args.effectKey}" not found on instance ${args.instanceId}`;
293
+ if (args.settled === void 0) return base;
294
+ const cause = args.settled.detail !== void 0 ? ` (${args.settled.detail})` : "";
295
+ return args.settled.status === "cancelled" ? `${base} — it was cancelled at ${args.settled.ranAt}${cause}` : `${base} — it already settled "${args.settled.status}" at ${args.settled.ranAt}${cause}`;
296
+ }
297
+
298
+ const TAG_RE = /^[a-z0-9][a-z0-9-]*$/;
299
+
300
+ function validateTag(tag) {
301
+ if (!TAG_RE.test(tag)) throw new ContractViolationError(`tag: invalid tag "${tag}" — must match ${TAG_RE.source} (ASCII lowercase + digits + dashes, no leading dash, no dots)`);
302
+ }
303
+
304
+ function tagScopeFilter() {
305
+ return "tag == $tag";
306
+ }
307
+
308
+ const NonEmptyString = v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("must not be empty"));
309
+
310
+ function asPredicate(validate) {
311
+ return value => {
312
+ try {
313
+ return validate(value), !0;
314
+ } catch {
315
+ return !1;
316
+ }
317
+ };
318
+ }
319
+
320
+ const isValidTag = asPredicate(validateTag), isValidAliasName = asPredicate(validateResourceAliasName), isValidDatasetId = asPredicate(datasetResourceParts), WorkflowResourceSchema = v__namespace.variant("type", [ v__namespace.object({
321
+ type: v__namespace.literal("dataset"),
322
+ id: v__namespace.pipe(NonEmptyString, v__namespace.check(isValidDatasetId, 'invalid dataset resource id — expected "<projectId>.<dataset>"'))
323
+ }), v__namespace.object({
324
+ type: v__namespace.literal("canvas"),
325
+ id: NonEmptyString
326
+ }), v__namespace.object({
327
+ type: v__namespace.literal("media-library"),
328
+ id: NonEmptyString
329
+ }), v__namespace.object({
330
+ type: v__namespace.literal("dashboard"),
331
+ id: NonEmptyString
332
+ }) ]), ResourceBindingSchema = v__namespace.object({
333
+ name: v__namespace.pipe(NonEmptyString, v__namespace.check(isValidAliasName, "invalid resource handle name — lowercase letters, digits and dashes only, no leading dash")),
334
+ resource: WorkflowResourceSchema
335
+ }), DefinitionSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.name == "string", "expected a workflow definition (an object with a string `name`)"), DeploymentSchema = v__namespace.object({
336
+ name: NonEmptyString,
337
+ tag: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty(), v__namespace.check(isValidTag, "invalid tag — lowercase letters, digits and dashes only, no leading dash, no dots")),
338
+ workflowResource: WorkflowResourceSchema,
339
+ resourceAliases: v__namespace.optional(v__namespace.pipe(v__namespace.array(ResourceBindingSchema), v__namespace.check(bindings => new Set(bindings.map(binding => binding.name)).size === bindings.length, "duplicate resource handle name — each binding name must be unique within a deployment"))),
340
+ definitions: v__namespace.pipe(v__namespace.array(DefinitionSchema), v__namespace.minLength(1, "a deployment needs at least one definition"))
341
+ }), TelemetryLoggerSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.log == "function", "expected a telemetry logger (an object with a `log` function)"), WorkflowConfigSchema = v__namespace.object({
342
+ deployments: v__namespace.pipe(v__namespace.array(DeploymentSchema), v__namespace.minLength(1, "a config needs at least one deployment"), v__namespace.check(deployments => new Set(deployments.map(deployment => deployment.tag)).size === deployments.length, "duplicate deployment tag — each deployment must use a unique tag")),
343
+ telemetry: v__namespace.optional(TelemetryLoggerSchema)
344
+ });
345
+
346
+ function resourceAliasesToMap(resourceAliases) {
347
+ return Object.fromEntries((resourceAliases ?? []).map(binding => [ binding.name, binding.resource ]));
348
+ }
349
+
350
+ const FIELD_READ = /^\$fields\.(\w+)(?:\.(.+))?$/, EFFECTS_READ = /^\$effects\['([^']+)'\](?:\.(.+))?$/;
351
+
352
+ function isGuardReadExpr(expr) {
353
+ return expr === "$self" || expr === "$now" || FIELD_READ.test(expr) || EFFECTS_READ.test(expr);
354
+ }
355
+
356
+ function printGuardRead(read) {
357
+ switch (read.type) {
358
+ case "self":
359
+ return "$self";
360
+
361
+ case "now":
362
+ return "$now";
363
+
364
+ case "fieldRead":
365
+ return read.path === void 0 ? `$fields.${read.field}` : `$fields.${read.field}.${read.path}`;
366
+
367
+ case "effectsRead":
368
+ return read.path === void 0 ? `$effects['${read.effect}']` : `$effects['${read.effect}'].${read.path}`;
369
+ }
370
+ }
371
+
372
+ const UNIVERSAL_ROLE_ALIAS_KEY = "$all";
373
+
374
+ function normalizeRoleAliases(aliases) {
375
+ if (aliases === void 0 || !("*" in aliases)) return aliases;
376
+ const {["*"]: universal, ...perRole} = aliases;
377
+ return {
378
+ ...perRole,
379
+ [UNIVERSAL_ROLE_ALIAS_KEY]: universal
380
+ };
381
+ }
382
+
383
+ function expandRequiredRoles(required, aliases) {
384
+ if (aliases === void 0) return [ ...required ];
385
+ const out = /* @__PURE__ */ new Set;
386
+ for (const role of required) {
387
+ out.add(role);
388
+ for (const fulfiller of aliases[role] ?? []) out.add(fulfiller);
389
+ }
390
+ for (const fulfiller of aliases[UNIVERSAL_ROLE_ALIAS_KEY] ?? []) out.add(fulfiller);
391
+ return [ ...out ];
392
+ }
393
+
394
+ function actorFulfillsRole({actorRoles: actorRoles, required: required, aliases: aliases}) {
395
+ if (actorRoles === void 0 || actorRoles.length === 0) return !1;
396
+ const accepted = new Set(expandRequiredRoles([ required ], aliases));
397
+ return actorRoles.some(role => accepted.has(role));
398
+ }
399
+
400
+ function isUnevaluable(result) {
401
+ return result == null;
402
+ }
403
+
404
+ async function evaluateConditionOutcome(args) {
405
+ const {condition: condition, snapshot: snapshot, params: params} = args;
406
+ return groqConditionDescribe.evaluateConditionOutcome({
407
+ condition: condition,
408
+ params: params,
409
+ dataset: snapshot.docs
410
+ });
411
+ }
412
+
413
+ async function evaluateCondition(args) {
414
+ return await evaluateConditionOutcome(args) === "satisfied";
415
+ }
416
+
417
+ async function evaluatePredicates(args) {
418
+ const out = {};
419
+ for (const [name, groq] of Object.entries(args.predicates ?? {})) {
420
+ const result = await runGroq({
421
+ groq: groq,
422
+ params: args.params,
423
+ snapshot: args.snapshot
424
+ }), outcome = groqConditionDescribe.conditionOutcome(result);
425
+ out[name] = outcome === "unevaluable" ? null : outcome === "satisfied";
426
+ }
427
+ return out;
428
+ }
429
+
430
+ async function runGroq({groq: groq, params: params, snapshot: snapshot}) {
431
+ return groqConditionDescribe.runGroq({
432
+ groq: groq,
433
+ params: params,
434
+ dataset: snapshot.docs
435
+ });
436
+ }
437
+
438
+ function conditionSyntaxIssues(groq, boundVars) {
439
+ const issues = [];
440
+ let tree;
441
+ try {
442
+ tree = groqJs.parse(groq);
443
+ } catch (err) {
444
+ issues.push(errorMessage(err));
445
+ }
446
+ if (/\*\s*\[\s*_type\b/.test(groq) && issues.push('condition scans by `_type` — that\'s a discovery query, not a predicate. Conditions evaluate against the in-memory snapshot (instance + ancestors + field-declared docs). To bring extra docs in scope, declare a `doc.ref` (or `doc.refs`) field entry on the workflow or this stage. For lake scans like "all articles in this release", use `subworkflows.forEach` instead.'),
447
+ boundVars !== void 0 && tree !== void 0) for (const name of conditionParameterNames(groq)) boundVars.includes(name) || issues.push(`reads $${name}, which this scope does not bind — an unbound variable evaluates to GROQ null, so the condition silently never matches. Bound here: ` + boundVars.map(n => `$${n}`).join(", "));
448
+ return issues;
449
+ }
450
+
451
+ function conditionParameterNames(groq) {
452
+ const read = /* @__PURE__ */ new Set;
453
+ return walkAstNodes(tryParseGroq(groq), node => {
454
+ node.type === "Parameter" && typeof node.name == "string" && read.add(node.name);
455
+ }), read;
456
+ }
457
+
458
+ function conditionFieldReadNames(groq) {
459
+ const read = /* @__PURE__ */ new Set;
460
+ return walkAstNodes(tryParseGroq(groq), node => {
461
+ if (node.type !== "AccessAttribute" || typeof node.name != "string") return;
462
+ const base = node.base;
463
+ base?.type === "Parameter" && base.name === "fields" && read.add(node.name);
464
+ }), read;
465
+ }
466
+
467
+ function conditionEffectReads(groq) {
468
+ const reads = [];
469
+ return walkAstNodes(tryParseGroq(groq), node => {
470
+ if (node.type !== "AccessAttribute" || typeof node.name != "string") return;
471
+ const base = node.base;
472
+ base?.type !== "AccessAttribute" || typeof base.name != "string" || base.base?.type === "Parameter" && base.base.name === "effects" && reads.push({
473
+ effect: base.name,
474
+ key: node.name
475
+ });
476
+ }), reads;
477
+ }
478
+
479
+ function tryParseGroq(groq) {
480
+ try {
481
+ return groqJs.parse(groq);
482
+ } catch {
483
+ return;
484
+ }
485
+ }
486
+
487
+ function walkAstNodes(node, visit) {
488
+ if (Array.isArray(node)) {
489
+ for (const item of node) walkAstNodes(item, visit);
490
+ return;
491
+ }
492
+ if (!(typeof node != "object" || node === null)) {
493
+ visit(node);
494
+ for (const value of Object.values(node)) walkAstNodes(value, visit);
495
+ }
496
+ }
497
+
498
+ const CONDITION_VARS = [ {
499
+ name: "self",
500
+ binding: "always",
501
+ label: "this workflow instance",
502
+ description: "GDR URI of the instance document itself — `*[_id == $self][0]` reads the instance in the snapshot."
503
+ }, {
504
+ name: "fields",
505
+ binding: "always",
506
+ label: "the workflow's fields",
507
+ description: "Declared field entries rendered by name (`$fields.<name>` is the value, no envelope). Stage/activity scopes overlay lexically; `doc.ref` values render the hydrated document when the snapshot holds it."
508
+ }, {
509
+ name: "parent",
510
+ binding: "always",
511
+ label: "the parent workflow",
512
+ description: "The parent instance's GDR URI, `null` on a root instance."
513
+ }, {
514
+ name: "ancestors",
515
+ binding: "always",
516
+ label: "the workflow's ancestors",
517
+ description: "GDR URIs of the ancestor chain, root first."
518
+ }, {
519
+ name: "stage",
520
+ binding: "always",
521
+ label: "the current stage",
522
+ description: "The current stage's name."
523
+ }, {
524
+ name: "now",
525
+ binding: "always",
526
+ label: "the current time",
527
+ description: "The ISO clock reading shared by every condition in one evaluation pass, so they agree on the time."
528
+ }, {
529
+ name: "effects",
530
+ binding: "always",
531
+ label: "automation outputs",
532
+ description: "The `effectsContext` map: stable handler params seeded at start plus completed effects' outputs namespaced by effect name (`$effects['<effect>'].<output>`). Handler fuel — transition filters should read instance/lake state (or $effectStatus) instead."
533
+ }, {
534
+ name: "effectStatus",
535
+ binding: "always",
536
+ label: "automation status",
537
+ description: "Effect name → `'done'` | `'failed'` of the latest completed run queued during the current stage entry; absent until the effect drains for this entry. Re-entry-safe: runs queued under a prior entry never count, so `$effectStatus['<effect>'] == 'done'` (or `defined($effectStatus['<effect>'])` for settled-either-way) waits for the fresh run."
538
+ }, {
539
+ name: "activities",
540
+ binding: "always",
541
+ label: "this stage's activities",
542
+ description: "The current stage's activity rows, statuses included."
543
+ }, {
544
+ name: "allActivitiesDone",
545
+ binding: "always",
546
+ label: "all activities in this stage are finished",
547
+ description: "Every current-stage activity is `done` or `skipped` — the default transition gate."
548
+ }, {
549
+ name: "anyActivityFailed",
550
+ binding: "always",
551
+ label: "an activity in this stage has failed",
552
+ description: "Some current-stage activity is `failed`."
553
+ }, {
554
+ name: "actor",
555
+ binding: "caller",
556
+ label: "you",
557
+ description: "The acting identity (id + roles); `undefined` when no caller rides the evaluation. Never holds a value in the cascade gates (deploy-rejected there)."
558
+ }, {
559
+ name: "assigned",
560
+ binding: "caller",
561
+ label: "you are assigned to this activity",
562
+ description: "Whether the caller matches the activity's assignees-kind field entry (by user id, or by a role under the definition's `roleAliases`); `false` outside an activity context. Constant `false` in the cascade gates (deploy-rejected there)."
563
+ }, {
564
+ name: "can",
565
+ binding: "caller",
566
+ label: "your permissions",
567
+ description: "Advisory per-permission booleans computed from the caller's grants; `undefined` without grants. Bound wherever grants ride the evaluation: the projection's rendered scope (action filters, activity requirements, editability predicates) and the fireAction/editField commit gates. Deploy rejects it at every site that evaluates without grants: transition filters, activity `filter`/`completeWhen`/`failWhen`, effect bindings, where-op `where`s, and the subworkflow `forEach`/`with`/`context` sites."
568
+ }, {
569
+ name: "row",
570
+ binding: "spawn",
571
+ label: "the spawned row",
572
+ description: "One `subworkflows.forEach` result row, bound while its `with` map evaluates — and the row under test while a where-op `where` evaluates (per row)."
573
+ }, {
574
+ name: "params",
575
+ binding: "caller",
576
+ label: "the action's arguments",
577
+ description: "The firing action's args — they hold values only while that action's effect bindings and where-op `where`s evaluate (activity/transition boundaries bind `{}`; subworkflow sites don't bind it at all). Deploy rejects a read in the cascade gates and in the caller-bound projection (action filters, requirements, editable predicates): args exist only once the caller fires the action, after those sites have evaluated."
578
+ }, {
579
+ name: "subworkflows",
580
+ binding: "always",
581
+ label: "the spawned subworkflows",
582
+ description: "Every row of the instance's subworkflow registry, faceted by `activity`/`definition`/`rowKey`/`status` (`'active'|'done'|'aborted'`) with `current` marking the open stage entry's cohort and `stage` the child's current stage. Usable anywhere — transition filters, requirements, any stage's gates; the implicit spawn gate is `count($subworkflows[activity == <name> && current && status == 'active']) == 0`."
583
+ } ], RESERVED_CONDITION_VARS = CONDITION_VARS.map(v2 => v2.name), FILTER_SCOPE_VARS = CONDITION_VARS.filter(v2 => v2.binding === "always").map(v2 => v2.name), CALLER_BOUND_VARS = CONDITION_VARS.filter(v2 => v2.binding === "caller").map(v2 => v2.name), GUARD_PREDICATE_VARS = [ {
584
+ name: "guard",
585
+ description: "The guard document itself (its `metadata` carries deploy-time resolved values)."
586
+ }, {
587
+ name: "mutation",
588
+ description: "The attempted mutation — `mutation.action` is the write kind being gated."
589
+ } ], ACTOR_KINDS = [ "person", "agent", "system" ];
590
+
591
+ function releaseDocId(releaseName) {
592
+ return `_.releases.${releaseName}`;
593
+ }
594
+
595
+ function releaseRef({res: res, releaseName: releaseName}) {
596
+ if (releaseName.length === 0) throw new ContractViolationError("releaseRef: releaseName must be a non-empty release name");
597
+ return {
598
+ id: gdrFromResource(res, releaseDocId(releaseName)),
599
+ type: "system.release",
600
+ releaseName: releaseName
601
+ };
602
+ }
603
+
604
+ function isTodoListItem(row) {
605
+ if (typeof row != "object" || row === null) return !1;
606
+ const candidate = row, status = candidate.status;
607
+ return typeof candidate._key == "string" && typeof candidate.label == "string" && (status == null || typeof status == "string");
608
+ }
609
+
610
+ function declaredRowColumns(entry) {
611
+ if (("_type" in entry ? entry._type : entry.type) === "array") return new Set((("of" in entry ? entry.of : void 0) ?? []).map(shape => shape.name));
612
+ }
613
+
614
+ function isTodoListEntry(entry) {
615
+ const columns = declaredRowColumns(entry);
616
+ return columns !== void 0 && columns.has("label") && columns.has("status");
617
+ }
618
+
619
+ function isNotesEntry(entry) {
620
+ const columns = declaredRowColumns(entry);
621
+ return columns !== void 0 && columns.has("body") && columns.has("actor") && columns.has("at");
622
+ }
623
+
624
+ class FieldValueShapeError extends WorkflowError {
625
+ entryType;
626
+ entryName;
627
+ issues;
628
+ constructor(args) {
629
+ const issueText = args.issues.join("; ");
630
+ super("field-value-shape", `Field entry ${args.mode} shape invalid for "${args.entryName}" (${args.entryType}): ${issueText}`),
631
+ this.name = "FieldValueShapeError", this.entryType = args.entryType, this.entryName = args.entryName,
632
+ this.issues = args.issues;
633
+ }
634
+ }
635
+
636
+ const GdrShape = v__namespace.looseObject({
637
+ id: v__namespace.pipe(v__namespace.string(), v__namespace.check(s => isGdrUri(s), "must be a GDR URI")),
638
+ type: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
639
+ }), ReleaseRefShape = v__namespace.pipe(v__namespace.looseObject({
640
+ id: v__namespace.pipe(v__namespace.string(), v__namespace.check(s => isGdrUri(s), "must be a GDR URI")),
641
+ type: v__namespace.literal("system.release"),
642
+ releaseName: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
643
+ }), v__namespace.check(ref => !isGdrUri(ref.id) || extractDocumentId(ref.id) === releaseDocId(ref.releaseName), "id must point at the `_.releases.<releaseName>` doc named by releaseName")), ActorShape = v__namespace.looseObject({
644
+ kind: v__namespace.picklist(ACTOR_KINDS),
645
+ id: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1)),
646
+ roles: v__namespace.optional(v__namespace.array(v__namespace.string())),
647
+ onBehalfOf: v__namespace.optional(v__namespace.string())
648
+ }), AssigneeShape = v__namespace.union([ v__namespace.looseObject({
649
+ type: v__namespace.literal("user"),
650
+ id: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
651
+ }), v__namespace.looseObject({
652
+ type: v__namespace.literal("role"),
653
+ role: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
654
+ }) ]), 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() ]), NullableDateTime = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.check(s => !Number.isNaN(Date.parse(s)), "must be an ISO-8601 datetime string")) ]), 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, valueSchemas = {
655
+ "doc.ref": v__namespace.union([ v__namespace.null(), GdrShape ]),
656
+ "doc.refs": v__namespace.array(GdrShape),
657
+ "release.ref": v__namespace.union([ v__namespace.null(), ReleaseRefShape ]),
658
+ query: v__namespace.any(),
659
+ string: NullableString,
660
+ text: NullableString,
661
+ number: NullableNumber,
662
+ boolean: NullableBoolean,
663
+ date: NullableDate,
664
+ datetime: NullableDateTime,
665
+ url: NullableUrl,
666
+ actor: v__namespace.union([ v__namespace.null(), ActorShape ]),
667
+ assignee: v__namespace.union([ v__namespace.null(), AssigneeShape ]),
668
+ assignees: v__namespace.array(AssigneeShape)
669
+ };
670
+
671
+ function shapeValueSchema(shape, leaf) {
672
+ return shape.type === "object" ? objectSchema(shape.fields ?? [], leaf) : shape.type === "array" ? v__namespace.array(objectSchema(shape.of ?? [], leaf)) : leaf[shape.type] ?? v__namespace.any();
673
+ }
674
+
675
+ function objectSchema(fields, leaf) {
676
+ const entries = /* @__PURE__ */ Object.create(null);
677
+ for (const f of fields) entries[f.name] = v__namespace.optional(shapeValueSchema(f, leaf));
678
+ return v__namespace.looseObject(entries);
679
+ }
680
+
681
+ function wholeValueSchema(args) {
682
+ const {entryType: entryType, shape: shape, leaf: leaf} = args;
683
+ return entryType === "object" ? v__namespace.union([ v__namespace.null(), objectSchema(shape.fields ?? [], leaf) ]) : entryType === "array" ? v__namespace.array(objectSchema(shape.of ?? [], leaf)) : leaf[entryType];
684
+ }
685
+
686
+ function appendItemSchema(entryType, shape) {
687
+ if (entryType === "array") return objectSchema(shape.of ?? [], valueSchemas);
688
+ if (entryType === "doc.refs") return GdrShape;
689
+ if (entryType === "assignees") return AssigneeShape;
690
+ }
691
+
692
+ function rejectedRefTypes(args) {
693
+ const {entryType: entryType, types: types, value: value} = args;
694
+ if (types === void 0 || value === null || value === void 0) return [];
695
+ if (entryType !== "doc.ref" && entryType !== "doc.refs") return [];
696
+ let items = [ value ];
697
+ return entryType === "doc.refs" && (items = Array.isArray(value) ? value : []),
698
+ [ ...new Set(items.map(gdrTypeOf).filter(t => t !== void 0 && !types.includes(t))) ];
699
+ }
700
+
701
+ function refTypeIssues(args) {
702
+ const rejected = rejectedRefTypes(args);
703
+ if (rejected.length === 0) return;
704
+ const accepts = (args.types ?? []).map(t => `"${t}"`).join(", ");
705
+ return rejected.map(t => `document type "${t}" is not accepted — this entry accepts ${accepts} (a GDR's \`type\` names the target document's schema type)`);
706
+ }
707
+
708
+ function gdrTypeOf(item) {
709
+ if (typeof item != "object" || item === null) return;
710
+ const t = item.type;
711
+ return typeof t == "string" ? t : void 0;
712
+ }
713
+
714
+ function checkFieldValue(args) {
715
+ return checkValueAgainst(args, valueSchemas);
716
+ }
717
+
718
+ function checkValueAgainst(args, leaf) {
719
+ const schema = wholeValueSchema({
720
+ entryType: args.entryType,
721
+ shape: args,
722
+ leaf: leaf
723
+ });
724
+ if (schema === void 0) return [ `unknown field entry type ${args.entryType}` ];
725
+ const result = v__namespace.safeParse(schema, args.value);
726
+ return result.success ? refTypeIssues({
727
+ entryType: args.entryType,
728
+ types: args.types,
729
+ value: args.value
730
+ }) : formatIssues(result.issues);
731
+ }
732
+
733
+ function validateFieldValue(args) {
734
+ const issues = checkFieldValue(args);
735
+ if (issues !== void 0) throw new FieldValueShapeError({
736
+ entryType: args.entryType,
737
+ entryName: args.entryName,
738
+ issues: issues,
739
+ mode: "value"
740
+ });
741
+ }
742
+
743
+ const BARE_ID_SOURCE = "[A-Za-z0-9_][A-Za-z0-9._-]*", BARE_ID_RE = new RegExp(`^${BARE_ID_SOURCE}$`), ALIAS_REF_RE = new RegExp(`^@${RESOURCE_ALIAS_NAME_SOURCE}:${BARE_ID_SOURCE}$`);
744
+
745
+ function isAuthoringRefId(id) {
746
+ return id.startsWith("@") ? ALIAS_REF_RE.test(id) : id.includes(":") ? isGdrUri(id) : BARE_ID_RE.test(id);
747
+ }
748
+
749
+ function isBareSeedId(id) {
750
+ return BARE_ID_RE.test(id);
751
+ }
752
+
753
+ const AuthoringRefId = v__namespace.pipe(v__namespace.string(), v__namespace.check(isAuthoringRefId, "must be a bare document id, a GDR URI, or a portable `@<alias>:<id>` reference")), AuthoringGdrShape = v__namespace.looseObject({
754
+ id: AuthoringRefId,
755
+ type: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
756
+ }), seedValueSchemas = {
757
+ ...valueSchemas,
758
+ "doc.ref": v__namespace.union([ v__namespace.null(), AuthoringGdrShape ]),
759
+ "doc.refs": v__namespace.array(AuthoringGdrShape),
760
+ "release.ref": v__namespace.union([ v__namespace.null(), v__namespace.looseObject({
761
+ id: AuthoringRefId,
762
+ type: v__namespace.literal("system.release"),
763
+ releaseName: v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1))
764
+ }) ])
765
+ };
766
+
767
+ function checkLiteralSeed(args) {
768
+ return args.value === null ? [ "a literal seed cannot be null — omit `initialValue` to start the field empty" ] : checkValueAgainst(args, seedValueSchemas);
769
+ }
770
+
771
+ function validateFieldAppendItem(args) {
772
+ const schema = appendItemSchema(args.entryType, args);
773
+ if (schema === void 0) throw new FieldValueShapeError({
774
+ entryType: args.entryType,
775
+ entryName: args.entryName,
776
+ issues: [ `field entry type ${args.entryType} does not support append` ],
777
+ mode: "item"
778
+ });
779
+ const result = v__namespace.safeParse(schema, args.item);
780
+ if (!result.success) throw new FieldValueShapeError({
781
+ entryType: args.entryType,
782
+ entryName: args.entryName,
783
+ issues: formatIssues(result.issues),
784
+ mode: "item"
785
+ });
786
+ const typeIssues = refTypeIssues({
787
+ entryType: args.entryType,
788
+ types: args.types,
789
+ value: [ args.item ]
790
+ });
791
+ if (typeIssues !== void 0) throw new FieldValueShapeError({
792
+ entryType: args.entryType,
793
+ entryName: args.entryName,
794
+ issues: typeIssues,
795
+ mode: "item"
796
+ });
797
+ }
798
+
799
+ function formatIssues(issues) {
800
+ return issues.map(i => {
801
+ const keys = i.path?.map(p => p.key) ?? [];
802
+ return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${i.message}`;
803
+ });
804
+ }
805
+
806
+ const ACTIVITY_STATUSES = [ "pending", "active", "done", "skipped", "failed" ], TERMINAL_ACTIVITY_STATUSES = [ "done", "skipped", "failed" ];
807
+
808
+ function isTerminalActivityStatus(status) {
809
+ return TERMINAL_ACTIVITY_STATUSES.includes(status);
810
+ }
811
+
812
+ const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISSIONS = [ "create", "read", "update" ], MUTATION_GUARD_ACTIONS = [ "create", "update", "delete", "publish", "unpublish" ], ACTIVITY_KINDS = [ "user", "service", "script", "manual", "receive" ], GROUP_KINDS = [ "core", "details" ], DRIVER_KINDS = [ "person", "agent", "service", "engine" ], NonEmpty = v__namespace.pipe(v__namespace.string(), v__namespace.minLength(1, "must be a non-empty string")), PositiveInt = v__namespace.pipe(v__namespace.number(), v__namespace.integer(), v__namespace.minValue(1)), GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
813
+
814
+ function groqIdentifier(referencedAs) {
815
+ return v__namespace.pipe(v__namespace.string(), v__namespace.regex(GROQ_IDENTIFIER, `must be a GROQ-safe identifier (letters, digits, underscore; not starting with a digit) because it is referenced as ${referencedAs} in GROQ conditions`));
816
+ }
817
+
818
+ function picklist(options) {
819
+ return v__namespace.picklist(options, `Invalid option: expected one of ${options.map(o => `"${o}"`).join("|")}`);
820
+ }
821
+
822
+ function pinned() {
823
+ return (schema, ..._exact) => schema;
824
+ }
825
+
826
+ const LiteralSchema = v__namespace.strictObject({
827
+ type: v__namespace.literal("literal"),
828
+ value: v__namespace.unknown()
829
+ }), FieldReadSchema = v__namespace.strictObject({
830
+ type: v__namespace.literal("fieldRead"),
831
+ scope: v__namespace.optional(v__namespace.union([ v__namespace.literal("workflow"), v__namespace.literal("stage") ])),
832
+ field: NonEmpty,
833
+ path: v__namespace.optional(v__namespace.string())
834
+ }), FieldSourceSchema = v__namespace.union([ v__namespace.strictObject({
835
+ type: v__namespace.literal("input")
836
+ }), v__namespace.strictObject({
837
+ type: v__namespace.literal("query"),
838
+ query: NonEmpty
839
+ }), LiteralSchema, FieldReadSchema ]), ValueExprSchema = v__namespace.lazy(() => v__namespace.union([ LiteralSchema, FieldReadSchema, v__namespace.strictObject({
840
+ type: v__namespace.literal("param"),
841
+ param: NonEmpty
842
+ }), v__namespace.strictObject({
843
+ type: v__namespace.literal("actor")
844
+ }), v__namespace.strictObject({
845
+ type: v__namespace.literal("now")
846
+ }), v__namespace.strictObject({
847
+ type: v__namespace.literal("self")
848
+ }), v__namespace.strictObject({
849
+ type: v__namespace.literal("stage")
850
+ }), v__namespace.strictObject({
851
+ type: v__namespace.literal("object"),
852
+ fields: v__namespace.record(NonEmpty, ValueExprSchema)
853
+ }) ])), StoredFieldRefSchema = v__namespace.strictObject({
854
+ scope: picklist(FIELD_SCOPES),
855
+ field: NonEmpty
856
+ }), AuthoringFieldRefSchema = v__namespace.strictObject({
857
+ scope: v__namespace.optional(picklist(FIELD_SCOPES)),
858
+ field: NonEmpty
859
+ }), HREF_SCHEMES = [ "http:", "https:" ];
860
+
861
+ function isHttpUrl(value) {
862
+ try {
863
+ return HREF_SCHEMES.includes(new URL(value).protocol);
864
+ } catch {
865
+ return !1;
866
+ }
867
+ }
868
+
869
+ const UrlString = v__namespace.pipe(v__namespace.string(), v__namespace.url("must be a valid URL"), v__namespace.check(isHttpUrl, "must be an http(s) URL"));
870
+
871
+ function manualTargetSchema(ref) {
872
+ return v__namespace.variant("type", [ v__namespace.strictObject({
873
+ type: v__namespace.literal("url"),
874
+ url: UrlString
875
+ }), v__namespace.strictObject({
876
+ type: v__namespace.literal("field"),
877
+ field: ref
878
+ }) ]);
879
+ }
880
+
881
+ const StoredManualTargetSchema = manualTargetSchema(StoredFieldRefSchema), AuthoringManualTargetSchema = manualTargetSchema(v__namespace.union([ NonEmpty, AuthoringFieldRefSchema ])), ConditionSchema = NonEmpty;
882
+
883
+ function opSchemas(targetSchema) {
884
+ return [ v__namespace.strictObject({
885
+ type: v__namespace.literal("field.set"),
886
+ target: targetSchema,
887
+ value: ValueExprSchema
888
+ }), v__namespace.strictObject({
889
+ type: v__namespace.literal("field.unset"),
890
+ target: targetSchema
891
+ }), v__namespace.strictObject({
892
+ type: v__namespace.literal("field.append"),
893
+ target: targetSchema,
894
+ value: ValueExprSchema
895
+ }), v__namespace.strictObject({
896
+ type: v__namespace.literal("field.updateWhere"),
897
+ target: targetSchema,
898
+ where: ConditionSchema,
899
+ value: ValueExprSchema
900
+ }), v__namespace.strictObject({
901
+ type: v__namespace.literal("field.removeWhere"),
902
+ target: targetSchema,
903
+ where: ConditionSchema
904
+ }) ];
905
+ }
906
+
907
+ const StoredFieldOpSchema = v__namespace.variant("type", [ ...opSchemas(StoredFieldRefSchema) ]), StoredOpSchema = v__namespace.variant("type", [ ...opSchemas(StoredFieldRefSchema), v__namespace.strictObject({
908
+ type: v__namespace.literal("status.set"),
909
+ activity: NonEmpty,
910
+ status: picklist(ACTIVITY_STATUSES)
911
+ }) ]), StoredTransitionOpSchema = StoredFieldOpSchema, AuditOpSchema = v__namespace.strictObject({
912
+ type: v__namespace.literal("audit"),
913
+ target: AuthoringFieldRefSchema,
914
+ value: ValueExprSchema,
915
+ stampFields: v__namespace.optional(v__namespace.strictObject({
916
+ actor: v__namespace.optional(NonEmpty),
917
+ at: v__namespace.optional(NonEmpty)
918
+ }))
919
+ }), AuthoringOpSchema = v__namespace.variant("type", [ ...opSchemas(AuthoringFieldRefSchema), v__namespace.strictObject({
920
+ type: v__namespace.literal("status.set"),
921
+ activity: v__namespace.optional(NonEmpty),
922
+ status: picklist(ACTIVITY_STATUSES)
923
+ }), AuditOpSchema ]), GroupName = v__namespace.pipe(v__namespace.string(), v__namespace.regex(GROQ_IDENTIFIER, "must be an identifier (letters, digits, underscore; not starting with a digit)")), GroupSchema = pinned()(v__namespace.strictObject({
924
+ name: GroupName,
925
+ title: v__namespace.optional(v__namespace.string()),
926
+ description: v__namespace.optional(v__namespace.string()),
927
+ kind: v__namespace.optional(picklist(GROUP_KINDS))
928
+ })), GroupNameList = v__namespace.pipe(v__namespace.array(GroupName), v__namespace.minLength(1, "name at least one group, or omit `group`"), v__namespace.check(names => new Set(names).size === names.length, "a group is listed more than once — list each group once")), StoredGroupMembershipSchema = GroupNameList, AuthoringGroupMembershipSchema = v__namespace.union([ GroupName, GroupNameList ]);
929
+
930
+ function groupMembershipNames(group) {
931
+ return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
932
+ }
933
+
934
+ const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "release.ref", "string", "text", "number", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), FieldEntryName = groqIdentifier("`$fields.<name>`");
935
+
936
+ function asShape(input) {
937
+ return typeof input == "object" && input !== null ? input : {};
938
+ }
939
+
940
+ function compositeShapeOk(input) {
941
+ const shape = asShape(input);
942
+ return shape.type === "object" ? Array.isArray(shape.fields) && shape.fields.length > 0 && shape.of === void 0 : shape.type === "array" ? Array.isArray(shape.of) && shape.of.length > 0 && shape.fields === void 0 : shape.fields === void 0 && shape.of === void 0;
943
+ }
944
+
945
+ function compositeShapeMessage(input) {
946
+ const shape = asShape(input);
947
+ return shape.type === "object" ? shape.of !== void 0 ? "an `object` kind declares its sub-fields with `fields`, not `of`" : "an `object` kind needs a non-empty `fields` list of sub-field shapes" : shape.type === "array" ? shape.fields !== void 0 ? "an `array` kind declares its item shape with `of`, not `fields`" : "an `array` kind needs a non-empty `of` list of sub-field shapes" : `\`fields\` / \`of\` are only valid on the \`object\` / \`array\` kinds, not "${String(shape.type)}"`;
948
+ }
949
+
950
+ function duplicateSubfieldName(input) {
951
+ const shape = asShape(input);
952
+ let list = [];
953
+ Array.isArray(shape.fields) ? list = shape.fields : Array.isArray(shape.of) && (list = shape.of);
954
+ const seen = /* @__PURE__ */ new Set;
955
+ for (const item of list) {
956
+ const name = asShape(item).name;
957
+ if (typeof name == "string") {
958
+ if (seen.has(name)) return name;
959
+ seen.add(name);
960
+ }
961
+ }
962
+ }
963
+
964
+ function compositeChecked(entries) {
965
+ return v__namespace.pipe(v__namespace.strictObject(entries), v__namespace.check(input => compositeShapeOk(input), issue => compositeShapeMessage(issue.input)), v__namespace.check(input => duplicateSubfieldName(input) === void 0, issue => `duplicate sub-field name "${duplicateSubfieldName(issue.input)}" — sub-field names must be unique within \`fields\` / \`of\``));
966
+ }
967
+
968
+ const FieldShapeSchema = v__namespace.lazy(() => compositeChecked({
969
+ type: FieldValueKindSchema,
970
+ name: FieldEntryName,
971
+ title: v__namespace.optional(v__namespace.string()),
972
+ description: v__namespace.optional(v__namespace.string()),
973
+ fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
974
+ of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
975
+ })), StoredEditableSchema = v__namespace.union([ v__namespace.literal(!0), NonEmpty ]), AuthoringEditableSchema = v__namespace.union([ v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty ]);
976
+
977
+ function fieldBase(editable, group) {
978
+ return {
979
+ name: FieldEntryName,
980
+ title: v__namespace.optional(v__namespace.string()),
981
+ description: v__namespace.optional(v__namespace.string()),
982
+ group: v__namespace.optional(group),
983
+ required: v__namespace.optional(v__namespace.boolean()),
984
+ initialValue: v__namespace.optional(FieldSourceSchema),
985
+ editable: v__namespace.optional(editable)
986
+ };
987
+ }
988
+
989
+ function fieldEntryFields(editable, group) {
990
+ return {
991
+ type: FieldKindSchema,
992
+ ...fieldBase(editable, group),
993
+ types: v__namespace.optional(v__namespace.pipe(v__namespace.array(NonEmpty), v__namespace.minLength(1, "declare at least one accepted type, or omit `types` to accept any"))),
994
+ fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
995
+ of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
996
+ };
997
+ }
998
+
999
+ function literalSeedIssues(entry) {
1000
+ if (entry.initialValue?.type === "literal") return checkLiteralSeed({
1001
+ entryType: entry.type,
1002
+ value: entry.initialValue.value,
1003
+ types: entry.types,
1004
+ fields: entry.fields,
1005
+ of: entry.of
1006
+ });
1007
+ }
1008
+
1009
+ function literalSeedCheck() {
1010
+ return v__namespace.check(entry => literalSeedIssues(entry) === void 0, issue => `initialValue literal does not fit the declared kind: ${(literalSeedIssues(issue.input) ?? []).join("; ")}`);
1011
+ }
1012
+
1013
+ function refTypesCheck() {
1014
+ return v__namespace.check(entry => entry.types === void 0 || entry.type === "doc.ref" || entry.type === "doc.refs", issue => `\`types\` is only valid on \`doc.ref\` / \`doc.refs\` entries, not "${issue.input.type}"`);
1015
+ }
1016
+
1017
+ const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(StoredEditableSchema, StoredGroupMembershipSchema)), refTypesCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(AuthoringEditableSchema, AuthoringGroupMembershipSchema)), refTypesCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v__namespace.strictObject({
1018
+ type: v__namespace.literal("claim"),
1019
+ name: FieldEntryName,
1020
+ title: v__namespace.optional(v__namespace.string()),
1021
+ description: v__namespace.optional(v__namespace.string()),
1022
+ group: v__namespace.optional(AuthoringGroupMembershipSchema)
1023
+ }));
1024
+
1025
+ function listSugarFields(type) {
1026
+ return {
1027
+ type: v__namespace.literal(type),
1028
+ ...fieldBase(AuthoringEditableSchema, AuthoringGroupMembershipSchema)
1029
+ };
1030
+ }
1031
+
1032
+ const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("todoList"))), NotesFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("notes"))), AuthoringFieldEntrySchema = pinned()(v__namespace.union([ RawAuthoringFieldEntrySchema, ClaimFieldSchema, TodoListFieldSchema, NotesFieldSchema ])), EffectSchema = v__namespace.strictObject({
1033
+ name: NonEmpty,
1034
+ title: v__namespace.optional(v__namespace.string()),
1035
+ description: v__namespace.optional(v__namespace.string()),
1036
+ bindings: v__namespace.optional(v__namespace.record(v__namespace.string(), ConditionSchema)),
1037
+ input: v__namespace.optional(v__namespace.record(v__namespace.string(), v__namespace.unknown())),
1038
+ outputs: v__namespace.optional(v__namespace.array(FieldShapeSchema))
1039
+ }), ActionParamSchema = v__namespace.strictObject({
1040
+ type: picklist([ "string", "number", "boolean", "url", "dateTime", "actor", "doc.ref", "doc.refs", "json" ]),
1041
+ name: NonEmpty,
1042
+ title: v__namespace.optional(v__namespace.string()),
1043
+ description: v__namespace.optional(v__namespace.string()),
1044
+ required: v__namespace.optional(v__namespace.boolean())
1045
+ });
1046
+
1047
+ function actionFields(op, group) {
1048
+ return {
1049
+ name: NonEmpty,
1050
+ title: v__namespace.optional(v__namespace.string()),
1051
+ description: v__namespace.optional(v__namespace.string()),
1052
+ group: v__namespace.optional(group),
1053
+ filter: v__namespace.optional(ConditionSchema),
1054
+ params: v__namespace.optional(v__namespace.array(ActionParamSchema)),
1055
+ ops: v__namespace.optional(v__namespace.array(op)),
1056
+ effects: v__namespace.optional(v__namespace.array(EffectSchema))
1057
+ };
1058
+ }
1059
+
1060
+ const StoredActionSchema = pinned()(v__namespace.strictObject(actionFields(StoredOpSchema, StoredGroupMembershipSchema))), TerminalActivityStatus = picklist(TERMINAL_ACTIVITY_STATUSES), RawAuthoringActionSchema = pinned()(v__namespace.strictObject({
1061
+ ...actionFields(AuthoringOpSchema, AuthoringGroupMembershipSchema),
1062
+ roles: v__namespace.optional(v__namespace.array(NonEmpty)),
1063
+ status: v__namespace.optional(TerminalActivityStatus)
1064
+ })), ClaimActionSchema = pinned()(v__namespace.strictObject({
1065
+ type: v__namespace.literal("claim"),
1066
+ name: NonEmpty,
1067
+ title: v__namespace.optional(v__namespace.string()),
1068
+ description: v__namespace.optional(v__namespace.string()),
1069
+ group: v__namespace.optional(AuthoringGroupMembershipSchema),
1070
+ field: v__namespace.union([ NonEmpty, AuthoringFieldRefSchema ]),
1071
+ roles: v__namespace.optional(v__namespace.array(NonEmpty)),
1072
+ filter: v__namespace.optional(ConditionSchema),
1073
+ params: v__namespace.optional(v__namespace.array(ActionParamSchema)),
1074
+ effects: v__namespace.optional(v__namespace.array(EffectSchema))
1075
+ })), AuthoringActionSchema = pinned()(v__namespace.union([ RawAuthoringActionSchema, ClaimActionSchema ])), DefinitionRefSchema = v__namespace.strictObject({
1076
+ name: NonEmpty,
1077
+ version: v__namespace.optional(v__namespace.union([ PositiveInt, v__namespace.literal("latest") ]))
1078
+ }), SubworkflowsSchema = v__namespace.strictObject({
1079
+ forEach: NonEmpty,
1080
+ definition: DefinitionRefSchema,
1081
+ with: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
1082
+ context: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
1083
+ onExit: v__namespace.optional(picklist([ "detach", "abort" ]))
1084
+ });
1085
+
1086
+ function activityFields({field: field, action: action, op: op, target: target, group: group}) {
1087
+ return {
1088
+ name: NonEmpty,
1089
+ title: v__namespace.optional(v__namespace.string()),
1090
+ description: v__namespace.optional(v__namespace.string()),
1091
+ groups: v__namespace.optional(v__namespace.array(GroupSchema)),
1092
+ group: v__namespace.optional(group),
1093
+ kind: v__namespace.optional(picklist(ACTIVITY_KINDS)),
1094
+ target: v__namespace.optional(target),
1095
+ activation: v__namespace.optional(picklist([ "auto", "manual" ])),
1096
+ filter: v__namespace.optional(ConditionSchema),
1097
+ requirements: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
1098
+ completeWhen: v__namespace.optional(ConditionSchema),
1099
+ failWhen: v__namespace.optional(ConditionSchema),
1100
+ ops: v__namespace.optional(v__namespace.array(op)),
1101
+ effects: v__namespace.optional(v__namespace.array(EffectSchema)),
1102
+ actions: v__namespace.optional(v__namespace.array(action)),
1103
+ subworkflows: v__namespace.optional(SubworkflowsSchema),
1104
+ fields: v__namespace.optional(v__namespace.array(field))
1105
+ };
1106
+ }
1107
+
1108
+ const StoredActivitySchema = pinned()(v__namespace.strictObject(activityFields({
1109
+ field: FieldEntrySchema,
1110
+ action: StoredActionSchema,
1111
+ op: StoredOpSchema,
1112
+ target: StoredManualTargetSchema,
1113
+ group: StoredGroupMembershipSchema
1114
+ }))), AuthoringActivitySchema = pinned()(v__namespace.strictObject(activityFields({
1115
+ field: AuthoringFieldEntrySchema,
1116
+ action: AuthoringActionSchema,
1117
+ op: AuthoringOpSchema,
1118
+ target: AuthoringManualTargetSchema,
1119
+ group: AuthoringGroupMembershipSchema
1120
+ })));
1121
+
1122
+ function transitionFields(op, filter) {
1123
+ return {
1124
+ name: NonEmpty,
1125
+ title: v__namespace.optional(v__namespace.string()),
1126
+ description: v__namespace.optional(v__namespace.string()),
1127
+ to: NonEmpty,
1128
+ filter: filter,
1129
+ ops: v__namespace.optional(v__namespace.array(op)),
1130
+ effects: v__namespace.optional(v__namespace.array(EffectSchema))
1131
+ };
1132
+ }
1133
+
1134
+ const StoredTransitionSchema = pinned()(v__namespace.strictObject(transitionFields(StoredTransitionOpSchema, ConditionSchema))), AuthoringTransitionOpSchema = v__namespace.variant("type", [ ...opSchemas(AuthoringFieldRefSchema), AuditOpSchema ]), AuthoringTransitionSchema = pinned()(v__namespace.strictObject(transitionFields(AuthoringTransitionOpSchema, v__namespace.optional(ConditionSchema)))), GuardActionSchema = picklist(MUTATION_GUARD_ACTIONS), GuardReadPath = v__namespace.pipe(NonEmpty, v__namespace.check(path => !/[\r\n\u2028\u2029]/.test(path), "a guard read path cannot contain a line break")), GuardReadSchema = v__namespace.variant("type", [ v__namespace.strictObject({
1135
+ type: v__namespace.literal("self")
1136
+ }), v__namespace.strictObject({
1137
+ type: v__namespace.literal("now")
1138
+ }), v__namespace.strictObject({
1139
+ type: v__namespace.literal("fieldRead"),
1140
+ field: FieldEntryName,
1141
+ path: v__namespace.optional(GuardReadPath)
1142
+ }), v__namespace.strictObject({
1143
+ type: v__namespace.literal("effectsRead"),
1144
+ effect: v__namespace.pipe(NonEmpty, v__namespace.check(name => !name.includes("'"), "an effect name cannot contain `'`")),
1145
+ path: v__namespace.optional(GuardReadPath)
1146
+ }) ]);
1147
+
1148
+ function guardMatchFields(read) {
1149
+ return {
1150
+ types: v__namespace.optional(v__namespace.array(NonEmpty)),
1151
+ idRefs: v__namespace.optional(v__namespace.array(read)),
1152
+ idPatterns: v__namespace.optional(v__namespace.array(NonEmpty)),
1153
+ actions: v__namespace.pipe(v__namespace.array(GuardActionSchema), v__namespace.minLength(1, "a guard must match at least one action"))
1154
+ };
1155
+ }
1156
+
1157
+ function guardFields(read) {
1158
+ return {
1159
+ name: NonEmpty,
1160
+ title: v__namespace.optional(v__namespace.string()),
1161
+ description: v__namespace.optional(v__namespace.string()),
1162
+ match: v__namespace.strictObject(guardMatchFields(read)),
1163
+ predicate: v__namespace.optional(v__namespace.string()),
1164
+ metadata: v__namespace.optional(v__namespace.record(NonEmpty, read))
1165
+ };
1166
+ }
1167
+
1168
+ const GuardSchema = v__namespace.strictObject(guardFields(NonEmpty)), AuthoringGuardSchema = v__namespace.strictObject(guardFields(GuardReadSchema));
1169
+
1170
+ function stageFields({field: field, activity: activity, transition: transition, guard: guard, editable: editable}) {
1171
+ return {
1172
+ name: NonEmpty,
1173
+ title: v__namespace.optional(v__namespace.string()),
1174
+ description: v__namespace.optional(v__namespace.string()),
1175
+ groups: v__namespace.optional(v__namespace.array(GroupSchema)),
1176
+ activities: v__namespace.optional(v__namespace.array(activity)),
1177
+ transitions: v__namespace.optional(v__namespace.array(transition)),
1178
+ guards: v__namespace.optional(v__namespace.array(guard)),
1179
+ fields: v__namespace.optional(v__namespace.array(field)),
1180
+ editable: v__namespace.optional(v__namespace.record(FieldEntryName, editable))
1181
+ };
1182
+ }
1183
+
1184
+ const StoredStageSchema = pinned()(v__namespace.strictObject(stageFields({
1185
+ field: FieldEntrySchema,
1186
+ activity: StoredActivitySchema,
1187
+ transition: StoredTransitionSchema,
1188
+ guard: GuardSchema,
1189
+ editable: StoredEditableSchema
1190
+ }))), AuthoringStageSchema = pinned()(v__namespace.strictObject(stageFields({
1191
+ field: AuthoringFieldEntrySchema,
1192
+ activity: AuthoringActivitySchema,
1193
+ transition: AuthoringTransitionSchema,
1194
+ guard: AuthoringGuardSchema,
1195
+ editable: AuthoringEditableSchema
1196
+ }))), RoleAliasesSchema = v__namespace.record(NonEmpty, v__namespace.pipe(v__namespace.array(NonEmpty), v__namespace.minLength(1, "a role alias must list at least one fulfilling role"))), WORKFLOW_LIFECYCLES = [ "standalone", "child" ];
1197
+
1198
+ function workflowFields(field, stage) {
1199
+ return {
1200
+ name: NonEmpty,
1201
+ title: NonEmpty,
1202
+ description: v__namespace.optional(v__namespace.string()),
1203
+ groups: v__namespace.optional(v__namespace.array(GroupSchema)),
1204
+ lifecycle: v__namespace.optional(picklist(WORKFLOW_LIFECYCLES)),
1205
+ applicableWhen: v__namespace.optional(ConditionSchema),
1206
+ initialStage: NonEmpty,
1207
+ fields: v__namespace.optional(v__namespace.array(field)),
1208
+ stages: v__namespace.pipe(v__namespace.array(stage), v__namespace.minLength(1, "must declare at least one stage")),
1209
+ predicates: v__namespace.optional(v__namespace.record(groqIdentifier("`$<name>`"), ConditionSchema)),
1210
+ roleAliases: v__namespace.optional(RoleAliasesSchema)
1211
+ };
1212
+ }
1213
+
1214
+ const WorkflowDefinitionSchema = pinned()(v__namespace.strictObject(workflowFields(FieldEntrySchema, StoredStageSchema)));
1215
+
1216
+ function parseStoredDefinition(input, label) {
1217
+ return parseOrThrow({
1218
+ schema: WorkflowDefinitionSchema,
1219
+ input: input,
1220
+ label: label
1221
+ });
1222
+ }
1223
+
1224
+ const AuthoringWorkflowSchema = pinned()(v__namespace.strictObject(workflowFields(AuthoringFieldEntrySchema, AuthoringStageSchema))), WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
1225
+
1226
+ function isStartableDefinition(definition) {
1227
+ return definition.lifecycle !== "child";
1228
+ }
1229
+
1230
+ function formatValidationError(label, issues) {
1231
+ const lines = issues.map(issue => ` - ${issue.path.length === 0 ? "(root)" : formatIssuePath(issue.path)}: ${issue.message}`);
1232
+ return `${label} failed validation (${issues.length} issue${issues.length === 1 ? "" : "s"}):\n${lines.join(`\n`)}`;
1233
+ }
1234
+
1235
+ function issuesFromValibot(issues) {
1236
+ return issues.map(issue => ({
1237
+ path: issue.path ? issue.path.map(item => item.key) : [],
1238
+ message: issue.message
1239
+ }));
1240
+ }
1241
+
1242
+ function formatIssuePath(path) {
1243
+ let out = "";
1244
+ for (const seg of path) typeof seg == "number" ? out += `[${seg}]` : out += out.length === 0 ? String(seg) : `.${String(seg)}`;
1245
+ return out;
1246
+ }
1247
+
1248
+ function parseOrThrow({schema: schema, input: input, label: label}) {
1249
+ const result = v__namespace.safeParse(schema, input);
1250
+ if (!result.success) throw new Error(formatValidationError(label, issuesFromValibot(result.issues)));
1251
+ return result.output;
1252
+ }
1253
+
1254
+ function labelFor(fn, value) {
1255
+ if (value && typeof value == "object" && "name" in value) {
1256
+ const raw = value.name;
1257
+ if (typeof raw == "string") return `${fn}("${raw}")`;
1258
+ }
1259
+ return fn;
1260
+ }
1261
+
1262
+ function knownList(ids) {
1263
+ const quoted = [ ...ids ].map(s => `"${s}"`);
1264
+ return quoted.length > 0 ? quoted.join(", ") : "(none)";
1265
+ }
1266
+
1267
+ function checkDuplicates({names: names, what: what, issues: issues}) {
1268
+ const seen = /* @__PURE__ */ new Set;
1269
+ for (const {name: name, path: path} of names) seen.has(name) && issues.push({
1270
+ path: path,
1271
+ message: `duplicate ${what} "${name}" (already declared earlier)`
1272
+ }), seen.add(name);
1273
+ return seen;
1274
+ }
1275
+
1276
+ function checkStages(def, issues) {
1277
+ const stageNames = checkDuplicates({
1278
+ names: def.stages.map((stage, i) => ({
1279
+ name: stage.name,
1280
+ path: [ "stages", i, "name" ]
1281
+ })),
1282
+ what: "stage name",
1283
+ issues: issues
1284
+ });
1285
+ for (const [i, stage] of def.stages.entries()) {
1286
+ const activityNames = checkDuplicates({
1287
+ names: (stage.activities ?? []).map((activity, j) => ({
1288
+ name: activity.name,
1289
+ path: [ "stages", i, "activities", j, "name" ]
1290
+ })),
1291
+ what: `activity name in stage "${stage.name}"`,
1292
+ issues: issues
1293
+ });
1294
+ checkDuplicates({
1295
+ names: (stage.transitions ?? []).map((t, k) => ({
1296
+ name: t.name,
1297
+ path: [ "stages", i, "transitions", k, "name" ]
1298
+ })),
1299
+ what: `transition name in stage "${stage.name}"`,
1300
+ issues: issues
1301
+ }), checkActivities({
1302
+ def: def,
1303
+ i: i,
1304
+ activityNames: activityNames,
1305
+ issues: issues
1306
+ });
1307
+ }
1308
+ return stageNames;
1309
+ }
1310
+
1311
+ function checkActivities({def: def, i: i, activityNames: activityNames, issues: issues}) {
1312
+ const stage = def.stages[i];
1313
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
1314
+ const path = [ "stages", i, "activities", j ];
1315
+ checkDuplicates({
1316
+ names: (activity.actions ?? []).map((action, a) => ({
1317
+ name: action.name,
1318
+ path: [ ...path, "actions", a, "name" ]
1319
+ })),
1320
+ what: `action name in activity "${activity.name}"`,
1321
+ issues: issues
1322
+ }), checkStatusSetTargets({
1323
+ activity: activity,
1324
+ activityNames: activityNames,
1325
+ path: path,
1326
+ issues: issues
1327
+ });
1328
+ }
1329
+ }
1330
+
1331
+ function checkStatusSetTargets({activity: activity, activityNames: activityNames, path: path, issues: issues}) {
1332
+ checkStatusSetOps({
1333
+ ops: activity.ops,
1334
+ activityNames: activityNames,
1335
+ path: [ ...path, "ops" ],
1336
+ issues: issues
1337
+ });
1338
+ for (const [a, action] of (activity.actions ?? []).entries()) checkStatusSetOps({
1339
+ ops: action.ops,
1340
+ activityNames: activityNames,
1341
+ path: [ ...path, "actions", a, "ops" ],
1342
+ issues: issues
1343
+ });
1344
+ }
1345
+
1346
+ function checkStatusSetOps({ops: ops, activityNames: activityNames, path: path, issues: issues}) {
1347
+ for (const [o, op] of (ops ?? []).entries()) op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
1348
+ path: [ ...path, o, "activity" ],
1349
+ message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
1350
+ });
1351
+ }
1352
+
1353
+ function checkInitialStage({def: def, stageNames: stageNames, issues: issues}) {
1354
+ stageNames.has(def.initialStage) || issues.push({
1355
+ path: [ "initialStage" ],
1356
+ message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
1357
+ });
1358
+ }
1359
+
1360
+ function checkTransitionTargets({def: def, stageNames: stageNames, issues: issues}) {
1361
+ for (const [i, stage] of def.stages.entries()) for (const [k, t] of (stage.transitions ?? []).entries()) stageNames.has(t.to) || issues.push({
1362
+ path: [ "stages", i, "transitions", k, "to" ],
1363
+ message: `transition target "${t.to}" is not a declared stage. Known stages: ${knownList(stageNames)}`
1364
+ });
1365
+ }
1366
+
1367
+ function checkStageReachability({def: def, stageNames: stageNames, issues: issues}) {
1368
+ if (!stageNames.has(def.initialStage)) return;
1369
+ const stagesByName = /* @__PURE__ */ new Map;
1370
+ for (const stage of def.stages) stagesByName.has(stage.name) || stagesByName.set(stage.name, stage);
1371
+ const reached = /* @__PURE__ */ new Set([ def.initialStage ]), frontier = [ def.initialStage ];
1372
+ for (;frontier.length > 0; ) {
1373
+ const stage = stagesByName.get(frontier.pop());
1374
+ for (const t of stage?.transitions ?? []) reached.has(t.to) || !stageNames.has(t.to) || (reached.add(t.to),
1375
+ frontier.push(t.to));
1376
+ }
1377
+ for (const [i, stage] of def.stages.entries()) reached.has(stage.name) || issues.push({
1378
+ path: [ "stages", i, "name" ],
1379
+ message: `stage "${stage.name}" is unreachable — no transition path leads from initialStage "${def.initialStage}" to it, so no instance can ever enter it. Add a transition targeting it, or remove the stage`
1380
+ });
1381
+ }
1382
+
1383
+ function effectNameSites(def) {
1384
+ const sites = [];
1385
+ for (const [i, stage] of def.stages.entries()) {
1386
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
1387
+ collectEffects({
1388
+ effects: activity.effects,
1389
+ path: [ "stages", i, "activities", j, "effects" ],
1390
+ sites: sites
1391
+ });
1392
+ for (const [a, action] of (activity.actions ?? []).entries()) collectEffects({
1393
+ effects: action.effects,
1394
+ path: [ "stages", i, "activities", j, "actions", a, "effects" ],
1395
+ sites: sites
1396
+ });
1397
+ }
1398
+ for (const [k, t] of (stage.transitions ?? []).entries()) collectEffects({
1399
+ effects: t.effects,
1400
+ path: [ "stages", i, "transitions", k, "effects" ],
1401
+ sites: sites
1402
+ });
1403
+ }
1404
+ return sites;
1405
+ }
1406
+
1407
+ function checkEffectNames(def, issues) {
1408
+ checkDuplicates({
1409
+ names: effectNameSites(def),
1410
+ what: "effect name (registry key — unique per definition)",
1411
+ issues: issues
1412
+ });
1413
+ }
1414
+
1415
+ function collectEffects({effects: effects, path: path, sites: sites}) {
1416
+ for (const [e, effect] of (effects ?? []).entries()) sites.push({
1417
+ name: effect.name,
1418
+ path: [ ...path, e, "name" ]
1419
+ });
1420
+ }
1421
+
1422
+ function checkGuardNames(def, issues) {
1423
+ const sites = def.stages.flatMap((stage, i) => (stage.guards ?? []).map((guard, g) => ({
1424
+ name: guard.name,
1425
+ path: [ "stages", i, "guards", g, "name" ]
1426
+ })));
1427
+ checkDuplicates({
1428
+ names: sites,
1429
+ what: "guard name (the guard lake _id derives from it — unique per definition)",
1430
+ issues: issues
1431
+ });
1432
+ }
1433
+
1434
+ function fieldScopes(def) {
1435
+ const scopes = [ {
1436
+ entries: def.fields,
1437
+ scope: "workflow",
1438
+ path: [ "fields" ],
1439
+ label: "workflow fields"
1440
+ } ];
1441
+ for (const [i, stage] of def.stages.entries()) {
1442
+ scopes.push({
1443
+ entries: stage.fields,
1444
+ scope: "stage",
1445
+ path: [ "stages", i, "fields" ],
1446
+ label: `stage "${stage.name}" fields`
1447
+ });
1448
+ for (const [j, activity] of (stage.activities ?? []).entries()) scopes.push({
1449
+ entries: activity.fields,
1450
+ scope: "activity",
1451
+ path: [ "stages", i, "activities", j, "fields" ],
1452
+ label: `activity "${activity.name}" fields`
1453
+ });
1454
+ }
1455
+ return scopes;
1456
+ }
1457
+
1458
+ function checkRequiredField(def, issues) {
1459
+ for (const {entries: entries, scope: scope, path: path, label: label} of fieldScopes(def)) for (const [n, entry] of (entries ?? []).entries()) if (entry.required === !0) {
1460
+ if (scope !== "workflow") issues.push({
1461
+ path: [ ...path, n, "required" ],
1462
+ message: `${label} entry "${entry.name}" is \`required\`, but \`required\` applies only to workflow-scope \`input\` entries — only those are caller-supplied at start/spawn`
1463
+ }); else if (entry.initialValue?.type !== "input") {
1464
+ const seed = entry.initialValue?.type ?? "working memory (no initialValue)";
1465
+ issues.push({
1466
+ path: [ ...path, n, "required" ],
1467
+ message: `field entry "${entry.name}" has initialValue "${seed}" — \`required\` applies only to \`input\`-sourced entries (the caller fills them at start/spawn)`
1468
+ });
1469
+ }
1470
+ }
1471
+ }
1472
+
1473
+ function checkFieldEntryNames(def, issues) {
1474
+ for (const {entries: entries, path: path, label: label} of fieldScopes(def)) checkDuplicates({
1475
+ names: (entries ?? []).map((entry, n) => ({
1476
+ name: entry.name,
1477
+ path: [ ...path, n, "name" ]
1478
+ })),
1479
+ what: `field entry name in ${label}`,
1480
+ issues: issues
1481
+ });
1482
+ }
1483
+
1484
+ function checkPredicates(def, issues) {
1485
+ const reserved = new Set(RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
1486
+ for (const name of names) reserved.has(name) && issues.push({
1487
+ path: [ "predicates", name ],
1488
+ message: `predicate "${name}" shadows the built-in $${name} — pick another name`
1489
+ });
1490
+ for (const [name, groq] of Object.entries(def.predicates ?? {})) checkPredicateBody({
1491
+ name: name,
1492
+ groq: groq,
1493
+ names: names,
1494
+ issues: issues
1495
+ });
1496
+ }
1497
+
1498
+ function checkPredicateBody({name: name, groq: groq, names: names, issues: issues}) {
1499
+ const reads = conditionParameterNames(groq);
1500
+ for (const caller of CALLER_BOUND_VARS) reads.has(caller) && issues.push({
1501
+ path: [ "predicates", name ],
1502
+ message: `predicate "${name}" reads $${caller} — predicates are instance-level (pre-evaluated once, without a caller); compose caller gates at the condition site instead`
1503
+ });
1504
+ for (const other of names) other === name || !reads.has(other) || issues.push({
1505
+ path: [ "predicates", name ],
1506
+ message: `predicate "${name}" references predicate $${other} — predicates may read built-in vars only (no cross-references; compose at the condition site instead)`
1507
+ });
1508
+ }
1509
+
1510
+ function entryNames(entries) {
1511
+ return new Set((entries ?? []).map(entry => entry.name));
1512
+ }
1513
+
1514
+ function checkUnboundCallerVars(def, issues) {
1515
+ for (const site of conditionSites(def)) {
1516
+ const reads = conditionParameterNames(site.groq);
1517
+ for (const name of unboundCallerVars(site.policy)) reads.has(name) && issues.push({
1518
+ path: site.path,
1519
+ message: callerVarMessage(site, name)
1520
+ });
1521
+ }
1522
+ }
1523
+
1524
+ function unboundCallerVars(policy) {
1525
+ return policy === "cascade" ? CALLER_BOUND_VARS : policy === "caller-bound" ? [ "params" ] : [ "can" ];
1526
+ }
1527
+
1528
+ function callerVarMessage(site, name) {
1529
+ return site.policy === "cascade" ? `${site.label} reads $${name} — the cascade evaluates transition filters and activity gates (filter/completeWhen/failWhen) with no caller bound ($assigned is constant false, the other caller vars hold no value); gate on instance state (e.g. a field an action wrote) instead` : site.policy === "caller-bound" ? `${site.label} reads $${name} — $params (the firing action's args) is bound only while the action's effect bindings and where-op \`where\`s evaluate; this site never binds it, so the condition could never pass. Bind $params in an effect binding or a where-op instead, or gate on a field an action wrote` : `${site.label} reads $can — $can (the caller's grants) is bound only in the caller-bound projection (action filters, requirements, editable predicates) and never holds a value in cascade conditions; move the check to one of those sites or drop $can`;
1530
+ }
1531
+
1532
+ function conditionSites(def) {
1533
+ const sites = [], workflowLayer = {
1534
+ scope: "workflow",
1535
+ names: entryNames(def.fields)
1536
+ };
1537
+ collectEditableSites({
1538
+ entries: def.fields,
1539
+ path: [ "fields" ],
1540
+ labelPrefix: "workflow",
1541
+ fields: "context-dependent",
1542
+ sites: sites
1543
+ });
1544
+ for (const [i, stage] of def.stages.entries()) collectStageConditionSites({
1545
+ stage: stage,
1546
+ i: i,
1547
+ workflowLayer: workflowLayer,
1548
+ sites: sites
1549
+ });
1550
+ return sites;
1551
+ }
1552
+
1553
+ function collectStageConditionSites({stage: stage, i: i, workflowLayer: workflowLayer, sites: sites}) {
1554
+ const stageLayer = {
1555
+ scope: "stage",
1556
+ names: entryNames(stage.fields)
1557
+ }, stageFields2 = [ stageLayer, workflowLayer ], editableWindow = [ stageLayer, workflowLayer, ...(stage.activities ?? []).map(activity => ({
1558
+ scope: "activity",
1559
+ names: entryNames(activity.fields)
1560
+ })) ];
1561
+ for (const [k, t] of (stage.transitions ?? []).entries()) sites.push({
1562
+ groq: t.filter,
1563
+ path: [ "stages", i, "transitions", k, "filter" ],
1564
+ label: `transition "${t.name}" filter`,
1565
+ policy: "cascade",
1566
+ fields: stageFields2
1567
+ }), collectBindingSites({
1568
+ effects: t.effects,
1569
+ path: [ "stages", i, "transitions", k, "effects" ],
1570
+ label: `transition "${t.name}"`,
1571
+ fields: stageFields2,
1572
+ sites: sites
1573
+ }), collectOpWhereSites({
1574
+ ops: t.ops,
1575
+ path: [ "stages", i, "transitions", k, "ops" ],
1576
+ label: `transition "${t.name}"`,
1577
+ fields: stageFields2,
1578
+ sites: sites
1579
+ });
1580
+ collectEditableSites({
1581
+ entries: stage.fields,
1582
+ path: [ "stages", i, "fields" ],
1583
+ labelPrefix: `stage "${stage.name}"`,
1584
+ fields: editableWindow,
1585
+ sites: sites
1586
+ });
1587
+ for (const [name, editable] of Object.entries(stage.editable ?? {})) typeof editable == "string" && sites.push({
1588
+ groq: editable,
1589
+ path: [ "stages", i, "editable", name ],
1590
+ label: `stage "${stage.name}" editable override "${name}"`,
1591
+ policy: "caller-bound",
1592
+ fields: editableWindow
1593
+ });
1594
+ for (const [j, activity] of (stage.activities ?? []).entries()) collectActivityConditionSites({
1595
+ activity: activity,
1596
+ path: [ "stages", i, "activities", j ],
1597
+ stageFields: stageFields2,
1598
+ sites: sites
1599
+ });
1600
+ }
1601
+
1602
+ function collectEditableSites({entries: entries, path: path, labelPrefix: labelPrefix, fields: fields, sites: sites}) {
1603
+ for (const [n, entry] of (entries ?? []).entries()) typeof entry.editable == "string" && sites.push({
1604
+ groq: entry.editable,
1605
+ path: [ ...path, n, "editable" ],
1606
+ label: `${labelPrefix} field "${entry.name}" editable`,
1607
+ policy: "caller-bound",
1608
+ fields: fields
1609
+ });
1610
+ }
1611
+
1612
+ function collectOpWhereSites({ops: ops, path: path, label: label, fields: fields, sites: sites}) {
1613
+ for (const [o, op] of (ops ?? []).entries()) op.where !== void 0 && sites.push({
1614
+ groq: op.where,
1615
+ path: [ ...path, o, "where" ],
1616
+ label: `${label} ${op.type} where`,
1617
+ fields: fields
1618
+ });
1619
+ }
1620
+
1621
+ function collectActivityConditionSites({activity: activity, path: path, stageFields: stageFields2, sites: sites}) {
1622
+ const fields = [ {
1623
+ scope: "activity",
1624
+ names: entryNames(activity.fields)
1625
+ }, ...stageFields2 ];
1626
+ for (const gate of [ "filter", "completeWhen", "failWhen" ]) {
1627
+ const groq = activity[gate];
1628
+ groq !== void 0 && sites.push({
1629
+ groq: groq,
1630
+ path: [ ...path, gate ],
1631
+ label: `activity "${activity.name}".${gate}`,
1632
+ policy: "cascade",
1633
+ fields: fields
1634
+ });
1635
+ }
1636
+ for (const [name, groq] of Object.entries(activity.requirements ?? {})) sites.push({
1637
+ groq: groq,
1638
+ path: [ ...path, "requirements", name ],
1639
+ label: `activity "${activity.name}" requirement "${name}"`,
1640
+ policy: "caller-bound",
1641
+ fields: fields
1642
+ });
1643
+ collectBindingSites({
1644
+ effects: activity.effects,
1645
+ path: [ ...path, "effects" ],
1646
+ label: `activity "${activity.name}"`,
1647
+ fields: fields,
1648
+ sites: sites
1649
+ }), collectOpWhereSites({
1650
+ ops: activity.ops,
1651
+ path: [ ...path, "ops" ],
1652
+ label: `activity "${activity.name}"`,
1653
+ fields: fields,
1654
+ sites: sites
1655
+ }), collectEditableSites({
1656
+ entries: activity.fields,
1657
+ path: [ ...path, "fields" ],
1658
+ labelPrefix: `activity "${activity.name}"`,
1659
+ fields: fields,
1660
+ sites: sites
1661
+ }), collectActionConditionSites({
1662
+ activity: activity,
1663
+ path: path,
1664
+ fields: fields,
1665
+ sites: sites
1666
+ }), collectSubworkflowSites({
1667
+ activity: activity,
1668
+ path: path,
1669
+ fields: fields,
1670
+ sites: sites
1671
+ });
1672
+ }
1673
+
1674
+ function collectActionConditionSites({activity: activity, path: path, fields: fields, sites: sites}) {
1675
+ for (const [a, action] of (activity.actions ?? []).entries()) action.filter !== void 0 && sites.push({
1676
+ groq: action.filter,
1677
+ path: [ ...path, "actions", a, "filter" ],
1678
+ label: `action "${action.name}" filter`,
1679
+ policy: "caller-bound",
1680
+ fields: fields
1681
+ }), collectBindingSites({
1682
+ effects: action.effects,
1683
+ path: [ ...path, "actions", a, "effects" ],
1684
+ label: `action "${action.name}"`,
1685
+ fields: fields,
1686
+ sites: sites
1687
+ }), collectOpWhereSites({
1688
+ ops: action.ops,
1689
+ path: [ ...path, "actions", a, "ops" ],
1690
+ label: `action "${action.name}"`,
1691
+ fields: fields,
1692
+ sites: sites
1693
+ });
1694
+ }
1695
+
1696
+ function collectSubworkflowSites({activity: activity, path: path, fields: fields, sites: sites}) {
1697
+ const sub = activity.subworkflows;
1698
+ if (sub === void 0) return;
1699
+ const subPath = [ ...path, "subworkflows" ];
1700
+ sites.push({
1701
+ groq: sub.forEach,
1702
+ path: [ ...subPath, "forEach" ],
1703
+ label: `activity "${activity.name}".subworkflows.forEach`,
1704
+ fields: fields
1705
+ });
1706
+ for (const [group, record] of [ [ "with", sub.with ], [ "context", sub.context ] ]) for (const [key, groq] of Object.entries(record ?? {})) sites.push({
1707
+ groq: groq,
1708
+ path: [ ...subPath, group, key ],
1709
+ label: `activity "${activity.name}".subworkflows.${group} "${key}"`,
1710
+ fields: fields
1711
+ });
1712
+ }
1713
+
1714
+ function collectBindingSites({effects: effects, path: path, label: label, fields: fields, sites: sites}) {
1715
+ for (const [e, effect] of (effects ?? []).entries()) for (const [key, groq] of Object.entries(effect.bindings ?? {})) sites.push({
1716
+ groq: groq,
1717
+ path: [ ...path, e, "bindings", key ],
1718
+ label: `${label} effect "${effect.name}" binding "${key}"`,
1719
+ fields: fields
1720
+ });
1721
+ }
1722
+
1723
+ function checkAssigneesEntries(def, issues) {
1724
+ for (const {entries: entries, path: path} of fieldScopes(def)) (entries ?? []).filter(e => e.type === "assignees").length <= 1 || issues.push({
1725
+ path: path,
1726
+ message: "at most one assignees-kind field entry per scope — the inbox reads it by kind"
1727
+ });
1728
+ }
1729
+
1730
+ function activityShape(activity) {
1731
+ return {
1732
+ hasActions: (activity.actions ?? []).length > 0,
1733
+ hasEffects: (activity.effects ?? []).length > 0,
1734
+ hasCompleteWhen: activity.completeWhen !== void 0,
1735
+ hasSubworkflows: activity.subworkflows !== void 0
1736
+ };
1737
+ }
1738
+
1739
+ const KIND_SHAPE_RULES = {
1740
+ user: s => s.hasActions ? [] : [ "needs at least one action for a person to fire" ],
1741
+ service: s => s.hasEffects ? [] : [ "needs at least one effect — the automated work it performs" ],
1742
+ manual: s => [ s.hasActions || s.hasCompleteWhen ? void 0 : "needs a way to complete — an action to acknowledge it, or a `completeWhen` predicate to verify it (otherwise it auto-resolves on activation)", s.hasSubworkflows ? "is off-system work, not a fan-out — drop `subworkflows` or move it to its own activity" : void 0 ].filter(m => m !== void 0),
1743
+ receive: s => [ s.hasCompleteWhen || s.hasSubworkflows ? void 0 : "needs a `completeWhen` (or `subworkflows`) condition to wait on", s.hasActions ? "has no actor, so it cannot carry actions" : void 0 ].filter(m => m !== void 0),
1744
+ script: s => [ s.hasActions ? "runs inline with no actor, so it cannot carry actions" : void 0, s.hasCompleteWhen ? "resolves on activation, so it cannot carry a `completeWhen` (that is a `receive`/`service` wait)" : void 0, s.hasSubworkflows ? "resolves on activation, so it cannot fan out with `subworkflows`" : void 0 ].filter(m => m !== void 0)
1745
+ };
1746
+
1747
+ function checkActivityKinds(def, issues) {
1748
+ for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) {
1749
+ const path = [ "stages", i, "activities", j ];
1750
+ if (activity.target !== void 0 && activity.kind !== "manual" && issues.push({
1751
+ path: [ ...path, "target" ],
1752
+ message: `activity "${activity.name}" has a \`target\` but is not \`kind: "manual"\` — a target is the deep-link for off-system manual work`
1753
+ }), activity.kind !== void 0) for (const fault of KIND_SHAPE_RULES[activity.kind](activityShape(activity))) issues.push({
1754
+ path: [ ...path, "kind" ],
1755
+ message: `activity "${activity.name}" declares kind "${activity.kind}" but ${fault}`
1756
+ });
1757
+ }
1758
+ }
1759
+
1760
+ function checkGroups(def, issues) {
1761
+ const workflowGroups = checkGroupDeclarations({
1762
+ groups: def.groups,
1763
+ path: [ "groups" ],
1764
+ what: "group name",
1765
+ issues: issues
1766
+ });
1767
+ checkFieldMemberships({
1768
+ entries: def.fields,
1769
+ reachable: [ workflowGroups ],
1770
+ path: [ "fields" ],
1771
+ label: "workflow fields",
1772
+ issues: issues
1773
+ });
1774
+ for (const [i, stage] of def.stages.entries()) checkStageGroups({
1775
+ stage: stage,
1776
+ i: i,
1777
+ workflowGroups: workflowGroups,
1778
+ issues: issues
1779
+ });
1780
+ }
1781
+
1782
+ function checkGroupDeclarations({groups: groups, path: path, what: what, issues: issues}) {
1783
+ return checkDuplicates({
1784
+ names: (groups ?? []).map((group, n) => ({
1785
+ name: group.name,
1786
+ path: [ ...path, n, "name" ]
1787
+ })),
1788
+ what: what,
1789
+ issues: issues
1790
+ });
1791
+ }
1792
+
1793
+ function checkStageGroups({stage: stage, i: i, workflowGroups: workflowGroups, issues: issues}) {
1794
+ const path = [ "stages", i ], enclosing = [ checkGroupDeclarations({
1795
+ groups: stage.groups,
1796
+ path: [ ...path, "groups" ],
1797
+ what: `group name in stage "${stage.name}"`,
1798
+ issues: issues
1799
+ }), workflowGroups ];
1800
+ checkFieldMemberships({
1801
+ entries: stage.fields,
1802
+ reachable: enclosing,
1803
+ path: [ ...path, "fields" ],
1804
+ label: `stage "${stage.name}" fields`,
1805
+ issues: issues
1806
+ });
1807
+ for (const [j, activity] of (stage.activities ?? []).entries()) checkActivityGroups({
1808
+ activity: activity,
1809
+ path: [ ...path, "activities", j ],
1810
+ enclosing: enclosing,
1811
+ issues: issues
1812
+ });
1813
+ }
1814
+
1815
+ function checkActivityGroups({activity: activity, path: path, enclosing: enclosing, issues: issues}) {
1816
+ checkGroupMembership({
1817
+ group: activity.group,
1818
+ reachable: enclosing,
1819
+ path: [ ...path, "group" ],
1820
+ label: `activity "${activity.name}"`,
1821
+ issues: issues
1822
+ });
1823
+ const inner = [ checkGroupDeclarations({
1824
+ groups: activity.groups,
1825
+ path: [ ...path, "groups" ],
1826
+ what: `group name in activity "${activity.name}"`,
1827
+ issues: issues
1828
+ }), ...enclosing ];
1829
+ checkFieldMemberships({
1830
+ entries: activity.fields,
1831
+ reachable: inner,
1832
+ path: [ ...path, "fields" ],
1833
+ label: `activity "${activity.name}" fields`,
1834
+ issues: issues
1835
+ });
1836
+ for (const [a, action] of (activity.actions ?? []).entries()) checkGroupMembership({
1837
+ group: action.group,
1838
+ reachable: inner,
1839
+ path: [ ...path, "actions", a, "group" ],
1840
+ label: `action "${action.name}"`,
1841
+ issues: issues
1842
+ });
1843
+ }
1844
+
1845
+ function checkFieldMemberships({entries: entries, reachable: reachable, path: path, label: label, issues: issues}) {
1846
+ for (const [n, entry] of (entries ?? []).entries()) checkGroupMembership({
1847
+ group: entry.group,
1848
+ reachable: reachable,
1849
+ path: [ ...path, n, "group" ],
1850
+ label: `${label} entry "${entry.name}"`,
1851
+ issues: issues
1852
+ });
1853
+ }
1854
+
1855
+ function checkGroupMembership({group: group, reachable: reachable, path: path, label: label, issues: issues}) {
1856
+ for (const name of groupMembershipNames(group)) {
1857
+ if (reachable.some(names => names.has(name))) continue;
1858
+ const declared = new Set(reachable.flatMap(names => [ ...names ]));
1859
+ issues.push({
1860
+ path: path,
1861
+ message: `${label} names group "${name}", which is not declared on its enclosing chain. Declared: ${knownList(declared)}`
1862
+ });
1863
+ }
1864
+ }
1865
+
1866
+ function checkConditionFieldReads(def, issues) {
1867
+ const everywhere = allDeclaredFieldNames(def);
1868
+ for (const site of conditionSites(def)) for (const name of conditionFieldReadNames(site.groq)) fieldVisibleAtSite({
1869
+ site: site,
1870
+ name: name,
1871
+ everywhere: everywhere
1872
+ }) || issues.push({
1873
+ path: site.path,
1874
+ message: undeclaredFieldReadMessage(site, name)
1875
+ });
1876
+ for (const [name, groq] of Object.entries(def.predicates ?? {})) for (const read of conditionFieldReadNames(groq)) everywhere.has(read) || issues.push({
1877
+ path: [ "predicates", name ],
1878
+ message: noFieldAnywhereMessage(`predicate "${name}"`, read)
1879
+ });
1880
+ }
1881
+
1882
+ function allDeclaredFieldNames(def) {
1883
+ const names = /* @__PURE__ */ new Set;
1884
+ for (const {entries: entries} of fieldScopes(def)) for (const entry of entries ?? []) names.add(entry.name);
1885
+ return names;
1886
+ }
1887
+
1888
+ function fieldVisibleAtSite({site: site, name: name, everywhere: everywhere}) {
1889
+ return site.fields === "context-dependent" ? everywhere.has(name) : site.fields.some(layer => layer.names.has(name));
1890
+ }
1891
+
1892
+ function noFieldAnywhereMessage(label, name) {
1893
+ return `${label} reads $fields.${name}, but no field entry named "${name}" is declared anywhere in the definition — the read evaluates to GROQ null, so the condition silently fails closed`;
1894
+ }
1895
+
1896
+ function undeclaredFieldReadMessage(site, name) {
1897
+ if (site.fields === "context-dependent") return noFieldAnywhereMessage(site.label, name);
1898
+ const visible = site.fields.flatMap(layer => [ ...layer.names ].map(n => `${layer.scope}:${n}`));
1899
+ return `${site.label} reads $fields.${name}, but no field entry named "${name}" is lexically visible here — the read evaluates to GROQ null, so the condition silently fails closed. Visible: ${visible.join(", ") || "(none)"}`;
1900
+ }
1901
+
1902
+ function checkFieldReadSeeds(def, issues) {
1903
+ const workflowEntries = def.fields ?? [];
1904
+ for (const {entries: entries, scope: scope, path: path, label: label} of fieldScopes(def)) for (const [n, entry] of (entries ?? []).entries()) {
1905
+ const read = entry.initialValue;
1906
+ read?.type === "fieldRead" && checkSeedRead({
1907
+ read: read,
1908
+ where: `${label} entry "${entry.name}"`,
1909
+ entryName: entry.name,
1910
+ scope: scope,
1911
+ siblings: entries ?? [],
1912
+ index: n,
1913
+ workflowEntries: workflowEntries,
1914
+ path: [ ...path, n, "initialValue" ],
1915
+ issues: issues
1916
+ });
1917
+ }
1918
+ }
1919
+
1920
+ function checkSeedRead(args) {
1921
+ const {read: read, where: where, path: path, issues: issues} = args, misspelled = seedScopeSpellingIssue(args);
1922
+ if (misspelled !== void 0) {
1923
+ issues.push({
1924
+ path: path,
1925
+ message: `${where} ${misspelled}`
1926
+ });
1927
+ return;
1928
+ }
1929
+ const target = read.scope === "workflow" ? seedWorkflowTarget(args) : seedEarlierSiblingTarget(args);
1930
+ target !== void 0 && pushFieldReadPathIssue({
1931
+ where: where,
1932
+ read: read,
1933
+ target: target,
1934
+ path: path,
1935
+ issues: issues
1936
+ });
1937
+ }
1938
+
1939
+ function seedScopeSpellingIssue({read: read, scope: scope}) {
1940
+ if (read.scope === "workflow" && scope === "workflow") return 'seeds from a fieldRead with scope "workflow", but workflow-scope seeds resolve against earlier same-scope siblings only (no workflow layer exists yet at start/spawn) — omit `scope`';
1941
+ if (read.scope === "stage") {
1942
+ if (scope === "workflow") return 'seeds from a fieldRead with scope "stage", but a workflow-scope entry has no stage in scope — omit `scope` to read an earlier workflow-scope sibling';
1943
+ if (scope === "activity") return 'seeds from a fieldRead with scope "stage", but a seed resolves non-workflow reads against the scope being seeded, so an activity-scope entry cannot read stage fields — omit `scope` to read an earlier activity-scope sibling, or use scope "workflow"';
1944
+ }
1945
+ }
1946
+
1947
+ function seedWorkflowTarget({read: read, where: where, workflowEntries: workflowEntries, path: path, issues: issues}) {
1948
+ const target = workflowEntries.find(entry => entry.name === read.field);
1949
+ if (target !== void 0) return target;
1950
+ issues.push({
1951
+ path: path,
1952
+ message: `${where} seeds from workflow-scope field "${read.field}", which is not declared — the read would resolve to the default value. Known workflow fields: ${knownList(workflowEntries.map(entry => entry.name))}`
1953
+ });
1954
+ }
1955
+
1956
+ function seedEarlierSiblingTarget(args) {
1957
+ const {read: read, where: where, entryName: entryName, scope: scope, siblings: siblings, index: index, workflowEntries: workflowEntries, path: path, issues: issues} = args, targetIndex = siblings.findIndex(entry => entry.name === read.field);
1958
+ if (targetIndex !== -1 && targetIndex < index) return siblings[targetIndex];
1959
+ if (targetIndex === index) {
1960
+ issues.push({
1961
+ path: path,
1962
+ message: `${where} seeds from itself — a fieldRead cannot read the entry it seeds`
1963
+ });
1964
+ return;
1965
+ }
1966
+ if (targetIndex > index) {
1967
+ issues.push({
1968
+ path: path,
1969
+ message: `${where} seeds from "${read.field}", which is declared later in the same scope — entries resolve in declaration order, so the read would see its default. Move "${read.field}" before "${entryName}"`
1970
+ });
1971
+ return;
1972
+ }
1973
+ const workflowHint = scope !== "workflow" && workflowEntries.some(entry => entry.name === read.field) ? ' — a workflow-scope entry of that name exists; add `scope: "workflow"` to read it (an omitted scope reads same-scope siblings only)' : "";
1974
+ issues.push({
1975
+ path: path,
1976
+ message: `${where} seeds from "${read.field}", which is not an earlier ${scope}-scope sibling — the read would resolve to the default value${workflowHint}. Earlier siblings: ${knownList(siblings.slice(0, index).map(entry => entry.name))}`
1977
+ });
1978
+ }
1979
+
1980
+ function checkFieldReadOpValues(def, issues) {
1981
+ const workflowEntries = def.fields ?? [];
1982
+ for (const [i, stage] of def.stages.entries()) {
1983
+ const shared = {
1984
+ workflowEntries: workflowEntries,
1985
+ stageEntries: stage.fields ?? [],
1986
+ issues: issues
1987
+ };
1988
+ for (const [k, t] of (stage.transitions ?? []).entries()) checkOpsFieldReads({
1989
+ ...shared,
1990
+ ops: t.ops,
1991
+ path: [ "stages", i, "transitions", k, "ops" ],
1992
+ label: `transition "${t.name}"`
1993
+ });
1994
+ for (const [j, activity] of (stage.activities ?? []).entries()) {
1995
+ const activityNames = entryNames(activity.fields), activityPath = [ "stages", i, "activities", j ];
1996
+ checkOpsFieldReads({
1997
+ ...shared,
1998
+ ops: activity.ops,
1999
+ path: [ ...activityPath, "ops" ],
2000
+ label: `activity "${activity.name}"`,
2001
+ activityNames: activityNames
2002
+ });
2003
+ for (const [a, action] of (activity.actions ?? []).entries()) checkOpsFieldReads({
2004
+ ...shared,
2005
+ ops: action.ops,
2006
+ path: [ ...activityPath, "actions", a, "ops" ],
2007
+ label: `action "${action.name}"`,
2008
+ activityNames: activityNames
2009
+ });
2010
+ }
2011
+ }
2012
+ }
2013
+
2014
+ function checkOpsFieldReads({ops: ops, path: path, label: label, ...ctx}) {
2015
+ for (const [o, op] of (ops ?? []).entries()) if ("value" in op) for (const {read: read, path: readPath} of fieldReadsIn(op.value, [ ...path, o, "value" ])) checkOpFieldRead({
2016
+ ...ctx,
2017
+ read: read,
2018
+ path: readPath,
2019
+ where: `${label} ${op.type} value`
2020
+ });
2021
+ }
2022
+
2023
+ function fieldReadsIn(value, path) {
2024
+ return value.type === "fieldRead" ? [ {
2025
+ read: value,
2026
+ path: path
2027
+ } ] : value.type !== "object" ? [] : Object.entries(value.fields).flatMap(([key, sub]) => fieldReadsIn(sub, [ ...path, "fields", key ]));
2028
+ }
2029
+
2030
+ function checkOpFieldRead({read: read, where: where, path: path, workflowEntries: workflowEntries, stageEntries: stageEntries, activityNames: activityNames, issues: issues}) {
2031
+ const hosts = [ {
2032
+ scope: "stage",
2033
+ entries: stageEntries
2034
+ }, {
2035
+ scope: "workflow",
2036
+ entries: workflowEntries
2037
+ } ].filter(host => read.scope === void 0 || host.scope === read.scope), target = hosts.flatMap(host => host.entries).find(entry => entry.name === read.field);
2038
+ if (target === void 0) {
2039
+ issues.push({
2040
+ path: path,
2041
+ message: opFieldReadMissMessage({
2042
+ read: read,
2043
+ where: where,
2044
+ hosts: hosts,
2045
+ activityNames: activityNames
2046
+ })
2047
+ });
2048
+ return;
2049
+ }
2050
+ pushFieldReadPathIssue({
2051
+ where: where,
2052
+ read: read,
2053
+ target: target,
2054
+ path: path,
2055
+ issues: issues
2056
+ });
2057
+ }
2058
+
2059
+ function opFieldReadMissMessage({read: read, where: where, hosts: hosts, activityNames: activityNames}) {
2060
+ const searched = read.scope === void 0 ? "stage or workflow scope" : `${read.scope} scope`, activityHint = activityNames?.has(read.field) ? ` "${read.field}" is an activity-scope field, and op-time field reads resolve against stage and workflow scopes only — declare it at stage scope to read it from an op.` : "", known = hosts.flatMap(host => host.entries.map(entry => `${host.scope}:${entry.name}`));
2061
+ return `${where} reads field "${read.field}", which is not declared at ${searched} — the read resolves to undefined at op time, so the write silently lands empty.${activityHint} Known: ${known.join(", ") || "(none)"}`;
2062
+ }
2063
+
2064
+ function checkGuardFieldReads(def, issues) {
2065
+ const reads = {
2066
+ workflowEntries: def.fields ?? [],
2067
+ effectNames: new Set(effectNameSites(def).map(site => site.name)),
2068
+ issues: issues
2069
+ };
2070
+ for (const [i, stage] of def.stages.entries()) for (const [g, guard] of (stage.guards ?? []).entries()) {
2071
+ const where = `stage "${stage.name}" guard "${guard.name}"`, guardPath = [ "stages", i, "guards", g ];
2072
+ for (const [k, expr] of (guard.match.idRefs ?? []).entries()) checkGuardRead({
2073
+ ...reads,
2074
+ expr: expr,
2075
+ where: `${where} match.idRefs`,
2076
+ path: [ ...guardPath, "match", "idRefs", k ]
2077
+ });
2078
+ for (const [key, expr] of Object.entries(guard.metadata ?? {})) checkGuardRead({
2079
+ ...reads,
2080
+ expr: expr,
2081
+ where: `${where} metadata "${key}"`,
2082
+ path: [ ...guardPath, "metadata", key ]
2083
+ });
2084
+ }
2085
+ }
2086
+
2087
+ function checkGuardRead(args) {
2088
+ const fieldRead = FIELD_READ.exec(args.expr);
2089
+ if (fieldRead !== null) {
2090
+ checkGuardFieldRead({
2091
+ ...args,
2092
+ name: fieldRead[1],
2093
+ valuePath: fieldRead[2]
2094
+ });
2095
+ return;
2096
+ }
2097
+ const effectName = EFFECTS_READ.exec(args.expr)?.[1];
2098
+ effectName === void 0 || args.effectNames.has(effectName) || args.issues.push({
2099
+ path: args.path,
2100
+ message: `${args.where} reads "${args.expr}", but no effect named "${effectName}" is declared — the read resolves to undefined and the guard deploys with a hole. Known effects: ${knownList(args.effectNames)}`
2101
+ });
2102
+ }
2103
+
2104
+ function checkGuardFieldRead({name: name, valuePath: valuePath, where: where, path: path, workflowEntries: workflowEntries, issues: issues}) {
2105
+ const target = workflowEntries.find(entry => entry.name === name);
2106
+ if (target === void 0) {
2107
+ issues.push({
2108
+ path: path,
2109
+ message: `${where} reads "$fields.${name}", but "${name}" is not a workflow-scope field entry — guard reads resolve against workflow-scope fields only. Known workflow fields: ${knownList(workflowEntries.map(entry => entry.name))}`
2110
+ });
2111
+ return;
2112
+ }
2113
+ pushFieldReadPathIssue({
2114
+ where: where,
2115
+ read: {
2116
+ field: name,
2117
+ path: valuePath
2118
+ },
2119
+ target: target,
2120
+ path: path,
2121
+ issues: issues
2122
+ });
2123
+ }
2124
+
2125
+ function pushFieldReadPathIssue({where: where, read: read, target: target, path: path, issues: issues}) {
2126
+ if (read.path === void 0) return;
2127
+ const pathIssue = fieldValuePathIssue({
2128
+ target: target,
2129
+ path: read.path
2130
+ });
2131
+ pathIssue !== void 0 && issues.push({
2132
+ path: path,
2133
+ message: `${where} reads "${read.field}" with path "${read.path}", which does not fit the declared shape of "${target.name ?? read.field}" (${target.type}) — ${pathIssue}`
2134
+ });
2135
+ }
2136
+
2137
+ const SCALAR = {
2138
+ kind: "scalar"
2139
+ }, DOC_CONTENT = {
2140
+ kind: "opaque"
2141
+ }, GDR_VALUE = {
2142
+ kind: "record",
2143
+ keys: {
2144
+ id: SCALAR,
2145
+ type: SCALAR
2146
+ }
2147
+ }, RELEASE_VALUE = {
2148
+ kind: "record",
2149
+ keys: {
2150
+ id: SCALAR,
2151
+ type: SCALAR,
2152
+ releaseName: SCALAR
2153
+ }
2154
+ }, ACTOR_VALUE = {
2155
+ kind: "record",
2156
+ keys: {
2157
+ kind: SCALAR,
2158
+ id: SCALAR,
2159
+ roles: {
2160
+ kind: "list",
2161
+ item: SCALAR
2162
+ },
2163
+ onBehalfOf: SCALAR
2164
+ }
2165
+ }, ASSIGNEE_VALUE = {
2166
+ kind: "record",
2167
+ keys: {
2168
+ type: SCALAR,
2169
+ id: SCALAR,
2170
+ role: SCALAR
2171
+ }
2172
+ }, VALUE_NODES = {
2173
+ "doc.ref": () => DOC_CONTENT,
2174
+ "doc.refs": () => ({
2175
+ kind: "list",
2176
+ item: GDR_VALUE
2177
+ }),
2178
+ "release.ref": () => RELEASE_VALUE,
2179
+ string: () => SCALAR,
2180
+ text: () => SCALAR,
2181
+ number: () => SCALAR,
2182
+ boolean: () => SCALAR,
2183
+ date: () => SCALAR,
2184
+ datetime: () => SCALAR,
2185
+ url: () => SCALAR,
2186
+ actor: () => ACTOR_VALUE,
2187
+ assignee: () => ASSIGNEE_VALUE,
2188
+ assignees: () => ({
2189
+ kind: "list",
2190
+ item: ASSIGNEE_VALUE
2191
+ }),
2192
+ object: shape => ({
2193
+ kind: "object",
2194
+ fields: shape.fields ?? []
2195
+ }),
2196
+ array: shape => ({
2197
+ kind: "rows",
2198
+ of: shape.of ?? []
2199
+ })
2200
+ };
2201
+
2202
+ function valueNodeFor(shape) {
2203
+ return Object.hasOwn(VALUE_NODES, shape.type) ? VALUE_NODES[shape.type](shape) : void 0;
2204
+ }
2205
+
2206
+ const INDEX_SEGMENT = /^\d+$/;
2207
+
2208
+ function stepIntoValueNode(node, segment) {
2209
+ switch (node.kind) {
2210
+ case "scalar":
2211
+ return "the value is a scalar with no sub-paths";
2212
+
2213
+ case "object":
2214
+ {
2215
+ const sub = node.fields.find(f => f.name === segment), next = sub === void 0 ? void 0 : valueNodeFor(sub);
2216
+ return next !== void 0 ? next : `an object value has sub-fields ${knownList(node.fields.map(f => f.name))} — "${segment}" is not one`;
2217
+ }
2218
+
2219
+ case "rows":
2220
+ return INDEX_SEGMENT.test(segment) ? {
2221
+ kind: "object",
2222
+ fields: node.of
2223
+ } : `an array value is addressed by numeric row index first (e.g. "0.<subField>") — "${segment}" is not an index`;
2224
+
2225
+ case "list":
2226
+ return INDEX_SEGMENT.test(segment) ? node.item : `an array value is addressed by numeric item index (e.g. "0") — "${segment}" is not an index`;
2227
+
2228
+ case "record":
2229
+ return Object.hasOwn(node.keys, segment) ? node.keys[segment] : `the value carries ${knownList(Object.keys(node.keys))} — "${segment}" is not one of them`;
2230
+
2231
+ case "opaque":
2232
+ return node;
2233
+ }
2234
+ }
2235
+
2236
+ function fieldValuePathIssue({target: target, path: path}) {
2237
+ let node = valueNodeFor(target);
2238
+ if (node === void 0) return `"${String(target.type)}" is not a known field kind`;
2239
+ for (const segment of path.split(".")) {
2240
+ const next = stepIntoValueNode(node, segment);
2241
+ if (typeof next == "string") return `at segment "${segment}": ${next}`;
2242
+ node = next;
2243
+ }
2244
+ }
2245
+
2246
+ function checkWorkflowInvariants(def) {
2247
+ const issues = [], stageNames = checkStages(def, issues);
2248
+ return checkInitialStage({
2249
+ def: def,
2250
+ stageNames: stageNames,
2251
+ issues: issues
2252
+ }), checkTransitionTargets({
2253
+ def: def,
2254
+ stageNames: stageNames,
2255
+ issues: issues
2256
+ }), checkStageReachability({
2257
+ def: def,
2258
+ stageNames: stageNames,
2259
+ issues: issues
2260
+ }), checkEffectNames(def, issues), checkGuardNames(def, issues), checkFieldEntryNames(def, issues),
2261
+ checkRequiredField(def, issues), checkPredicates(def, issues), checkUnboundCallerVars(def, issues),
2262
+ checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues), checkFieldReadOpValues(def, issues),
2263
+ checkGuardFieldReads(def, issues), checkAssigneesEntries(def, issues), checkActivityKinds(def, issues),
2264
+ checkGroups(def, issues), issues;
2265
+ }
2266
+
2267
+ exports.ACTIVITY_KINDS = ACTIVITY_KINDS;
2268
+
2269
+ exports.ACTOR_KINDS = ACTOR_KINDS;
2270
+
2271
+ exports.AuthoringActionSchema = AuthoringActionSchema;
2272
+
2273
+ exports.AuthoringActivitySchema = AuthoringActivitySchema;
2274
+
2275
+ exports.AuthoringFieldEntrySchema = AuthoringFieldEntrySchema;
2276
+
2277
+ exports.AuthoringGuardSchema = AuthoringGuardSchema;
2278
+
2279
+ exports.AuthoringOpSchema = AuthoringOpSchema;
2280
+
2281
+ exports.AuthoringStageSchema = AuthoringStageSchema;
2282
+
2283
+ exports.AuthoringTransitionSchema = AuthoringTransitionSchema;
2284
+
2285
+ exports.AuthoringWorkflowSchema = AuthoringWorkflowSchema;
2286
+
2287
+ exports.CALLER_BOUND_VARS = CALLER_BOUND_VARS;
2288
+
2289
+ exports.CONDITION_VARS = CONDITION_VARS;
2290
+
2291
+ exports.ContractViolationError = ContractViolationError;
2292
+
2293
+ exports.DOCUMENT_VALUE_PERMISSIONS = DOCUMENT_VALUE_PERMISSIONS;
2294
+
2295
+ exports.DRIVER_KINDS = DRIVER_KINDS;
2296
+
2297
+ exports.DefinitionInUseError = DefinitionInUseError;
2298
+
2299
+ exports.DefinitionNotFoundError = DefinitionNotFoundError;
2300
+
2301
+ exports.EFFECTS_READ = EFFECTS_READ;
2302
+
2303
+ exports.EffectNotFoundError = EffectNotFoundError;
2304
+
2305
+ exports.EffectSchema = EffectSchema;
2306
+
2307
+ exports.FIELD_READ = FIELD_READ;
2308
+
2309
+ exports.FILTER_SCOPE_VARS = FILTER_SCOPE_VARS;
2310
+
2311
+ exports.FieldValueShapeError = FieldValueShapeError;
2312
+
2313
+ exports.GROUP_KINDS = GROUP_KINDS;
2314
+
2315
+ exports.GUARD_PREDICATE_VARS = GUARD_PREDICATE_VARS;
2316
+
2317
+ exports.GroupSchema = GroupSchema;
2318
+
2319
+ exports.InstanceNotFoundError = InstanceNotFoundError;
2320
+
2321
+ exports.RESERVED_CONDITION_VARS = RESERVED_CONDITION_VARS;
2322
+
2323
+ exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
2324
+
2325
+ exports.StoredFieldOpSchema = StoredFieldOpSchema;
2326
+
2327
+ exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
2328
+
2329
+ exports.WorkflowConfigSchema = WorkflowConfigSchema;
2330
+
2331
+ exports.WorkflowError = WorkflowError;
2332
+
2333
+ exports.actorFulfillsRole = actorFulfillsRole;
2334
+
2335
+ exports.andConditions = andConditions;
2336
+
2337
+ exports.checkFieldValue = checkFieldValue;
2338
+
2339
+ exports.checkWorkflowInvariants = checkWorkflowInvariants;
2340
+
2341
+ exports.clientConfigFromResource = clientConfigFromResource;
2342
+
2343
+ exports.conditionEffectReads = conditionEffectReads;
2344
+
2345
+ exports.conditionParameterNames = conditionParameterNames;
2346
+
2347
+ exports.conditionSyntaxIssues = conditionSyntaxIssues;
2348
+
2349
+ exports.datasetResourceParts = datasetResourceParts;
2350
+
2351
+ exports.definitionDocId = definitionDocId;
2352
+
2353
+ exports.errorMessage = errorMessage;
2354
+
2355
+ exports.evaluateCondition = evaluateCondition;
2356
+
2357
+ exports.evaluateConditionOutcome = evaluateConditionOutcome;
2358
+
2359
+ exports.evaluatePredicates = evaluatePredicates;
2360
+
2361
+ exports.expandRequiredRoles = expandRequiredRoles;
2362
+
2363
+ exports.extractDocumentId = extractDocumentId;
2364
+
2365
+ exports.formatIssuePath = formatIssuePath;
2366
+
2367
+ exports.formatIssues = formatIssues;
2368
+
2369
+ exports.formatValidationError = formatValidationError;
2370
+
2371
+ exports.gdrFromResource = gdrFromResource;
2372
+
2373
+ exports.gdrRef = gdrRef;
2374
+
2375
+ exports.gdrResourcePrefix = gdrResourcePrefix;
2376
+
2377
+ exports.gdrUri = gdrUri;
2378
+
2379
+ exports.groupMembershipNames = groupMembershipNames;
2380
+
2381
+ exports.isBareSeedId = isBareSeedId;
2382
+
2383
+ exports.isGdr = isGdr;
2384
+
2385
+ exports.isGdrUri = isGdrUri;
2386
+
2387
+ exports.isGuardReadExpr = isGuardReadExpr;
2388
+
2389
+ exports.isNotesEntry = isNotesEntry;
2390
+
2391
+ exports.isStartableDefinition = isStartableDefinition;
2392
+
2393
+ exports.isTerminalActivityStatus = isTerminalActivityStatus;
2394
+
2395
+ exports.isTodoListEntry = isTodoListEntry;
2396
+
2397
+ exports.isTodoListItem = isTodoListItem;
2398
+
2399
+ exports.isUnevaluable = isUnevaluable;
2400
+
2401
+ exports.labelFor = labelFor;
2402
+
2403
+ exports.normalizeRoleAliases = normalizeRoleAliases;
2404
+
2405
+ exports.parseGdr = parseGdr;
2406
+
2407
+ exports.parseOrThrow = parseOrThrow;
2408
+
2409
+ exports.parseResourceGdr = parseResourceGdr;
2410
+
2411
+ exports.parseStoredDefinition = parseStoredDefinition;
2412
+
2413
+ exports.printGuardRead = printGuardRead;
2414
+
2415
+ exports.refCanvas = refCanvas;
2416
+
2417
+ exports.refDashboard = refDashboard;
2418
+
2419
+ exports.refDataset = refDataset;
2420
+
2421
+ exports.refMediaLibrary = refMediaLibrary;
2422
+
2423
+ exports.refTypeIssues = refTypeIssues;
2424
+
2425
+ exports.rejectedRefTypes = rejectedRefTypes;
2426
+
2427
+ exports.releaseDocId = releaseDocId;
2428
+
2429
+ exports.releaseRef = releaseRef;
2430
+
2431
+ exports.resourceAliasesToMap = resourceAliasesToMap;
2432
+
2433
+ exports.resourceFromGdrUri = resourceFromGdrUri;
2434
+
2435
+ exports.resourceFromParsed = resourceFromParsed;
2436
+
2437
+ exports.resourceGdr = resourceGdr;
2438
+
2439
+ exports.rethrowWithContext = rethrowWithContext;
2440
+
2441
+ exports.runGroq = runGroq;
2442
+
2443
+ exports.sameResource = sameResource;
2444
+
2445
+ exports.selfGdr = selfGdr;
2446
+
2447
+ exports.tagScopeFilter = tagScopeFilter;
2448
+
2449
+ exports.toBareId = toBareId;
2450
+
2451
+ exports.toPhysicalGdr = toPhysicalGdr;
2452
+
2453
+ exports.tryParseGdr = tryParseGdr;
2454
+
2455
+ exports.validateFieldAppendItem = validateFieldAppendItem;
2456
+
2457
+ exports.validateFieldValue = validateFieldValue;
2458
+
2459
+ exports.validateResourceAliasName = validateResourceAliasName;
2460
+
2461
+ exports.validateTag = validateTag;