@sanity/workflow-engine-test 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -3,7 +3,6 @@ import type { CompleteEffectArgs } from "@sanity/workflow-engine";
3
3
  import { DeployDefinitionsArgs } from "@sanity/workflow-engine";
4
4
  import { DeployDefinitionsResult } from "@sanity/workflow-engine";
5
5
  import { DispatchResult } from "@sanity/workflow-engine";
6
- import { EffectsContextEntry } from "@sanity/workflow-engine";
7
6
  import type { EvaluateArgs } from "@sanity/workflow-engine";
8
7
  import type { FireActionArgs } from "@sanity/workflow-engine";
9
8
  import type { Grant } from "@sanity/workflow-engine";
@@ -275,6 +274,7 @@ declare type EngineWrappers = {
275
274
  tick: (args: BenchTickArgs) => Promise<DispatchResult>;
276
275
  evaluate: (args: BenchEvaluateArgs) => Promise<WorkflowEvaluation>;
277
276
  guardsForInstance: (instanceId: string) => Promise<MutationGuardDoc[]>;
277
+ guardsForDefinition: (definition: string) => Promise<MutationGuardDoc[]>;
278
278
  };
279
279
 
280
280
  /**
@@ -527,52 +527,50 @@ declare type QueryHelpers = {
527
527
  declare type ReadHelpers = {
528
528
  /** Read the workflow instance by id. Throws if missing. */
529
529
  getInstance: (instanceId: string) => Promise<WorkflowInstance>;
530
- /** Current stage id of an instance. */
530
+ /** Current stage name of an instance. */
531
531
  currentStage: (instanceId: string) => Promise<string>;
532
532
  /** Pending effects on an instance. */
533
533
  pendingEffects: (instanceId: string) => Promise<PendingEffect[]>;
534
534
  /** Status of a single task on an instance, or undefined if missing. */
535
535
  taskStatus: (
536
536
  instanceId: string,
537
- taskId: string,
537
+ task: string,
538
538
  ) => Promise<TaskStatus | undefined>;
539
- /** EffectsContext entries on an instance, keyed by `key`. */
540
- effectsContextMap: (
541
- instanceId: string,
542
- ) => Promise<Record<string, EffectsContextEntry["value"]>>;
539
+ /** The rendered `$effects` map context entries keyed by `name`,
540
+ * completed-effect outputs namespaced under the effect's name. */
541
+ effectsContextMap: (instanceId: string) => Promise<Record<string, unknown>>;
543
542
  /**
544
- * Spawned children of `parentInstanceId`. If `taskId` is provided,
543
+ * Spawned children of `parentInstanceId`. If `task` is provided,
545
544
  * only children spawned by that specific task on the parent.
546
545
  *
547
546
  * Walks `history.spawned` entries on the parent — this is the durable
548
- * record. (The per-task `spawnedInstances` field on `stages[id == $stage && !defined(exitedAt)][0].tasks[]`
549
- * gets wiped when the parent transitions past the spawning stage,
550
- * since `taskStatus` is rebuilt on every transition.)
547
+ * record. (The per-task `spawnedInstances` field only lives on the
548
+ * open StageEntry's tasks; history survives transitions.)
551
549
  *
552
550
  * Returns children ordered by `startedAt` ascending.
553
551
  */
554
552
  children: (
555
553
  parentInstanceId: string,
556
- taskId?: string,
554
+ task?: string,
557
555
  ) => Promise<WorkflowInstance[]>;
558
556
  /**
559
- * All workflow instances whose `workflow.state.doc.ref` slot named
560
- * `slotId` (default `"subject"`) matches the given doc id. Useful
557
+ * All workflow instances whose `doc.ref` state entry named
558
+ * `entryName` (default `"subject"`) matches the given doc id. Useful
561
559
  * for "what workflow is running on this document?" questions. Pass
562
- * `slotId` for workflows whose subject slot uses a different id.
560
+ * `entryName` for workflows whose subject entry uses a different name.
563
561
  */
564
562
  instancesForSubject: (
565
563
  subjectRef: string,
566
- slotId?: string,
564
+ entryName?: string,
567
565
  ) => Promise<WorkflowInstance[]>;
568
566
  /**
569
- * All instances of `workflowId` currently at `stageId`. Includes
567
+ * All instances of `workflowName` currently at `stage`. Includes
570
568
  * completed instances (`completedAt != null`) by default; set
571
569
  * `{ openOnly: true }` to filter to in-flight only.
572
570
  */
