@sanity/workflow-engine-test 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +18 -8
- package/dist/index.cjs +141 -5707
- package/dist/index.d.cts +133 -796
- package/dist/index.d.ts +133 -796
- package/dist/index.js +140 -5700
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,46 +1,45 @@
|
|
|
1
1
|
import type { AbortInstanceArgs } from "@sanity/workflow-engine";
|
|
2
2
|
import { ActivityStatus } from "@sanity/workflow-engine";
|
|
3
3
|
import { Actor } from "@sanity/workflow-engine";
|
|
4
|
-
import {
|
|
4
|
+
import { ChildrenArgs } from "@sanity/workflow-engine";
|
|
5
5
|
import { Clock } from "@sanity/workflow-engine";
|
|
6
6
|
import type { CompleteEffectArgs } from "@sanity/workflow-engine";
|
|
7
7
|
import { CreateEngineArgs } from "@sanity/workflow-engine";
|
|
8
8
|
import type { DeclaredExecutionContext } from "@sanity/workflow-engine";
|
|
9
|
+
import { DefinitionsForDocumentArgs } from "@sanity/workflow-engine";
|
|
10
|
+
import type { DeleteDefinitionArgs } from "@sanity/workflow-engine";
|
|
11
|
+
import { DeleteDefinitionResult } from "@sanity/workflow-engine";
|
|
9
12
|
import { DeployDefinitionsArgs } from "@sanity/workflow-engine";
|
|
10
13
|
import { DeployDefinitionsResult } from "@sanity/workflow-engine";
|
|
11
14
|
import { DeployedDefinition } from "@sanity/workflow-engine";
|
|
12
15
|
import type { EditFieldArgs } from "@sanity/workflow-engine";
|
|
13
16
|
import { Engine } from "@sanity/workflow-engine";
|
|
14
17
|
import type { EvaluateArgs } from "@sanity/workflow-engine";
|
|
18
|
+
import { EvaluateStartArgs } from "@sanity/workflow-engine";
|
|
19
|
+
import { FindPendingEffectsArgs } from "@sanity/workflow-engine";
|
|
15
20
|
import type { FireActionArgs } from "@sanity/workflow-engine";
|
|
16
|
-
import { GdrUri } from "@sanity/workflow-engine";
|
|
17
21
|
import type { Grant } from "@sanity/workflow-engine";
|
|
18
22
|
import { InitialFieldValue } from "@sanity/workflow-engine";
|
|
23
|
+
import { InstanceRefArgs } from "@sanity/workflow-engine";
|
|
24
|
+
import { InstancesForDocumentArgs } from "@sanity/workflow-engine";
|
|
25
|
+
import { InstancesQueryFilter } from "@sanity/workflow-engine";
|
|
19
26
|
import { MutationGuardAction } from "@sanity/workflow-engine";
|
|
20
27
|
import { MutationGuardDoc } from "@sanity/workflow-engine";
|
|
21
28
|
import type { OperationArgs } from "@sanity/workflow-engine";
|
|
22
29
|
import { OperationResult } from "@sanity/workflow-engine";
|
|
23
30
|
import { PendingEffect } from "@sanity/workflow-engine";
|
|
31
|
+
import type { ResourceClientResolver } from "@sanity/workflow-engine";
|
|
24
32
|
import type { SetStageArgs } from "@sanity/workflow-engine";
|
|
33
|
+
import { StartEvaluation } from "@sanity/workflow-engine";
|
|
25
34
|
import type { StartInstanceArgs } from "@sanity/workflow-engine";
|
|
35
|
+
import type { TestClient } from "@sanity-labs/client-fake-for-test";
|
|
26
36
|
import type { WorkflowAccess } from "@sanity/workflow-engine";
|
|
37
|
+
import { WorkflowDefinition } from "@sanity/workflow-engine";
|
|
27
38
|
import { WorkflowDefinitionInput } from "@sanity/workflow-engine";
|
|
28
39
|
import { WorkflowEvaluation } from "@sanity/workflow-engine";
|
|
29
40
|
import { WorkflowInstance } from "@sanity/workflow-engine";
|
|
30
41
|
import type { WorkflowResource } from "@sanity/workflow-engine";
|
|
31
42
|
|
|
32
|
-
declare type Action = ReleaseAction | VersionAction;
|
|
33
|
-
|
|
34
|
-
/** Options for `action()`. Only `tag` is meaningful to the fake. */
|
|
35
|
-
declare interface ActionOptions {
|
|
36
|
-
/** Request tag, recorded on the {@link CallRecord} (`null` = explicit suppression). */
|
|
37
|
-
tag?: string | null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
declare interface ActionResult {
|
|
41
|
-
transactionId: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
43
|
/**
|
|
45
44
|
* The bench's default identity — wildcard user + wildcard grants,
|
|
46
45
|
* registered as the default token on the bench's fake client so the
|
|
@@ -94,6 +93,9 @@ declare type BenchArgsWithGrants<T> = BenchArgs<T> & {
|
|
|
94
93
|
|
|
95
94
|
declare type BenchCompleteEffectArgs = BenchArgs<CompleteEffectArgs>;
|
|
96
95
|
|
|
96
|
+
declare type BenchDeleteDefinitionArgs =
|
|
97
|
+
BenchArgsWithGrants<DeleteDefinitionArgs>;
|
|
98
|
+
|
|
97
99
|
declare type BenchEditFieldArgs = BenchArgsWithGrants<EditFieldArgs>;
|
|
98
100
|
|
|
99
101
|
declare type BenchEvaluateArgs = BenchArgsWithGrants<EvaluateArgs>;
|
|
@@ -112,6 +114,9 @@ declare interface BenchState {
|
|
|
112
114
|
tag: string;
|
|
113
115
|
/** The workflow resource every wrapped call targets. */
|
|
114
116
|
workflowResource: WorkflowResource;
|
|
117
|
+
/** The cross-resource read routing every wrapped call carries, when the
|
|
118
|
+
* bench declared any — see {@link CreateBenchOptions.resourceClients}. */
|
|
119
|
+
resourceClients?: ResourceClientResolver;
|
|
115
120
|
/** The declared execution context stamped on every wrapped call's history
|
|
116
121
|
* entries (default `{kind: 'test'}`) — inherited by {@link createBenchEngine}. */
|
|
117
122
|
executionContext: DeclaredExecutionContext;
|
|
@@ -146,8 +151,7 @@ declare interface BenchState {
|
|
|
146
151
|
* Freeze the bench clock at an explicit ISO instant. Every subsequent
|
|
147
152
|
* engine call (`startInstance` / `fireAction` / `tick` / `completeEffect`
|
|
148
153
|
* / `evaluate`) sees this as `$now` and stamps it on history, so
|
|
149
|
-
* time-based `
|
|
150
|
-
* deterministic.
|
|
154
|
+
* time-based `when` triggers and SLA predicates are deterministic.
|
|
151
155
|
*/
|
|
152
156
|
setNow: (iso: string) => void;
|
|
153
157
|
/**
|
|
@@ -160,28 +164,6 @@ declare interface BenchState {
|
|
|
160
164
|
|
|
161
165
|
declare type BenchTickArgs = BenchArgs<OperationArgs>;
|
|
162
166
|
|
|
163
|
-
/**
|
|
164
|
-
* One recorded invocation of a client method — the spy layer behind
|
|
165
|
-
* `client.calls()` / `client.callCount()`. `result` holds the resolved
|
|
166
|
-
* value (awaited, for async methods); `error` holds the thrown/rejected
|
|
167
|
-
* value. Builder-returning methods (`patch`, `transaction`) record the
|
|
168
|
-
* builder as `result`; their eventual writes show up in the mutation log.
|
|
169
|
-
*/
|
|
170
|
-
declare interface CallRecord {
|
|
171
|
-
/** Method name; namespace methods are dotted, e.g. `releases.create`. */
|
|
172
|
-
method: string;
|
|
173
|
-
/** Arguments as passed (stored by reference, like `vi.fn`). */
|
|
174
|
-
args: unknown[];
|
|
175
|
-
/** Resolved/returned value, set once the call settles successfully. */
|
|
176
|
-
result?: unknown;
|
|
177
|
-
/** Thrown or rejected value, set if the call failed. */
|
|
178
|
-
error?: unknown;
|
|
179
|
-
/** Request tag from the call's options, when one was passed (`null` = explicit suppression). */
|
|
180
|
-
tag?: string | null;
|
|
181
|
-
projectId: string;
|
|
182
|
-
dataset: string;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
167
|
/** Helpers composed across the wrapper + read groups at bench assembly. */
|
|
186
168
|
declare interface ComposedHelpers {
|
|
187
169
|
/**
|
|
@@ -259,6 +241,23 @@ export declare interface CreateBenchOptions {
|
|
|
259
241
|
* URIs read as `dataset:test:test:<docId>`.
|
|
260
242
|
*/
|
|
261
243
|
workflowResource?: WorkflowResource;
|
|
244
|
+
/**
|
|
245
|
+
* Sibling datasets the bench serves (and thereby declares) from its own
|
|
246
|
+
* store — the common cross-resource case. Each listed resource routes to
|
|
247
|
+
* a `withConfig`-derived handle over the bench's store, so reads reach it
|
|
248
|
+
* and runtime-supplied refs into it are admitted. Only `dataset`
|
|
249
|
+
* resources can be siblings of the bench's store; anything else needs
|
|
250
|
+
* {@link CreateBenchOptions.resourceClients}.
|
|
251
|
+
*/
|
|
252
|
+
serveResources?: WorkflowResource[];
|
|
253
|
+
/**
|
|
254
|
+
* Cross-resource read routing for the bench engine scope — a served
|
|
255
|
+
* resource is also part of the declared surface for written refs. The
|
|
256
|
+
* escape hatch for resolver logic beyond same-store siblings; prefer
|
|
257
|
+
* {@link CreateBenchOptions.serveResources}, which is consulted first
|
|
258
|
+
* when both are given. Omit for single-resource benches.
|
|
259
|
+
*/
|
|
260
|
+
resourceClients?: ResourceClientResolver;
|
|
262
261
|
/**
|
|
263
262
|
* Freeze the bench clock at this ISO instant from construction, so
|
|
264
263
|
* `$now` and every engine timestamp are deterministic. Equivalent to
|
|
@@ -274,35 +273,17 @@ export declare interface CreateBenchOptions {
|
|
|
274
273
|
executionContext?: DeclaredExecutionContext;
|
|
275
274
|
}
|
|
276
275
|
|
|
277
|
-
declare interface CurrentUser {
|
|
278
|
-
id: string;
|
|
279
|
-
name?: string;
|
|
280
|
-
email?: string;
|
|
281
|
-
/** @deprecated singular `role` on legacy responses */
|
|
282
|
-
role?: string;
|
|
283
|
-
roles?: {
|
|
284
|
-
name: string;
|
|
285
|
-
title?: string;
|
|
286
|
-
description?: string;
|
|
287
|
-
}[];
|
|
288
|
-
}
|
|
289
|
-
|
|
290
276
|
/** Default workflow resource for benches that don't pass one. */
|
|
291
277
|
export declare const DEFAULT_WORKFLOW_RESOURCE: WorkflowResource;
|
|
292
278
|
|
|
293
279
|
/**
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
280
|
+
* The write {@link GuardHelpers.editDocument} performs. Every arm is a real
|
|
281
|
+
* distinct client write the guard seam vets under that action — `create` is
|
|
282
|
+
* deliberately absent because editing addresses an existing document; create
|
|
283
|
+
* through the client (`bench.client.create` / `clientFor(...).create`), which
|
|
284
|
+
* the same seam gates as a create.
|
|
298
285
|
*/
|
|
299
|
-
declare
|
|
300
|
-
_id?: string;
|
|
301
|
-
_type: string;
|
|
302
|
-
[field: string]: unknown;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
declare type DocumentValuePermission = "create" | "read" | "update";
|
|
286
|
+
export declare type EditDocumentAction = Exclude<MutationGuardAction, "create">;
|
|
306
287
|
|
|
307
288
|
/**
|
|
308
289
|
* How {@link GuardHelpers.editDocument} mutates the document. Each present
|
|
@@ -324,6 +305,7 @@ declare type EngineScope = {
|
|
|
324
305
|
client: TestClient;
|
|
325
306
|
tag: string;
|
|
326
307
|
workflowResource: WorkflowResource;
|
|
308
|
+
resourceClients?: ResourceClientResolver;
|
|
327
309
|
executionContext: DeclaredExecutionContext;
|
|
328
310
|
};
|
|
329
311
|
|
|
@@ -332,6 +314,9 @@ declare type EngineWrappers = {
|
|
|
332
314
|
deployDefinitions: <T extends WorkflowDefinitionInput<T>>(
|
|
333
315
|
args: DeployDefinitionsArgs<T>,
|
|
334
316
|
) => Promise<DeployDefinitionsResult>;
|
|
317
|
+
deleteDefinition: (
|
|
318
|
+
args: BenchDeleteDefinitionArgs,
|
|
319
|
+
) => Promise<DeleteDefinitionResult>;
|
|
335
320
|
startInstance: (args: BenchStartInstanceArgs) => Promise<OperationResult>;
|
|
336
321
|
fireAction: (args: BenchFireActionArgs) => Promise<OperationResult>;
|
|
337
322
|
editField: (args: BenchEditFieldArgs) => Promise<OperationResult>;
|
|
@@ -346,95 +331,18 @@ declare type EngineWrappers = {
|
|
|
346
331
|
guardsForDefinition: (definition: string) => Promise<MutationGuardDoc[]>;
|
|
347
332
|
};
|
|
348
333
|
|
|
349
|
-
/**
|
|
350
|
-
*
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
| {
|
|
362
|
-
createIfNotExists: SanityDocumentLike;
|
|
363
|
-
}
|
|
364
|
-
| {
|
|
365
|
-
delete: {
|
|
366
|
-
id: string;
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
| {
|
|
370
|
-
patch: {
|
|
371
|
-
id: string;
|
|
372
|
-
ifRevisionID?: string;
|
|
373
|
-
set?: Record<string, unknown>;
|
|
374
|
-
setIfMissing?: Record<string, unknown>;
|
|
375
|
-
unset?: string[];
|
|
376
|
-
inc?: Record<string, number>;
|
|
377
|
-
dec?: Record<string, number>;
|
|
378
|
-
insert?: {
|
|
379
|
-
before?: string;
|
|
380
|
-
after?: string;
|
|
381
|
-
replace?: string;
|
|
382
|
-
items: unknown[];
|
|
383
|
-
};
|
|
384
|
-
};
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Data-plane subset of `@sanity/client`'s surface, with multi-dataset support.
|
|
389
|
-
*
|
|
390
|
-
* One `createTestClient()` call creates a registry of stores keyed by
|
|
391
|
-
* `(projectId, dataset)`. The returned client points at one of them.
|
|
392
|
-
* `withConfig({ projectId, dataset })` returns a new handle into the same
|
|
393
|
-
* registry but pointing at a different store — useful for workflows where
|
|
394
|
-
* definitions live in one dataset and instances live in another.
|
|
395
|
-
*
|
|
396
|
-
* Two separate `createTestClient()` calls have separate registries, so
|
|
397
|
-
* tests stay isolated from each other.
|
|
398
|
-
*
|
|
399
|
-
* Methods not on the real client:
|
|
400
|
-
*
|
|
401
|
-
* - `seed`, `add`, `reset`, `snapshot`, `store` — bulk-load helpers,
|
|
402
|
-
* scoped to the current dataset.
|
|
403
|
-
* - `simulateConcurrentEdit()` — force the next N revision-guarded writes
|
|
404
|
-
* to a document to 409, for optimistic-locking retry tests.
|
|
405
|
-
* - `datasets()` — lists known dataset keys in this registry.
|
|
406
|
-
*
|
|
407
|
-
* Methods deliberately omitted:
|
|
408
|
-
*
|
|
409
|
-
* - Project / agent / asset / live / listen APIs.
|
|
410
|
-
*/
|
|
411
|
-
declare interface FetchOptions {
|
|
412
|
-
/** Override the client's configured perspective for this read. */
|
|
413
|
-
perspective?: Perspective;
|
|
414
|
-
/**
|
|
415
|
-
* When `false`, resolve to a {@link RawQueryResponse} (`{ query, ms,
|
|
416
|
-
* result }`) instead of the bare result — mirrors `@sanity/client`.
|
|
417
|
-
* Defaults to `true`.
|
|
418
|
-
*/
|
|
419
|
-
filterResponse?: boolean;
|
|
420
|
-
/**
|
|
421
|
-
* With `filterResponse: false`, set to `false` to omit `query` from the
|
|
422
|
-
* raw response. Ignored when `filterResponse` is not `false`.
|
|
423
|
-
*/
|
|
424
|
-
returnQuery?: boolean;
|
|
425
|
-
/**
|
|
426
|
-
* Request tag, recorded on the {@link CallRecord} for assertions.
|
|
427
|
-
* `null` mirrors `@sanity/client`'s explicit-suppression form and is
|
|
428
|
-
* recorded as-is. No other behavior is simulated.
|
|
429
|
-
*/
|
|
430
|
-
tag?: string | null;
|
|
431
|
-
/** Accepted for signature parity; not simulated. */
|
|
432
|
-
signal?: AbortSignal;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
declare interface Grant_2 {
|
|
436
|
-
filter: string;
|
|
437
|
-
permissions: DocumentValuePermission[];
|
|
334
|
+
/** The slice of a bench {@link startedInstanceFixture} drives — structural,
|
|
335
|
+
* so the fixture module needs no import of the bench itself. */
|
|
336
|
+
declare interface FixtureBench {
|
|
337
|
+
deployDefinitions: (args: {
|
|
338
|
+
definitions: WorkflowDefinition[];
|
|
339
|
+
}) => Promise<unknown>;
|
|
340
|
+
startInstance: (args: {
|
|
341
|
+
definition: string;
|
|
342
|
+
instanceId?: string;
|
|
343
|
+
}) => Promise<{
|
|
344
|
+
instance: WorkflowInstance;
|
|
345
|
+
}>;
|
|
438
346
|
}
|
|
439
347
|
|
|
440
348
|
declare type GuardHelpers = {
|
|
@@ -454,137 +362,28 @@ declare type GuardHelpers = {
|
|
|
454
362
|
* client gates the write against deployed guards (incl. `identity()`) and
|
|
455
363
|
* throws `MutationGuardDeniedError` on denial — the lake's intended
|
|
456
364
|
* rejection, simulated by the bench. `as` routes the write through a
|
|
457
|
-
* token-scoped sibling so `identity()` resolves to that actor.
|
|
458
|
-
*
|
|
459
|
-
*
|
|
365
|
+
* token-scoped sibling so `identity()` resolves to that actor.
|
|
366
|
+
*
|
|
367
|
+
* Each {@link EditDocumentAction} performs that real write, so a guard
|
|
368
|
+
* scoped to it is genuinely consulted: `update` (default) applies `patch`;
|
|
369
|
+
* `delete` deletes; `publish` promotes the existing draft
|
|
370
|
+
* (`drafts.<documentId>`) onto `documentId`; `unpublish` retracts
|
|
371
|
+
* `documentId` into its draft. `documentId` is always the published id.
|
|
372
|
+
* A `patch` ({@link EditDocumentPatch}) is required for `update` and
|
|
373
|
+
* rejected for every other action — the combination is contradictory input.
|
|
374
|
+
*
|
|
375
|
+
* Resolves to the post-write document as the DEFAULT identity reads it —
|
|
376
|
+
* `undefined` after `delete`/`unpublish` (the doc is gone), or when the
|
|
377
|
+
* default identity cannot read the written doc.
|
|
460
378
|
*/
|
|
461
379
|
editDocument: (opts: {
|
|
462
380
|
documentId: string;
|
|
463
381
|
patch?: EditDocumentPatch;
|
|
464
|
-
action?:
|
|
382
|
+
action?: EditDocumentAction;
|
|
465
383
|
as?: Actor;
|
|
466
|
-
}) => Promise<StoreDocument>;
|
|
384
|
+
}) => Promise<StoreDocument | undefined>;
|
|
467
385
|
};
|
|
468
386
|
|
|
469
|
-
/** Result of a mutation when ids are requested for all affected documents. */
|
|
470
|
-
declare interface MultipleMutationResult {
|
|
471
|
-
transactionId: string;
|
|
472
|
-
documentIds: string[];
|
|
473
|
-
results: {
|
|
474
|
-
id: string;
|
|
475
|
-
operation: MutationOperation;
|
|
476
|
-
}[];
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/** Append-only record of one committed transaction (a single mutation is a 1-entry transaction). */
|
|
480
|
-
declare interface MutationLogEntry {
|
|
481
|
-
transactionId: string;
|
|
482
|
-
projectId: string;
|
|
483
|
-
dataset: string;
|
|
484
|
-
mutations: TxnMutation[];
|
|
485
|
-
/** Request tag the commit carried, when one was passed (`null` = explicit suppression). */
|
|
486
|
-
tag?: string | null;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/** The operation recorded per affected document, matching `@sanity/client`. */
|
|
490
|
-
declare type MutationOperation = "create" | "update" | "delete" | "none";
|
|
491
|
-
|
|
492
|
-
declare interface MutationOptions {
|
|
493
|
-
ifRevisionId?: string;
|
|
494
|
-
/**
|
|
495
|
-
* Shape the resolved value, mirroring `@sanity/client`:
|
|
496
|
-
* - default → the mutated document
|
|
497
|
-
* - `returnDocuments: false` → an id-shaped mutation result
|
|
498
|
-
* ({@link SingleMutationResult} / {@link MultipleMutationResult})
|
|
499
|
-
* - `returnFirst: false` with documents → an array
|
|
500
|
-
*
|
|
501
|
-
* The static return type reflects the default (the document); pass a
|
|
502
|
-
* type argument or cast when requesting an id-shaped result.
|
|
503
|
-
*/
|
|
504
|
-
returnDocuments?: boolean;
|
|
505
|
-
returnFirst?: boolean;
|
|
506
|
-
/** Override the synthetic transaction id used in the result and log. */
|
|
507
|
-
transactionId?: string;
|
|
508
|
-
/** When `true`, validate + shape the result but don't persist. */
|
|
509
|
-
dryRun?: boolean;
|
|
510
|
-
/** Accepted for signature parity; not simulated. */
|
|
511
|
-
visibility?: "sync" | "async" | "deferred";
|
|
512
|
-
/** Accepted for signature parity; not simulated. */
|
|
513
|
-
autoGenerateArrayKeys?: boolean;
|
|
514
|
-
/**
|
|
515
|
-
* Request tag, recorded on the {@link CallRecord} and the
|
|
516
|
-
* {@link MutationLogEntry} for assertions. `null` mirrors
|
|
517
|
-
* `@sanity/client`'s explicit-suppression form and is recorded as-is.
|
|
518
|
-
* No other behavior is simulated.
|
|
519
|
-
*/
|
|
520
|
-
tag?: string | null;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/** Options for `PatchHandle.commit()`. Only `tag` is meaningful to the fake. */
|
|
524
|
-
declare interface PatchCommitOptions {
|
|
525
|
-
/** Request tag, recorded on the mutation log entry (`null` = explicit suppression). */
|
|
526
|
-
tag?: string | null;
|
|
527
|
-
/** Accepted for signature parity; not simulated. */
|
|
528
|
-
visibility?: "sync" | "async" | "deferred";
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
declare interface PatchHandle {
|
|
532
|
-
set: (props: Record<string, unknown>) => PatchHandle;
|
|
533
|
-
setIfMissing: (props: Record<string, unknown>) => PatchHandle;
|
|
534
|
-
unset: (paths: string[]) => PatchHandle;
|
|
535
|
-
inc: (props: Record<string, number>) => PatchHandle;
|
|
536
|
-
dec: (props: Record<string, number>) => PatchHandle;
|
|
537
|
-
insert: (
|
|
538
|
-
position: "before" | "after" | "replace",
|
|
539
|
-
anchor: string,
|
|
540
|
-
items: unknown[],
|
|
541
|
-
) => PatchHandle;
|
|
542
|
-
ifRevisionId: (rev: string) => PatchHandle;
|
|
543
|
-
commit: (options?: PatchCommitOptions) => Promise<SanityDocument>;
|
|
544
|
-
/** Test-only introspection — not on real Patch */
|
|
545
|
-
toJSON: () => {
|
|
546
|
-
id: string;
|
|
547
|
-
ops: PatchOp[];
|
|
548
|
-
ifRev?: string;
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Patch operations the test client supports.
|
|
554
|
-
*
|
|
555
|
-
* Subset of `@sanity/client`'s PatchOperations. Each entry is one
|
|
556
|
-
* mutation step applied in order at commit time.
|
|
557
|
-
*/
|
|
558
|
-
declare type PatchOp =
|
|
559
|
-
| {
|
|
560
|
-
kind: "set";
|
|
561
|
-
props: Record<string, unknown>;
|
|
562
|
-
}
|
|
563
|
-
| {
|
|
564
|
-
kind: "setIfMissing";
|
|
565
|
-
props: Record<string, unknown>;
|
|
566
|
-
}
|
|
567
|
-
| {
|
|
568
|
-
kind: "unset";
|
|
569
|
-
paths: string[];
|
|
570
|
-
}
|
|
571
|
-
| {
|
|
572
|
-
kind: "inc";
|
|
573
|
-
props: Record<string, number>;
|
|
574
|
-
}
|
|
575
|
-
| {
|
|
576
|
-
kind: "dec";
|
|
577
|
-
props: Record<string, number>;
|
|
578
|
-
}
|
|
579
|
-
| {
|
|
580
|
-
kind: "insert";
|
|
581
|
-
position: "before" | "after" | "replace";
|
|
582
|
-
anchor: string;
|
|
583
|
-
items: unknown[];
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
declare type Perspective = "raw" | "published" | "drafts" | string[];
|
|
587
|
-
|
|
588
387
|
declare type QueryHelpers = {
|
|
589
388
|
/**
|
|
590
389
|
* Run an arbitrary GROQ query through `workflow.query`. The query MUST
|
|
@@ -598,11 +397,13 @@ declare type QueryHelpers = {
|
|
|
598
397
|
) => Promise<T>;
|
|
599
398
|
/**
|
|
600
399
|
* Snapshot-aware GROQ for `instanceId` — runs against the same
|
|
601
|
-
* in-memory view the engine's filters see
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
400
|
+
* in-memory view the engine's filters see, with the caller-free
|
|
401
|
+
* rendered scope auto-bound: every always-bound condition var,
|
|
402
|
+
* `$fields` with the open stage's overlay merged, `$assigned` at its
|
|
403
|
+
* caller-free `false`, and the author's pre-evaluated `$<predicate>`
|
|
404
|
+
* booleans, ids in GDR URI form. Use to ask "what does the engine see
|
|
405
|
+
* for this workflow?" — useful for filter debugging, UIs that mirror
|
|
406
|
+
* engine state, etc.
|
|
606
407
|
*/
|
|
607
408
|
queryInScope: <T = unknown>({
|
|
608
409
|
instanceId,
|
|
@@ -616,34 +417,35 @@ declare type QueryHelpers = {
|
|
|
616
417
|
};
|
|
617
418
|
|
|
618
419
|
declare type ReadHelpers = {
|
|
619
|
-
/**
|
|
620
|
-
|
|
420
|
+
/**
|
|
421
|
+
* The engine's instance point-read: throws typed `InstanceNotFoundError`
|
|
422
|
+
* when the doc is missing or belongs to another engine's tag partition.
|
|
423
|
+
*/
|
|
424
|
+
getInstance: (args: InstanceRefArgs) => Promise<WorkflowInstance>;
|
|
621
425
|
/** Current stage name of an instance. */
|
|
622
426
|
currentStage: (instanceId: string) => Promise<string>;
|
|
623
|
-
/**
|
|
624
|
-
|
|
427
|
+
/** Every pending effect on an instance — claimed and unclaimed alike. */
|
|
428
|
+
listPendingEffects: (args: InstanceRefArgs) => Promise<PendingEffect[]>;
|
|
429
|
+
/** Pending effects filtered by claim presence and/or effect names. */
|
|
430
|
+
findPendingEffects: (
|
|
431
|
+
args: FindPendingEffectsArgs,
|
|
432
|
+
) => Promise<PendingEffect[]>;
|
|
625
433
|
/** Status of a single activity on an instance, or undefined if missing. */
|
|
626
434
|
activityStatus: (
|
|
627
435
|
instanceId: string,
|
|
628
436
|
activity: string,
|
|
629
437
|
) => Promise<ActivityStatus | undefined>;
|
|
630
|
-
/** The rendered `$
|
|
631
|
-
*
|
|
632
|
-
|
|
438
|
+
/** The rendered `$context` map — the start-time seed + a parent's spawn
|
|
439
|
+
* handoff, keyed by entry `name`. */
|
|
440
|
+
contextMap: (instanceId: string) => Promise<Record<string, unknown>>;
|
|
441
|
+
/** The rendered `$effects` map — completed effects' outputs, namespaced
|
|
442
|
+
* by effect name. */
|
|
443
|
+
effectOutputsMap: (instanceId: string) => Promise<Record<string, unknown>>;
|
|
633
444
|
/**
|
|
634
|
-
* Spawned children of
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
* Walks `history.spawned` entries on the parent — the durable record
|
|
638
|
-
* (the workflow-scope registry tracks the same children, keyed for
|
|
639
|
-
* adoption rather than enumeration).
|
|
640
|
-
*
|
|
641
|
-
* Returns children ordered by `startedAt` ascending.
|
|
445
|
+
* Spawned children of the instance, optionally restricted to those
|
|
446
|
+
* spawned by `activity`. Ordered by `startedAt` ascending.
|
|
642
447
|
*/
|
|
643
|
-
children: (
|
|
644
|
-
parentInstanceId: string,
|
|
645
|
-
activity?: string,
|
|
646
|
-
) => Promise<WorkflowInstance[]>;
|
|
448
|
+
children: (args: ChildrenArgs) => Promise<WorkflowInstance[]>;
|
|
647
449
|
/**
|
|
648
450
|
* All workflow instances whose `doc.ref` field entry named
|
|
649
451
|
* `entryName` (default `"subject"`) matches the given doc id. Useful
|
|
@@ -655,83 +457,45 @@ declare type ReadHelpers = {
|
|
|
655
457
|
entryName?: string,
|
|
656
458
|
) => Promise<WorkflowInstance[]>;
|
|
657
459
|
/**
|
|
658
|
-
* All instances of `
|
|
659
|
-
*
|
|
660
|
-
*
|
|
460
|
+
* All instances of `definition` currently at `stage`. In-flight only by
|
|
461
|
+
* default; `includeCompleted: true` widens to completed/aborted instances.
|
|
462
|
+
* The options derive from the engine's {@link InstancesQueryFilter}, so a
|
|
463
|
+
* vocabulary drift is a compile error here, not a silently-dropped filter.
|
|
661
464
|
*/
|
|
662
|
-
instancesByStage: (
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}) => Promise<WorkflowInstance[]>;
|
|
465
|
+
instancesByStage: (
|
|
466
|
+
options: Required<Pick<InstancesQueryFilter, "definition" | "stage">> &
|
|
467
|
+
Pick<InstancesQueryFilter, "includeCompleted">,
|
|
468
|
+
) => Promise<WorkflowInstance[]>;
|
|
667
469
|
/**
|
|
668
470
|
* Every in-flight instance whose reactive watch-set includes `document`
|
|
669
471
|
* (a resource-qualified GDR URI) — the reverse of the forward watch-set.
|
|
670
472
|
* Answers "which instances should this changed doc `tick`?" the way a
|
|
671
473
|
* non-reactive content forwarder needs. Sorted by `startedAt` ascending.
|
|
672
474
|
*/
|
|
673
|
-
instancesForDocument: (
|
|
475
|
+
instancesForDocument: (
|
|
476
|
+
args: InstancesForDocumentArgs,
|
|
477
|
+
) => Promise<WorkflowInstance[]>;
|
|
674
478
|
/**
|
|
675
479
|
* The startable half of {@link ReadHelpers.instancesForDocument}: the
|
|
676
480
|
* latest deployed version of every definition applicable to the LOADED
|
|
677
481
|
* candidate document — startable, a required subject entry accepts its
|
|
678
|
-
* `_type`, `
|
|
482
|
+
* `_type`, `start.filter` (browse-time-pure) passes. All matches, name
|
|
483
|
+
* ascending.
|
|
679
484
|
*/
|
|
680
485
|
definitionsForDocument: (
|
|
681
|
-
|
|
486
|
+
args: DefinitionsForDocumentArgs,
|
|
682
487
|
) => Promise<DeployedDefinition[]>;
|
|
488
|
+
/**
|
|
489
|
+
* Pre-flight `startInstance`'s gates for a definition + candidate
|
|
490
|
+
* `initialFields`: the `start.allowed` verdict (with its insight) plus the
|
|
491
|
+
* still-missing required inputs — the read a start surface renders before
|
|
492
|
+
* committing.
|
|
493
|
+
*/
|
|
494
|
+
evaluateStart: (args: EvaluateStartArgs) => Promise<StartEvaluation>;
|
|
683
495
|
/** Snapshot of all documents in the store — for inspecting the world. */
|
|
684
496
|
snapshot: () => readonly StoreDocument[];
|
|
685
497
|
};
|
|
686
498
|
|
|
687
|
-
declare type ReleaseAction =
|
|
688
|
-
| {
|
|
689
|
-
actionType: "sanity.action.release.create";
|
|
690
|
-
releaseId: string;
|
|
691
|
-
metadata?: Partial<ReleaseMetadata>;
|
|
692
|
-
}
|
|
693
|
-
| {
|
|
694
|
-
actionType: "sanity.action.release.edit";
|
|
695
|
-
releaseId: string;
|
|
696
|
-
patch: {
|
|
697
|
-
set?: Record<string, unknown>;
|
|
698
|
-
unset?: string[];
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
| {
|
|
702
|
-
actionType: "sanity.action.release.schedule";
|
|
703
|
-
releaseId: string;
|
|
704
|
-
publishAt: string;
|
|
705
|
-
}
|
|
706
|
-
| {
|
|
707
|
-
actionType: "sanity.action.release.unschedule";
|
|
708
|
-
releaseId: string;
|
|
709
|
-
}
|
|
710
|
-
| {
|
|
711
|
-
actionType: "sanity.action.release.publish";
|
|
712
|
-
releaseId: string;
|
|
713
|
-
}
|
|
714
|
-
| {
|
|
715
|
-
actionType: "sanity.action.release.archive";
|
|
716
|
-
releaseId: string;
|
|
717
|
-
}
|
|
718
|
-
| {
|
|
719
|
-
actionType: "sanity.action.release.unarchive";
|
|
720
|
-
releaseId: string;
|
|
721
|
-
}
|
|
722
|
-
| {
|
|
723
|
-
actionType: "sanity.action.release.delete";
|
|
724
|
-
releaseId: string;
|
|
725
|
-
};
|
|
726
|
-
|
|
727
|
-
declare interface ReleaseDocument extends SanityDocument {
|
|
728
|
-
_type: "system.release";
|
|
729
|
-
name: string;
|
|
730
|
-
state: ReleaseState;
|
|
731
|
-
metadata: ReleaseMetadata;
|
|
732
|
-
publishAt?: string;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
499
|
/**
|
|
736
500
|
* A `release.ref` entry pointing at `_.releases.<releaseName>` in the bench's
|
|
737
501
|
* default resource — what a release-targeting workflow's `release` field
|
|
@@ -744,85 +508,19 @@ export declare function releaseField(
|
|
|
744
508
|
},
|
|
745
509
|
): InitialFieldValue;
|
|
746
510
|
|
|
747
|
-
declare interface ReleaseMetadata {
|
|
748
|
-
title?: string;
|
|
749
|
-
description?: string;
|
|
750
|
-
releaseType?: ReleaseType;
|
|
751
|
-
intendedPublishAt?: string;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
declare interface ReleasesHandle {
|
|
755
|
-
create: (params: {
|
|
756
|
-
releaseId: string;
|
|
757
|
-
metadata?: Partial<ReleaseMetadata>;
|
|
758
|
-
}) => Promise<
|
|
759
|
-
ActionResult & {
|
|
760
|
-
releaseId: string;
|
|
761
|
-
metadata: ReleaseMetadata;
|
|
762
|
-
}
|
|
763
|
-
>;
|
|
764
|
-
edit: (params: {
|
|
765
|
-
releaseId: string;
|
|
766
|
-
patch: {
|
|
767
|
-
set?: Record<string, unknown>;
|
|
768
|
-
unset?: string[];
|
|
769
|
-
};
|
|
770
|
-
}) => Promise<ActionResult>;
|
|
771
|
-
get: (params: { releaseId: string }) => Promise<ReleaseDocument | undefined>;
|
|
772
|
-
fetchDocuments: (params: { releaseId: string }) => Promise<SanityDocument[]>;
|
|
773
|
-
schedule: (params: {
|
|
774
|
-
releaseId: string;
|
|
775
|
-
publishAt: string;
|
|
776
|
-
}) => Promise<ActionResult>;
|
|
777
|
-
unschedule: (params: { releaseId: string }) => Promise<ActionResult>;
|
|
778
|
-
publish: (params: { releaseId: string }) => Promise<ActionResult>;
|
|
779
|
-
archive: (params: { releaseId: string }) => Promise<ActionResult>;
|
|
780
|
-
unarchive: (params: { releaseId: string }) => Promise<ActionResult>;
|
|
781
|
-
delete: (params: { releaseId: string }) => Promise<ActionResult>;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
declare type ReleaseState = "active" | "scheduled" | "published" | "archived";
|
|
785
|
-
|
|
786
|
-
declare type ReleaseType = "asap" | "scheduled" | "undecided";
|
|
787
|
-
|
|
788
|
-
/** @public */
|
|
789
|
-
declare interface SanityDocument {
|
|
790
|
-
_id: string;
|
|
791
|
-
_type: string;
|
|
792
|
-
_createdAt: string;
|
|
793
|
-
_updatedAt: string;
|
|
794
|
-
_rev: string;
|
|
795
|
-
[key: string]: unknown;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
511
|
/**
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
*
|
|
512
|
+
* A REAL, minimal started instance — deployed and started through the bench's
|
|
513
|
+
* actual verbs, parked forever on its first stage. The fixture for consumers
|
|
514
|
+
* (adapter tests, validation tests) that need a persisted-shape-valid
|
|
515
|
+
* instance document without caring about its workflow: hand-crafted instance
|
|
516
|
+
* stubs do not pass the engine's read parse.
|
|
804
517
|
*/
|
|
805
|
-
declare
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
_system?: {
|
|
812
|
-
delete?: boolean;
|
|
813
|
-
};
|
|
814
|
-
[key: string]: unknown;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
/** Result of a mutation when `returnFirst` resolves true and ids are requested. */
|
|
818
|
-
declare interface SingleMutationResult {
|
|
819
|
-
transactionId: string;
|
|
820
|
-
documentId: string;
|
|
821
|
-
results: {
|
|
822
|
-
id: string;
|
|
823
|
-
operation: MutationOperation;
|
|
824
|
-
}[];
|
|
825
|
-
}
|
|
518
|
+
export declare function startedInstanceFixture(
|
|
519
|
+
bench: FixtureBench,
|
|
520
|
+
opts?: {
|
|
521
|
+
instanceId?: string;
|
|
522
|
+
},
|
|
523
|
+
): Promise<WorkflowInstance>;
|
|
826
524
|
|
|
827
525
|
/** A document as stored in the bench's fake lake. */
|
|
828
526
|
declare type StoreDocument = {
|
|
@@ -844,367 +542,6 @@ export declare function subjectField(
|
|
|
844
542
|
},
|
|
845
543
|
): InitialFieldValue;
|
|
846
544
|
|
|
847
|
-
declare interface SystemFields {
|
|
848
|
-
_rev: string;
|
|
849
|
-
_createdAt: string;
|
|
850
|
-
_updatedAt: string;
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
declare interface TestClient {
|
|
854
|
-
fetch: <T = unknown>(
|
|
855
|
-
query: string,
|
|
856
|
-
params?: Record<string, unknown>,
|
|
857
|
-
options?: FetchOptions,
|
|
858
|
-
) => Promise<T>;
|
|
859
|
-
getDocument: <T = SanityDocument>(
|
|
860
|
-
id: string,
|
|
861
|
-
options?: FetchOptions,
|
|
862
|
-
) => Promise<T | undefined>;
|
|
863
|
-
getDocuments: <T = SanityDocument>(
|
|
864
|
-
ids: string[],
|
|
865
|
-
options?: FetchOptions,
|
|
866
|
-
) => Promise<(T | null)[]>;
|
|
867
|
-
/**
|
|
868
|
-
* Sanity-style HTTP request hook. Present iff the handle has an
|
|
869
|
-
* acting identity — created with `accessControl`, or bound to a
|
|
870
|
-
* registered token (`identities` + `token`). The engine's access
|
|
871
|
-
* resolver pokes `/users/me` and the configured ACL path through
|
|
872
|
-
* this — without it the engine throws on any verb that needs an
|
|
873
|
-
* actor.
|
|
874
|
-
*/
|
|
875
|
-
request?: <T>(opts: {
|
|
876
|
-
url?: string;
|
|
877
|
-
uri?: string;
|
|
878
|
-
signal?: AbortSignal;
|
|
879
|
-
tag?: string | null;
|
|
880
|
-
}) => Promise<T>;
|
|
881
|
-
create: <T extends SanityDocumentLike>(
|
|
882
|
-
doc: T,
|
|
883
|
-
options?: MutationOptions,
|
|
884
|
-
) => Promise<T & SystemFields>;
|
|
885
|
-
createOrReplace: <T extends SanityDocumentLike>(
|
|
886
|
-
doc: T,
|
|
887
|
-
options?: MutationOptions,
|
|
888
|
-
) => Promise<T & SystemFields>;
|
|
889
|
-
createIfNotExists: <T extends SanityDocumentLike>(
|
|
890
|
-
doc: T,
|
|
891
|
-
options?: MutationOptions,
|
|
892
|
-
) => Promise<T & SystemFields>;
|
|
893
|
-
delete: (
|
|
894
|
-
id: string,
|
|
895
|
-
options?: MutationOptions,
|
|
896
|
-
) => Promise<{
|
|
897
|
-
_id: string;
|
|
898
|
-
} | null>;
|
|
899
|
-
patch: (documentId: string) => PatchHandle;
|
|
900
|
-
transaction: () => TransactionHandle;
|
|
901
|
-
/**
|
|
902
|
-
* Apply a batch of mutations in the raw array form (or a `patch()` /
|
|
903
|
-
* `transaction()` builder) — mirrors `@sanity/client`'s `mutate()`.
|
|
904
|
-
* Atomic: any failure rolls the whole batch back. The resolved shape
|
|
905
|
-
* follows `options.returnDocuments` / `returnFirst` exactly like the
|
|
906
|
-
* real client (default → {@link MultipleMutationResult}).
|
|
907
|
-
*/
|
|
908
|
-
mutate: (
|
|
909
|
-
operations: FakeMutation[] | PatchHandle | TransactionHandle,
|
|
910
|
-
options?: TxnCommitOptions,
|
|
911
|
-
) => Promise<TxnCommitResult>;
|
|
912
|
-
/**
|
|
913
|
-
* Dispatch one or more release / version actions against the store.
|
|
914
|
-
* Returns a synthetic `transactionId`. Multi-action arrays are applied
|
|
915
|
-
* atomically — any failure rolls back the batch.
|
|
916
|
-
*/
|
|
917
|
-
action: (
|
|
918
|
-
action: Action | Action[],
|
|
919
|
-
options?: ActionOptions,
|
|
920
|
-
) => Promise<ActionResult>;
|
|
921
|
-
/** Helpers mirroring `@sanity/client`'s `client.releases.*` surface. */
|
|
922
|
-
releases: ReleasesHandle;
|
|
923
|
-
/** Helper for `sanity.action.document.version.create`. */
|
|
924
|
-
createVersion: (params: {
|
|
925
|
-
releaseId: string;
|
|
926
|
-
publishedId: string;
|
|
927
|
-
document: DocumentBody;
|
|
928
|
-
}) => Promise<ActionResult>;
|
|
929
|
-
/** Helper for `sanity.action.document.version.unpublish`. */
|
|
930
|
-
unpublishVersion: (params: {
|
|
931
|
-
releaseId: string;
|
|
932
|
-
publishedId: string;
|
|
933
|
-
}) => Promise<ActionResult>;
|
|
934
|
-
/**
|
|
935
|
-
* Current `(projectId, dataset)` and active perspective. `token` is
|
|
936
|
-
* present iff the handle is bound to a registered identity.
|
|
937
|
-
*/
|
|
938
|
-
config: () => {
|
|
939
|
-
projectId: string;
|
|
940
|
-
dataset: string;
|
|
941
|
-
perspective: Perspective;
|
|
942
|
-
token?: string;
|
|
943
|
-
};
|
|
944
|
-
/**
|
|
945
|
-
* Return a new client handle pointing at a different `(projectId, dataset)`
|
|
946
|
-
* within the SAME backing registry. Either field can be omitted to keep
|
|
947
|
-
* the current value. Two clients produced by `withConfig` see each
|
|
948
|
-
* other's writes if they point at the same `(projectId, dataset)`.
|
|
949
|
-
*/
|
|
950
|
-
withConfig: (
|
|
951
|
-
config: Partial<{
|
|
952
|
-
projectId: string;
|
|
953
|
-
dataset: string;
|
|
954
|
-
perspective: Perspective;
|
|
955
|
-
/**
|
|
956
|
-
* Rebind the acting identity (and its grants) on a sibling that shares
|
|
957
|
-
* the same store — the test analogue of a token-scoped client. Lets two
|
|
958
|
-
* actors write the same dataset, e.g. for `identity()`-based guards.
|
|
959
|
-
* Mutually exclusive with `token`.
|
|
960
|
-
*/
|
|
961
|
-
accessControl: TestClientAccessControl;
|
|
962
|
-
/**
|
|
963
|
-
* Bind the sibling to a token registered in the family's identity
|
|
964
|
-
* registry (`createTestClient({ identities })` / `addIdentity`): its
|
|
965
|
-
* `/users/me` serves that identity's user, its ACL path serves that
|
|
966
|
-
* identity's grants, and reads/writes are gated through them — the
|
|
967
|
-
* token determines identity, exactly like production. Unknown tokens
|
|
968
|
-
* throw. Mutually exclusive with `accessControl`.
|
|
969
|
-
*/
|
|
970
|
-
token: string;
|
|
971
|
-
}>,
|
|
972
|
-
) => TestClient;
|
|
973
|
-
/** Replace the current dataset with the given documents. */
|
|
974
|
-
seed: (documents: SanityDocumentLike[]) => void;
|
|
975
|
-
/** Add documents to the current dataset without dropping existing ones. */
|
|
976
|
-
add: (documents: SanityDocumentLike[]) => void;
|
|
977
|
-
/** Drop all documents in the current dataset. */
|
|
978
|
-
reset: () => void;
|
|
979
|
-
/** Read-only snapshot of all documents in the current dataset. */
|
|
980
|
-
snapshot: () => readonly SanityDocument[];
|
|
981
|
-
/** Direct store access for the current dataset. */
|
|
982
|
-
store: () => TestStore;
|
|
983
|
-
/**
|
|
984
|
-
* Simulate `count` concurrent edits to `id` in the current dataset: the
|
|
985
|
-
* next `count` revision-guarded mutations (those passing `ifRevisionId`)
|
|
986
|
-
* to that document throw a 409-shaped conflict, as if another client
|
|
987
|
-
* committed between the caller's read and write. Mutations that don't
|
|
988
|
-
* pass `ifRevisionId` are unaffected.
|
|
989
|
-
*
|
|
990
|
-
* Reach for this when the code under test reads a document's `_rev` and
|
|
991
|
-
* commits with `ifRevisionId` internally — so you can't stage the race
|
|
992
|
-
* by mutating the document first (the code would just re-read the new
|
|
993
|
-
* revision and its commit would match). The counter is consumed one per
|
|
994
|
-
* guarded commit, so `count` lets a test drive a recover-after-N-losses
|
|
995
|
-
* path or exhaust a retry budget, deterministically and without relying
|
|
996
|
-
* on promise interleaving.
|
|
997
|
-
*
|
|
998
|
-
* Note: this forces the conflict *outcome* — it short-circuits the
|
|
999
|
-
* revision comparison rather than changing the stored `_rev`. The code
|
|
1000
|
-
* under test sees the identical 409 error a real lost race produces; the
|
|
1001
|
-
* stored revision is left untouched.
|
|
1002
|
-
*/
|
|
1003
|
-
simulateConcurrentEdit: (id: string, count?: number) => void;
|
|
1004
|
-
/** List `(projectId, dataset)` pairs known in this registry. */
|
|
1005
|
-
datasets: () => {
|
|
1006
|
-
projectId: string;
|
|
1007
|
-
dataset: string;
|
|
1008
|
-
}[];
|
|
1009
|
-
/**
|
|
1010
|
-
* Register a handler for a `@sanity/client` member the fake doesn't
|
|
1011
|
-
* implement (e.g. `listen`, `assets`). Accessing that member on the
|
|
1012
|
-
* client then returns the handler instead of throwing the
|
|
1013
|
-
* "not implemented" guard error. Shared across sibling `withConfig`
|
|
1014
|
-
* handles. Stubs fill gaps only — they don't shadow implemented methods.
|
|
1015
|
-
*/
|
|
1016
|
-
stub: (name: string, handler: unknown) => void;
|
|
1017
|
-
/** The currently-registered stubs, keyed by member name. */
|
|
1018
|
-
stubs: () => Record<string, unknown>;
|
|
1019
|
-
/**
|
|
1020
|
-
* Register (or upsert) a token→identity entry in the family's shared
|
|
1021
|
-
* registry. Siblings already bound to `token` resolve lazily, so a
|
|
1022
|
-
* re-registration takes effect on them immediately. Registering an
|
|
1023
|
-
* identity does not bind it — pass `token` at `createTestClient` or
|
|
1024
|
-
* `withConfig({ token })` to act as it.
|
|
1025
|
-
*/
|
|
1026
|
-
addIdentity: (token: string, identity: TestClientIdentity) => void;
|
|
1027
|
-
/** Snapshot of the registered token→identity entries. */
|
|
1028
|
-
identities: () => Record<string, TestClientIdentity>;
|
|
1029
|
-
/**
|
|
1030
|
-
* Every mutation committed through this client's registry, flattened
|
|
1031
|
-
* and in order — `create` / `createOrReplace` / `createIfNotExists` /
|
|
1032
|
-
* `delete` / `patch`, whether issued directly, via `transaction()`, or
|
|
1033
|
-
* via `mutate()`. The spy hook for "assert exactly what writes my code
|
|
1034
|
-
* submitted".
|
|
1035
|
-
*/
|
|
1036
|
-
mutations: () => TxnMutation[];
|
|
1037
|
-
/**
|
|
1038
|
-
* Every committed transaction, in order. A direct mutation is recorded
|
|
1039
|
-
* as a one-mutation transaction. Each entry carries its synthetic
|
|
1040
|
-
* `transactionId` and the `(projectId, dataset)` it targeted.
|
|
1041
|
-
*/
|
|
1042
|
-
transactions: () => MutationLogEntry[];
|
|
1043
|
-
/** Clear the recorded mutation / transaction log. */
|
|
1044
|
-
clearLog: () => void;
|
|
1045
|
-
/**
|
|
1046
|
-
* Every recorded method call, in order — the spy layer for "was `fetch`
|
|
1047
|
-
* called, how many times, and with what params". Records the
|
|
1048
|
-
* `@sanity/client`-surface methods (`fetch`, `getDocument`, `create`,
|
|
1049
|
-
* `patch`, `mutate`, `releases.*`, …), not the test-only helpers.
|
|
1050
|
-
* Pass a method name to filter (e.g. `calls("fetch")`); namespace
|
|
1051
|
-
* methods are dotted (`calls("releases.create")`). Shared across
|
|
1052
|
-
* `withConfig` siblings.
|
|
1053
|
-
*/
|
|
1054
|
-
calls: (method?: string) => CallRecord[];
|
|
1055
|
-
/** Number of recorded calls, optionally filtered by method name. */
|
|
1056
|
-
callCount: (method?: string) => number;
|
|
1057
|
-
/** Clear the recorded call log. */
|
|
1058
|
-
clearCalls: () => void;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
declare interface TestClientAccessControl {
|
|
1062
|
-
/** What `client.request({ url: "/users/me" })` returns. */
|
|
1063
|
-
currentUser: CurrentUser;
|
|
1064
|
-
/** What `client.request({ url: aclPath })` returns. */
|
|
1065
|
-
grants: Grant_2[];
|
|
1066
|
-
/**
|
|
1067
|
-
* URL path the engine's access resolver hits to fetch grants.
|
|
1068
|
-
* Defaults to `/projects/<projectId>/datasets/<dataset>/acl`.
|
|
1069
|
-
*/
|
|
1070
|
-
aclPath?: string;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
/**
|
|
1074
|
-
* One entry in the token→identity registry (`createTestClient({ identities })`).
|
|
1075
|
-
* A handle bound to the entry's token behaves exactly like one configured
|
|
1076
|
-
* with `accessControl: { currentUser: user, grants }` — `/users/me` serves
|
|
1077
|
-
* `user`, the default ACL path serves `grants`, and reads/writes are gated
|
|
1078
|
-
* through them.
|
|
1079
|
-
*/
|
|
1080
|
-
declare interface TestClientIdentity {
|
|
1081
|
-
/** What `/users/me` returns for clients bound to this token. */
|
|
1082
|
-
user: CurrentUser;
|
|
1083
|
-
/** Grants served at the ACL path and enforced on reads/writes. */
|
|
1084
|
-
grants: Grant_2[];
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
/**
|
|
1088
|
-
* In-memory document store backing a TestClient. Closure-scoped — created
|
|
1089
|
-
* fresh per test, no global state.
|
|
1090
|
-
*
|
|
1091
|
-
* The shape mirrors what `groq-js` evaluates against: an array of
|
|
1092
|
-
* documents. Internally we keep a Map by `_id` for O(1) lookup, and
|
|
1093
|
-
* project to an array on each query.
|
|
1094
|
-
*/
|
|
1095
|
-
declare interface TestStore {
|
|
1096
|
-
/** Replace the entire dataset with the given documents. Existing docs are dropped. */
|
|
1097
|
-
seed: (documents: SanityDocumentLike[]) => void;
|
|
1098
|
-
/** Add documents without dropping existing ones. Conflicts (same _id) overwrite. */
|
|
1099
|
-
add: (documents: SanityDocumentLike[]) => void;
|
|
1100
|
-
/** Remove all documents. */
|
|
1101
|
-
reset: () => void;
|
|
1102
|
-
/** All documents as an array, in insertion order. */
|
|
1103
|
-
all: () => SanityDocument[];
|
|
1104
|
-
/** Get one document by _id, or undefined. */
|
|
1105
|
-
get: (id: string) => SanityDocument | undefined;
|
|
1106
|
-
/** Insert a fully-formed document by _id. Replaces if it already exists. */
|
|
1107
|
-
put: (doc: SanityDocument) => void;
|
|
1108
|
-
/** Remove a document by _id. Returns the removed doc or undefined. */
|
|
1109
|
-
remove: (id: string) => SanityDocument | undefined;
|
|
1110
|
-
/** Snapshot of all docs, useful for assertions. */
|
|
1111
|
-
snapshot: () => readonly SanityDocument[];
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
declare interface TransactionHandle {
|
|
1115
|
-
create: (doc: SanityDocumentLike) => TransactionHandle;
|
|
1116
|
-
createOrReplace: (doc: SanityDocumentLike) => TransactionHandle;
|
|
1117
|
-
createIfNotExists: (doc: SanityDocumentLike) => TransactionHandle;
|
|
1118
|
-
delete: (id: string) => TransactionHandle;
|
|
1119
|
-
/** Accept either a Patch builder (drained at commit) or an inline doc id + ops. */
|
|
1120
|
-
patch: (
|
|
1121
|
-
documentIdOrPatch: string | PatchHandle,
|
|
1122
|
-
ops?: PatchOp[],
|
|
1123
|
-
ifRev?: string,
|
|
1124
|
-
) => TransactionHandle;
|
|
1125
|
-
commit: (options?: TxnCommitOptions) => Promise<TxnCommitResult>;
|
|
1126
|
-
/** Test-only introspection — not on real Transaction. */
|
|
1127
|
-
toJSON: () => TxnMutation[];
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
declare interface TxnCommitOptions {
|
|
1131
|
-
/**
|
|
1132
|
-
* Shape the resolved value (mirrors `@sanity/client`):
|
|
1133
|
-
* - default (both unset) → {@link MultipleMutationResult}
|
|
1134
|
-
* - `returnDocuments: true` → the resulting document(s)
|
|
1135
|
-
* - `returnFirst: true` with `returnDocuments` → a single document
|
|
1136
|
-
* - `returnDocuments: false` → an id-shaped mutation result
|
|
1137
|
-
*/
|
|
1138
|
-
returnDocuments?: boolean;
|
|
1139
|
-
returnFirst?: boolean;
|
|
1140
|
-
/** Override the synthetic transaction id (mirrors `client.transaction(undefined, { transactionId })`). */
|
|
1141
|
-
transactionId?: string;
|
|
1142
|
-
/**
|
|
1143
|
-
* Request tag, recorded on the mutation log entry for assertions.
|
|
1144
|
-
* `null` mirrors `@sanity/client`'s explicit-suppression form and is
|
|
1145
|
-
* recorded as-is. No other behavior is simulated.
|
|
1146
|
-
*/
|
|
1147
|
-
tag?: string | null;
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
declare type TxnCommitResult =
|
|
1151
|
-
| MultipleMutationResult
|
|
1152
|
-
| SingleMutationResult
|
|
1153
|
-
| SanityDocument
|
|
1154
|
-
| SanityDocument[];
|
|
1155
|
-
|
|
1156
|
-
/**
|
|
1157
|
-
* A transaction collects mutations and applies them atomically at commit
|
|
1158
|
-
* time. Mutations are applied in declaration order; if any one fails, the
|
|
1159
|
-
* whole transaction throws and no writes land in the store.
|
|
1160
|
-
*
|
|
1161
|
-
* Subset of `@sanity/client`'s Transaction. Same shape, narrower surface.
|
|
1162
|
-
*/
|
|
1163
|
-
declare type TxnMutation =
|
|
1164
|
-
| {
|
|
1165
|
-
kind: "create";
|
|
1166
|
-
doc: SanityDocumentLike;
|
|
1167
|
-
}
|
|
1168
|
-
| {
|
|
1169
|
-
kind: "createOrReplace";
|
|
1170
|
-
doc: SanityDocumentLike;
|
|
1171
|
-
}
|
|
1172
|
-
| {
|
|
1173
|
-
kind: "createIfNotExists";
|
|
1174
|
-
doc: SanityDocumentLike;
|
|
1175
|
-
}
|
|
1176
|
-
| {
|
|
1177
|
-
kind: "delete";
|
|
1178
|
-
id: string;
|
|
1179
|
-
}
|
|
1180
|
-
| {
|
|
1181
|
-
kind: "patch";
|
|
1182
|
-
documentId: string;
|
|
1183
|
-
ops: PatchOp[];
|
|
1184
|
-
ifRev?: string;
|
|
1185
|
-
};
|
|
1186
|
-
|
|
1187
|
-
declare type VersionAction =
|
|
1188
|
-
| {
|
|
1189
|
-
actionType: "sanity.action.document.version.create";
|
|
1190
|
-
publishedId: string;
|
|
1191
|
-
document: DocumentBody;
|
|
1192
|
-
releaseId?: string;
|
|
1193
|
-
}
|
|
1194
|
-
| {
|
|
1195
|
-
actionType: "sanity.action.document.version.replace";
|
|
1196
|
-
document: SanityDocumentLike;
|
|
1197
|
-
}
|
|
1198
|
-
| {
|
|
1199
|
-
actionType: "sanity.action.document.version.discard";
|
|
1200
|
-
versionId: string;
|
|
1201
|
-
}
|
|
1202
|
-
| {
|
|
1203
|
-
actionType: "sanity.action.document.version.unpublish";
|
|
1204
|
-
versionId: string;
|
|
1205
|
-
publishedId: string;
|
|
1206
|
-
};
|
|
1207
|
-
|
|
1208
545
|
/**
|
|
1209
546
|
* The default grants used when tests don't specify any. A single
|
|
1210
547
|
* permissive grant matches every document and confers all permissions.
|