573
571
  instancesByStage: (
574
- workflowId: string,
575
- stageId: string,
572
+ workflowName: string,
573
+ stage: string,
576
574
  options?: {
577
575
  openOnly?: boolean;
578
576
  },
package/dist/index.d.ts CHANGED
@@ -3,7 +3,6 @@ import type { CompleteEffectArgs } from "@sanity/workflow-engine";
3
3
  import { DeployDefinitionsArgs } from "@sanity/workflow-engine";
4
4
  import { DeployDefinitionsResult } from "@sanity/workflow-engine";
5
5
  import { DispatchResult } from "@sanity/workflow-engine";
6
- import { EffectsContextEntry } from "@sanity/workflow-engine";
7
6
  import type { EvaluateArgs } from "@sanity/workflow-engine";
8
7
  import type { FireActionArgs } from "@sanity/workflow-engine";
9
8
  import type { Grant } from "@sanity/workflow-engine";
@@ -275,6 +274,7 @@ declare type EngineWrappers = {
275
274
  tick: (args: BenchTickArgs) => Promise<DispatchResult>;
276
275
  evaluate: (args: BenchEvaluateArgs) => Promise<WorkflowEvaluation>;
277
276
  guardsForInstance: (instanceId: string) => Promise<MutationGuardDoc[]>;
277
+ guardsForDefinition: (definition: string) => Promise<MutationGuardDoc[]>;
278
278
  };
279
279
 
280
280
  /**
@@ -527,52 +527,50 @@ declare type QueryHelpers = {
527
527
  declare type ReadHelpers = {
528
528
  /** Read the workflow instance by id. Throws if missing. */
529
529
  getInstance: (instanceId: string) => Promise<WorkflowInstance>;
530
- /** Current stage id of an instance. */
530
+ /** Current stage name of an instance. */
531
531
  currentStage: (instanceId: string) => Promise<string>;
532
532
  /** Pending effects on an instance. */
533
533
  pendingEffects: (instanceId: string) => Promise<PendingEffect[]>;
534
534
  /** Status of a single task on an instance, or undefined if missing. */
535
535
  taskStatus: (
536
536
  instanceId: string,
537
- taskId: string,
537
+ task: string,
538
538
  ) => Promise<TaskStatus | undefined>;
539
- /** EffectsContext entries on an instance, keyed by `key`. */
540
- effectsContextMap: (
541
- instanceId: string,
542
- ) => Promise<Record<string, EffectsContextEntry["value"]>>;
539
+ /** The rendered `$effects` map context entries keyed by `name`,
540
+ * completed-effect outputs namespaced under the effect's name. */
541
+ effectsContextMap: (instanceId: string) => Promise<Record<string, unknown>>;
543
542
  /**
544
- * Spawned children of `parentInstanceId`. If `taskId` is provided,
543
+ * Spawned children of `parentInstanceId`. If `task` is provided,
545
544
  * only children spawned by that specific task on the parent.
546
545
  *
547
546
  * Walks `history.spawned` entries on the parent — this is the durable
548
- * record. (The per-task `spawnedInstances` field on `stages[id == $stage && !defined(exitedAt)][0].tasks[]`
549
- * gets wiped when the parent transitions past the spawning stage,
550
- * since `taskStatus` is rebuilt on every transition.)
547
+ * record. (The per-task `spawnedInstances` field only lives on the
548
+ * open StageEntry's tasks; history survives transitions.)
551
549
  *
552
550
  * Returns children ordered by `startedAt` ascending.
553
551
  */
554
552
  children: (
555
553
  parentInstanceId: string,
556
- taskId?: string,
554
+ task?: string,
557
555
  ) => Promise<WorkflowInstance[]>;
558
556
  /**
559
- * All workflow instances whose `workflow.state.doc.ref` slot named
560
- * `slotId` (default `"subject"`) matches the given doc id. Useful
557
+ * All workflow instances whose `doc.ref` state entry named
558
+ * `entryName` (default `"subject"`) matches the given doc id. Useful
561
559
  * for "what workflow is running on this document?" questions. Pass
562
- * `slotId` for workflows whose subject slot uses a different id.
560
+ * `entryName` for workflows whose subject entry uses a different name.
563
561
  */
564
562
  instancesForSubject: (
565
563
  subjectRef: string,
566
- slotId?: string,
564
+ entryName?: string,
567
565
  ) => Promise<WorkflowInstance[]>;
568
566
  /**
569
- * All instances of `workflowId` currently at `stageId`. Includes
567
+ * All instances of `workflowName` currently at `stage`. Includes
570
568
  * completed instances (`completedAt != null`) by default; set
571
569
  * `{ openOnly: true }` to filter to in-flight only.
572
570
  */
573
571
  instancesByStage: (
574
- workflowId: string,
575
- stageId: string,
572
+ workflowName: string,
573
+ stage: string,
576
574
  options?: {
577
575
  openOnly?: boolean;
578
576
  },
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { guardsForResource, denyingGuards, MutationGuardDeniedError, workflow, validateTags } from "@sanity/workflow-engine";
1
+ import { guardsForResource, denyingGuards, MutationGuardDeniedError, workflow, WORKFLOW_INSTANCE_TYPE, tagScopeFilter, effectsContextMap, validateTags } from "@sanity/workflow-engine";
2
2
  import require$$0 from "tty";
3
3
  import require$$1 from "util";
4
4
  function escapeRegExp(string2) {
@@ -5047,11 +5047,7 @@ function benchMutationGuard(getClient) {
5047
5047
  ...identity !== void 0 ? { identity } : {}
5048
5048
  });
5049
5049
  if (denied.length > 0)
5050
- throw new MutationGuardDeniedError({
5051
- documentId: id,
5052
- action,
5053
- denied: denied.map((g) => ({ guardId: g._id, ...g.name ? { name: g.name } : {} }))
5054
- });
5050
+ throw MutationGuardDeniedError.fromGuards({ documentId: id, action, guards: denied });
5055
5051
  };
5056
5052
  }
5057
5053
  function resolveBenchClient(options) {
@@ -5100,7 +5096,8 @@ function createEngineWrappers(scope, access, clock) {
5100
5096
  completeEffect: (args) => workflow.completeEffect(withAccess(args)),
5101
5097
  tick: (args) => workflow.tick(withAccess(args)),
5102
5098
  evaluate: (args) => workflow.evaluate(withAccess(args)),
5103
- guardsForInstance: (instanceId) => workflow.guardsForInstance({ ...scope, instanceId })
5099
+ guardsForInstance: (instanceId) => workflow.guardsForInstance({ ...scope, instanceId }),
5100
+ guardsForDefinition: (definition) => workflow.guardsForDefinition({ ...scope, definition })
5104
5101
  };
5105
5102
  }
5106
5103
  function createGuardHelpers(client) {
@@ -5144,42 +5141,38 @@ function createReadHelpers(scope) {
5144
5141
  };
5145
5142
  return {
5146
5143
  getInstance,
5147
- currentStage: async (instanceId) => (await getInstance(instanceId)).currentStageId,
5144
+ currentStage: async (instanceId) => (await getInstance(instanceId)).currentStage,
5148
5145
  pendingEffects: async (instanceId) => (await getInstance(instanceId)).pendingEffects,
5149
- taskStatus: async (instanceId, taskId) => {
5146
+ taskStatus: async (instanceId, task) => {
5150
5147
  const instance = await getInstance(instanceId);
5151
5148
  return instance.stages.find(
5152
- (s) => s.id === instance.currentStageId && s.exitedAt === void 0
5153
- )?.tasks.find((t) => t.id === taskId)?.status;
5154
- },
5155
- effectsContextMap: async (instanceId) => {
5156
- const instance = await getInstance(instanceId), map2 = {};
5157
- for (const entry of instance.effectsContext) map2[entry.id] = entry.value;
5158
- return map2;
5149
+ (s) => s.name === instance.currentStage && s.exitedAt === void 0
5150
+ )?.tasks.find((t) => t.name === task)?.status;
5159
5151
  },
5160
- children: async (parentInstanceId, taskId) => workflow.children({
5152
+ effectsContextMap: async (instanceId) => effectsContextMap(await getInstance(instanceId)),
5153
+ children: async (parentInstanceId, task) => workflow.children({
5161
5154
  ...scope,
5162
5155
  instanceId: parentInstanceId,
5163
- ...taskId !== void 0 ? { taskId } : {}
5156
+ ...task !== void 0 ? { task } : {}
5164
5157
  }),
5165
- instancesForSubject: async (subjectRef, slotId = "subject") => (
5166
- // Subjects live on a workflow-scope `state[id == $slot]` doc.ref
5167
- // slot. Match instances whose slot's value.id equals the supplied
5168
- // ref. The slot id is conventionally "subject" but workflows may
5169
- // name it otherwise.
5158
+ instancesForSubject: async (subjectRef, entryName = "subject") => (
5159
+ // Subjects live on a workflow-scope `doc.ref` state entry. Match
5160
+ // instances whose entry's value.id equals the supplied ref. The
5161
+ // entry name is conventionally "subject" but workflows may name
5162
+ // it otherwise.
5170
5163
  client.fetch(
5171
- `*[_type == "workflow.instance"
5172
- && state[_type == "workflow.state.doc.ref" && id == $slot][0].value.id == $ref
5173
- && count(tags[@ in $engineTags]) > 0] | order(startedAt asc)`,
5174
- { ref: subjectRef, slot: slotId, engineTags: tags }
5164
+ `*[_type == "${WORKFLOW_INSTANCE_TYPE}"
5165
+ && state[_type == "doc.ref" && name == $entry][0].value.id == $ref
5166
+ && ${tagScopeFilter()}] | order(startedAt asc)`,
5167
+ { ref: subjectRef, entry: entryName, engineTags: tags }
5175
5168
  )
5176
5169
  ),
5177
- instancesByStage: async (workflowId, stageId, queryOptions) => {
5170
+ instancesByStage: async (workflowName, stage, queryOptions) => {
5178
5171
  const filter = queryOptions?.openOnly ? " && completedAt == null" : "";
5179
5172
  return client.fetch(
5180
- `*[_type == "workflow.instance" && workflowId == $wf && currentStageId == $stage && count(tags[@ in $engineTags]) > 0${filter}]
5173
+ `*[_type == "${WORKFLOW_INSTANCE_TYPE}" && definition == $wf && currentStage == $stage && ${tagScopeFilter()}${filter}]
5181
5174
  | order(startedAt asc)`,
5182
- { wf: workflowId, stage: stageId, engineTags: tags }
5175
+ { wf: workflowName, stage, engineTags: tags }
5183
5176
  );
5184
5177
  },
5185
5178
  snapshot: () => client.snapshot()