@sanity-labs/client-fake-for-test 0.12.0 → 0.14.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
@@ -38,7 +38,7 @@ export declare function applyPatchOps(
38
38
  */
39
39
  export declare function applyPerspective(
40
40
  docs: readonly SanityDocument[],
41
- perspective: Perspective,
41
+ requested: Perspective,
42
42
  ): SanityDocument[];
43
43
 
44
44
  /**
@@ -61,6 +61,8 @@ export declare interface CallRecord {
61
61
  tag?: string | null;
62
62
  projectId: string;
63
63
  dataset: string;
64
+ /** The resource the call targeted, on a `resource`-configured handle. */
65
+ resource?: TestClientResource;
64
66
  }
65
67
 
66
68
  /** Outcome of a recorded call, reported once a (possibly async) result is known. */
@@ -105,6 +107,27 @@ export declare interface CreateTestClientOptions {
105
107
  * pairs. Useful when workflows span multiple datasets.
106
108
  */
107
109
  datasets?: Record<string, SanityDocumentLike[]>;
110
+ /**
111
+ * Optional: seed any resource type. Keys are `"<type>:<id>"`, the
112
+ * `resource` config's two fields: `"media-library:ml1"`, `"canvas:c1"`,
113
+ * `"dashboard:d1"`, or `"dataset:<projectId>.<dataset>"` (the same store
114
+ * as `datasets["<projectId>:<dataset>"]`).
115
+ */
116
+ resources?: Record<string, SanityDocumentLike[]>;
117
+ /**
118
+ * The resource the root handle points at, named exactly as
119
+ * `@sanity/client`'s `resource` config names it. While set, it decides
120
+ * the store (over `projectId` / `dataset`), and each capability the
121
+ * platform lacks on that resource type answers with the platform's
122
+ * refusal. `withConfig({ resource })` mints siblings on other resources.
123
+ */
124
+ resource?: TestClientResource;
125
+ /**
126
+ * The organization every resource of this client belongs to — what
127
+ * `GET /media-libraries/<id>`, `/canvases/<id>`, `/dashboards/<id>` and
128
+ * `/projects/<projectId>` answer as `organizationId`.
129
+ */
130
+ organizationId?: string;
108
131
  /**
109
132
  * Opt-in access-control simulation. When set, the client exposes
110
133
  * `request({ url })` that serves `/users/me` (host-aware), the
@@ -330,11 +353,14 @@ export declare type FakeMutation =
330
353
  /**
331
354
  * Data-plane subset of `@sanity/client`'s surface, with multi-dataset support.
332
355
  *
333
- * One `createTestClient()` call creates a registry of stores keyed by
334
- * `(projectId, dataset)`. The returned client points at one of them.
335
- * `withConfig({ projectId, dataset })` returns a new handle into the same
336
- * registry but pointing at a different store — useful for workflows where
337
- * definitions live in one dataset and instances live in another.
356
+ * One `createTestClient()` call creates a registry of stores, one per
357
+ * resource: a `(projectId, dataset)` pair, or a Media Library, Canvas or
358
+ * dashboard named by `resource: { type, id }` exactly as `@sanity/client`
359
+ * names it. The returned client points at one of them.
360
+ * `withConfig({ projectId, dataset })` or `withConfig({ resource })` returns
361
+ * a new handle into the same registry but pointing at a different store —
362
+ * useful for workflows where definitions live in one dataset and instances
363
+ * live in another.
338
364
  *
339
365
  * Two separate `createTestClient()` calls have separate registries, so
340
366
  * tests stay isolated from each other.
@@ -345,7 +371,7 @@ export declare type FakeMutation =
345
371
  * scoped to the current dataset.
346
372
  * - `simulateConcurrentEdit()` — force the next N revision-guarded writes
347
373
  * to a document to 409, for optimistic-locking retry tests.
348
- * - `datasets()` — lists known dataset keys in this registry.
374
+ * - `datasets()` / `resources()` — list the stores known in this registry.
349
375
  *
350
376
  * Methods deliberately omitted:
351
377
  *
@@ -425,6 +451,37 @@ export declare interface GuardDeniedResponse {
425
451
  statusMessage: "Forbidden";
426
452
  }
427
453
 
454
+ /** An event as `GET <data base>/history/events/documents/<ids>` serves it. */
455
+ export declare interface HistoryEvent {
456
+ type: "createLiveDocument" | "updateLiveDocument";
457
+ id: string;
458
+ documentId: string;
459
+ revisionId: string;
460
+ timestamp: string;
461
+ author?: string;
462
+ }
463
+
464
+ /** A transaction as `GET <data base>/history/transactions/<ids>` serves it, one per NDJSON line. */
465
+ export declare interface HistoryTransactionRecord {
466
+ id: string;
467
+ timestamp: string;
468
+ author?: string;
469
+ mutations: (
470
+ | {
471
+ create: SanityDocument;
472
+ }
473
+ | {
474
+ createOrReplace: SanityDocument;
475
+ }
476
+ | {
477
+ delete: {
478
+ id: string;
479
+ };
480
+ }
481
+ )[];
482
+ documentIDs: string[];
483
+ }
484
+
428
485
  export declare const isDraftId: (id: string) => boolean;
429
486
 
430
487
  export declare const isReleaseDocId: (id: string) => boolean;
@@ -489,6 +546,8 @@ export declare interface MutationLogEntry {
489
546
  transactionId: string;
490
547
  projectId: string;
491
548
  dataset: string;
549
+ /** The resource the transaction targeted, on a `resource`-configured handle. */
550
+ resource?: TestClientResource;
492
551
  mutations: TxnMutation[];
493
552
  /** Request tag the commit carried, when one was passed (`null` = explicit suppression). */
494
553
  tag?: string | null;
@@ -600,7 +659,46 @@ export declare type PatchOp =
600
659
  items: unknown[];
601
660
  };
602
661
 
603
- export declare type Perspective = "raw" | "published" | "drafts" | string[];
662
+ /**
663
+ * `raw`, `published`, `drafts`, a release stack, or a single release name
664
+ * (`"rSpring"`) — which the Content Lake reads as a one-release stack.
665
+ */
666
+ export declare type Perspective =
667
+ | "raw"
668
+ | "published"
669
+ | "drafts"
670
+ | (string & {})
671
+ | string[];
672
+
673
+ /** The `response` of an HTTP error, shaped like `@sanity/client`'s `HttpError["response"]`. */
674
+ declare interface PlatformErrorResponse {
675
+ body: unknown;
676
+ url: string;
677
+ method: string;
678
+ headers: Record<string, string>;
679
+ statusCode: number;
680
+ statusMessage: string;
681
+ }
682
+
683
+ /**
684
+ * The platform's refusal, shaped like the `ClientError` `@sanity/client`
685
+ * throws for the same response: `statusCode`, `response`, `responseBody`,
686
+ * `details`, and a `message` derived from the body the way the client
687
+ * derives it.
688
+ */
689
+ export declare class PlatformHttpError extends Error {
690
+ readonly statusCode: number;
691
+ readonly response: PlatformErrorResponse;
692
+ readonly responseBody: string;
693
+ readonly details: unknown;
694
+ constructor(args: {
695
+ method: string;
696
+ path: string;
697
+ statusCode: number;
698
+ statusMessage: string;
699
+ body: unknown;
700
+ });
701
+ }
604
702
 
605
703
  /** One row of the `/projects/<projectId>` members response. */
606
704
  export declare interface ProjectMemberRecord {
@@ -733,6 +831,25 @@ export declare type ReleaseState =
733
831
 
734
832
  export declare type ReleaseType = "asap" | "scheduled" | "undecided";
735
833
 
834
+ /**
835
+ * What the Access API (`/access/<type>/<id>/…`) answers about one actor on
836
+ * one resource: the roles it holds there (served by `…/users` and collected
837
+ * into `…/roles`) and the permissions `…/user-permissions/me` and
838
+ * `…/user-permissions/me/check` report, as `"<type>.<action>"` names such
839
+ * as `"sanity.media-library.read"`.
840
+ */
841
+ export declare interface ResourceAccess {
842
+ roles?: NonNullable<CurrentUser["roles"]>;
843
+ permissions?: string[];
844
+ }
845
+
846
+ /** Resource types `@sanity/client`'s `resource` config can name (the ones staging probed). */
847
+ export declare type ResourceType =
848
+ | "dataset"
849
+ | "media-library"
850
+ | "canvas"
851
+ | "dashboard";
852
+
736
853
  /** @public */
737
854
  declare interface SanityDocument {
738
855
  _id: string;
@@ -789,6 +906,7 @@ export declare const SUPPORTED_SURFACE: readonly [
789
906
  "createVersion",
790
907
  "unpublishVersion",
791
908
  "request (only with accessControl or a bound token)",
909
+ "getDataUrl",
792
910
  "config",
793
911
  "withConfig",
794
912
  ];
@@ -819,7 +937,8 @@ export declare interface TestClient {
819
937
  * registered token (`identities` + `token`). The engine's access
820
938
  * resolver pokes `/users/me` and the configured ACL path through
821
939
  * this — without it the engine throws on any verb that needs an
822
- * actor.
940
+ * actor. Also serves the resource's history, ACL, lookup and Access API
941
+ * endpoints, or the platform's refusal where the resource has none.
823
942
  */
824
943
  request?: <T>(opts: {
825
944
  url?: string;
@@ -827,6 +946,13 @@ export declare interface TestClient {
827
946
  signal?: AbortSignal;
828
947
  tag?: string | null;
829
948
  }) => Promise<T>;
949
+ /**
950
+ * `@sanity/client`'s `getDataUrl(operation, path)`: `<resource
951
+ * base>/<operation>/<path>` on a `resource`-configured handle,
952
+ * `/data/<operation>/<dataset>/<path>` otherwise. Pass the result to
953
+ * `request()` to reach e.g. the History API.
954
+ */
955
+ getDataUrl: (operation: string, path?: string) => string;
830
956
  create: <T extends SanityDocumentLike>(
831
957
  doc: T,
832
958
  options?: MutationOptions,
@@ -884,13 +1010,15 @@ export declare interface TestClient {
884
1010
  publishedId: string;
885
1011
  }) => Promise<ActionResult>;
886
1012
  /**
887
- * Current `(projectId, dataset)`, active perspective, and which API host
1013
+ * Current `(projectId, dataset)` or `resource`, active perspective, and which API host
888
1014
  * the handle models (`useProjectHostname`). `token` is present iff the
889
1015
  * handle is bound to a registered identity.
890
1016
  */
891
1017
  config: () => {
892
1018
  projectId: string;
893
1019
  dataset: string;
1020
+ /** Present iff the handle is `resource`-configured. */
1021
+ resource?: TestClientResource;
894
1022
  perspective: Perspective;
895
1023
  requestTagPrefix?: string;
896
1024
  token?: string;
@@ -906,6 +1034,13 @@ export declare interface TestClient {
906
1034
  config: Partial<{
907
1035
  projectId: string;
908
1036
  dataset: string;
1037
+ /**
1038
+ * Point the sibling at a resource, named as `@sanity/client`'s
1039
+ * `resource` config names it. While set, it decides the store (over
1040
+ * `projectId` / `dataset`), as in `@sanity/client`. Pass `undefined`
1041
+ * to drop it and address `(projectId, dataset)` again.
1042
+ */
1043
+ resource: TestClientResource | undefined;
909
1044
  perspective: Perspective;
910
1045
  /** Prefix composed with request tags and used alone for untagged requests. */
911
1046
  requestTagPrefix: string;
@@ -972,6 +1107,8 @@ export declare interface TestClient {
972
1107
  projectId: string;
973
1108
  dataset: string;
974
1109
  }[];
1110
+ /** List every resource known in this registry — datasets as `{ type: "dataset", id: "<projectId>.<dataset>" }`. */
1111
+ resources: () => TestClientResource[];
975
1112
  /**
976
1113
  * Register a handler for a `@sanity/client` member the fake doesn't
977
1114
  * implement (e.g. `listen`, `assets`). Accessing that member on the
@@ -1041,9 +1178,15 @@ export declare interface TestClientAccessControl {
1041
1178
  grants: Grant[];
1042
1179
  /**
1043
1180
  * URL path the engine's access resolver hits to fetch grants.
1044
- * Defaults to `/projects/<projectId>/datasets/<dataset>/acl`.
1181
+ * Defaults to the handle's resource ACL: `/projects/<projectId>/datasets/<dataset>/acl`,
1182
+ * or `<resource base>/acl` on a `resource`-configured handle.
1045
1183
  */
1046
1184
  aclPath?: string;
1185
+ /**
1186
+ * Access API entries, keyed `"<access type>:<id>"` — `"organization:<id>"`,
1187
+ * `"project:<projectId>"`, `"media-library:<id>"`, `"canvas:<id>"`, `"dashboard:<id>"`. See {@link ResourceAccess}.
1188
+ */
1189
+ access?: Record<string, ResourceAccess>;
1047
1190
  }
1048
1191
 
1049
1192
  /**
@@ -1081,6 +1224,24 @@ export declare interface TestClientIdentity {
1081
1224
  usersByProject?: Record<string, CurrentUser>;
1082
1225
  /** Grants served at the ACL path and enforced on reads/writes. */
1083
1226
  grants: Grant[];
1227
+ /**
1228
+ * Access API entries, keyed `"<access type>:<id>"` (`"organization:<id>"`,
1229
+ * `"media-library:<id>"`, `"canvas:<id>"`, `"dashboard:<id>"`,
1230
+ * `"project:<projectId>"`). On a non-project resource, an entry with
1231
+ * `roles` makes the identity a member there. Project membership needs no entry: every identity is a member of
1232
+ * every project with its project-scoped roles.
1233
+ */
1234
+ access?: Record<string, ResourceAccess>;
1235
+ }
1236
+
1237
+ /**
1238
+ * A resource, named exactly as `@sanity/client`'s `resource` config names
1239
+ * it: `{ type: "media-library", id: "ml…" }`, or `{ type: "dataset", id:
1240
+ * "<projectId>.<dataset>" }`.
1241
+ */
1242
+ export declare interface TestClientResource {
1243
+ type: ResourceType;
1244
+ id: string;
1084
1245
  }
1085
1246
 
1086
1247
  /**
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare function applyPatchOps(
38
38
  */
39
39
  export declare function applyPerspective(
40
40
  docs: readonly SanityDocument[],
41
- perspective: Perspective,
41
+ requested: Perspective,
42
42
  ): SanityDocument[];
43
43
 
44
44
  /**
@@ -61,6 +61,8 @@ export declare interface CallRecord {
61
61
  tag?: string | null;
62
62
  projectId: string;
63
63
  dataset: string;
64
+ /** The resource the call targeted, on a `resource`-configured handle. */
65
+ resource?: TestClientResource;
64
66
  }
65
67
 
66
68
  /** Outcome of a recorded call, reported once a (possibly async) result is known. */
@@ -105,6 +107,27 @@ export declare interface CreateTestClientOptions {
105
107
  * pairs. Useful when workflows span multiple datasets.
106
108
  */
107
109
  datasets?: Record<string, SanityDocumentLike[]>;
110
+ /**
111
+ * Optional: seed any resource type. Keys are `"<type>:<id>"`, the
112
+ * `resource` config's two fields: `"media-library:ml1"`, `"canvas:c1"`,
113
+ * `"dashboard:d1"`, or `"dataset:<projectId>.<dataset>"` (the same store
114
+ * as `datasets["<projectId>:<dataset>"]`).
115
+ */
116
+ resources?: Record<string, SanityDocumentLike[]>;
117
+ /**
118
+ * The resource the root handle points at, named exactly as
119
+ * `@sanity/client`'s `resource` config names it. While set, it decides
120
+ * the store (over `projectId` / `dataset`), and each capability the
121
+ * platform lacks on that resource type answers with the platform's
122
+ * refusal. `withConfig({ resource })` mints siblings on other resources.
123
+ */
124
+ resource?: TestClientResource;
125
+ /**
126
+ * The organization every resource of this client belongs to — what
127
+ * `GET /media-libraries/<id>`, `/canvases/<id>`, `/dashboards/<id>` and
128
+ * `/projects/<projectId>` answer as `organizationId`.
129
+ */
130
+ organizationId?: string;
108
131
  /**
109
132
  * Opt-in access-control simulation. When set, the client exposes
110
133
  * `request({ url })` that serves `/users/me` (host-aware), the
@@ -330,11 +353,14 @@ export declare type FakeMutation =
330
353
  /**
331
354
  * Data-plane subset of `@sanity/client`'s surface, with multi-dataset support.
332
355
  *
333
- * One `createTestClient()` call creates a registry of stores keyed by
334
- * `(projectId, dataset)`. The returned client points at one of them.
335
- * `withConfig({ projectId, dataset })` returns a new handle into the same
336
- * registry but pointing at a different store — useful for workflows where
337
- * definitions live in one dataset and instances live in another.
356
+ * One `createTestClient()` call creates a registry of stores, one per
357
+ * resource: a `(projectId, dataset)` pair, or a Media Library, Canvas or
358
+ * dashboard named by `resource: { type, id }` exactly as `@sanity/client`
359
+ * names it. The returned client points at one of them.
360
+ * `withConfig({ projectId, dataset })` or `withConfig({ resource })` returns
361
+ * a new handle into the same registry but pointing at a different store —
362
+ * useful for workflows where definitions live in one dataset and instances
363
+ * live in another.
338
364
  *
339
365
  * Two separate `createTestClient()` calls have separate registries, so
340
366
  * tests stay isolated from each other.
@@ -345,7 +371,7 @@ export declare type FakeMutation =
345
371
  * scoped to the current dataset.
346
372
  * - `simulateConcurrentEdit()` — force the next N revision-guarded writes
347
373
  * to a document to 409, for optimistic-locking retry tests.
348
- * - `datasets()` — lists known dataset keys in this registry.
374
+ * - `datasets()` / `resources()` — list the stores known in this registry.
349
375
  *
350
376
  * Methods deliberately omitted:
351
377
  *
@@ -425,6 +451,37 @@ export declare interface GuardDeniedResponse {
425
451
  statusMessage: "Forbidden";
426
452
  }
427
453
 
454
+ /** An event as `GET <data base>/history/events/documents/<ids>` serves it. */
455
+ export declare interface HistoryEvent {
456
+ type: "createLiveDocument" | "updateLiveDocument";
457
+ id: string;
458
+ documentId: string;
459
+ revisionId: string;
460
+ timestamp: string;
461
+ author?: string;
462
+ }
463
+
464
+ /** A transaction as `GET <data base>/history/transactions/<ids>` serves it, one per NDJSON line. */
465
+ export declare interface HistoryTransactionRecord {
466
+ id: string;
467
+ timestamp: string;
468
+ author?: string;
469
+ mutations: (
470
+ | {
471
+ create: SanityDocument;
472
+ }
473
+ | {
474
+ createOrReplace: SanityDocument;
475
+ }
476
+ | {
477
+ delete: {
478
+ id: string;
479
+ };
480
+ }
481
+ )[];
482
+ documentIDs: string[];
483
+ }
484
+
428
485
  export declare const isDraftId: (id: string) => boolean;
429
486
 
430
487
  export declare const isReleaseDocId: (id: string) => boolean;
@@ -489,6 +546,8 @@ export declare interface MutationLogEntry {
489
546
  transactionId: string;
490
547
  projectId: string;
491
548
  dataset: string;
549
+ /** The resource the transaction targeted, on a `resource`-configured handle. */
550
+ resource?: TestClientResource;
492
551
  mutations: TxnMutation[];
493
552
  /** Request tag the commit carried, when one was passed (`null` = explicit suppression). */
494
553
  tag?: string | null;
@@ -600,7 +659,46 @@ export declare type PatchOp =
600
659
  items: unknown[];
601
660
  };
602
661
 
603
- export declare type Perspective = "raw" | "published" | "drafts" | string[];
662
+ /**
663
+ * `raw`, `published`, `drafts`, a release stack, or a single release name
664
+ * (`"rSpring"`) — which the Content Lake reads as a one-release stack.
665
+ */
666
+ export declare type Perspective =
667
+ | "raw"
668
+ | "published"
669
+ | "drafts"
670
+ | (string & {})
671
+ | string[];
672
+
673
+ /** The `response` of an HTTP error, shaped like `@sanity/client`'s `HttpError["response"]`. */
674
+ declare interface PlatformErrorResponse {
675
+ body: unknown;
676
+ url: string;
677
+ method: string;
678
+ headers: Record<string, string>;
679
+ statusCode: number;
680
+ statusMessage: string;
681
+ }
682
+
683
+ /**
684
+ * The platform's refusal, shaped like the `ClientError` `@sanity/client`
685
+ * throws for the same response: `statusCode`, `response`, `responseBody`,
686
+ * `details`, and a `message` derived from the body the way the client
687
+ * derives it.
688
+ */
689
+ export declare class PlatformHttpError extends Error {
690
+ readonly statusCode: number;
691
+ readonly response: PlatformErrorResponse;
692
+ readonly responseBody: string;
693
+ readonly details: unknown;
694
+ constructor(args: {
695
+ method: string;
696
+ path: string;
697
+ statusCode: number;
698
+ statusMessage: string;
699
+ body: unknown;
700
+ });
701
+ }
604
702
 
605
703
  /** One row of the `/projects/<projectId>` members response. */
606
704
  export declare interface ProjectMemberRecord {
@@ -733,6 +831,25 @@ export declare type ReleaseState =
733
831
 
734
832
  export declare type ReleaseType = "asap" | "scheduled" | "undecided";
735
833
 
834
+ /**
835
+ * What the Access API (`/access/<type>/<id>/…`) answers about one actor on
836
+ * one resource: the roles it holds there (served by `…/users` and collected
837
+ * into `…/roles`) and the permissions `…/user-permissions/me` and
838
+ * `…/user-permissions/me/check` report, as `"<type>.<action>"` names such
839
+ * as `"sanity.media-library.read"`.
840
+ */
841
+ export declare interface ResourceAccess {
842
+ roles?: NonNullable<CurrentUser["roles"]>;
843
+ permissions?: string[];
844
+ }
845
+
846
+ /** Resource types `@sanity/client`'s `resource` config can name (the ones staging probed). */
847
+ export declare type ResourceType =
848
+ | "dataset"
849
+ | "media-library"
850
+ | "canvas"
851
+ | "dashboard";
852
+
736
853
  /** @public */
737
854
  declare interface SanityDocument {
738
855
  _id: string;
@@ -789,6 +906,7 @@ export declare const SUPPORTED_SURFACE: readonly [
789
906
  "createVersion",
790
907
  "unpublishVersion",
791
908
  "request (only with accessControl or a bound token)",
909
+ "getDataUrl",
792
910
  "config",
793
911
  "withConfig",
794
912
  ];
@@ -819,7 +937,8 @@ export declare interface TestClient {
819
937
  * registered token (`identities` + `token`). The engine's access
820
938
  * resolver pokes `/users/me` and the configured ACL path through
821
939
  * this — without it the engine throws on any verb that needs an
822
- * actor.
940
+ * actor. Also serves the resource's history, ACL, lookup and Access API
941
+ * endpoints, or the platform's refusal where the resource has none.
823
942
  */
824
943
  request?: <T>(opts: {
825
944
  url?: string;
@@ -827,6 +946,13 @@ export declare interface TestClient {
827
946
  signal?: AbortSignal;
828
947
  tag?: string | null;
829
948
  }) => Promise<T>;
949
+ /**
950
+ * `@sanity/client`'s `getDataUrl(operation, path)`: `<resource
951
+ * base>/<operation>/<path>` on a `resource`-configured handle,
952
+ * `/data/<operation>/<dataset>/<path>` otherwise. Pass the result to
953
+ * `request()` to reach e.g. the History API.
954
+ */
955
+ getDataUrl: (operation: string, path?: string) => string;
830
956
  create: <T extends SanityDocumentLike>(
831
957
  doc: T,
832
958
  options?: MutationOptions,
@@ -884,13 +1010,15 @@ export declare interface TestClient {
884
1010
  publishedId: string;
885
1011
  }) => Promise<ActionResult>;
886
1012
  /**
887
- * Current `(projectId, dataset)`, active perspective, and which API host
1013
+ * Current `(projectId, dataset)` or `resource`, active perspective, and which API host
888
1014
  * the handle models (`useProjectHostname`). `token` is present iff the
889
1015
  * handle is bound to a registered identity.
890
1016
  */
891
1017
  config: () => {
892
1018
  projectId: string;
893
1019
  dataset: string;
1020
+ /** Present iff the handle is `resource`-configured. */
1021
+ resource?: TestClientResource;
894
1022
  perspective: Perspective;
895
1023
  requestTagPrefix?: string;
896
1024
  token?: string;
@@ -906,6 +1034,13 @@ export declare interface TestClient {
906
1034
  config: Partial<{
907
1035
  projectId: string;
908
1036
  dataset: string;
1037
+ /**
1038
+ * Point the sibling at a resource, named as `@sanity/client`'s
1039
+ * `resource` config names it. While set, it decides the store (over
1040
+ * `projectId` / `dataset`), as in `@sanity/client`. Pass `undefined`
1041
+ * to drop it and address `(projectId, dataset)` again.
1042
+ */
1043
+ resource: TestClientResource | undefined;
909
1044
  perspective: Perspective;
910
1045
  /** Prefix composed with request tags and used alone for untagged requests. */
911
1046
  requestTagPrefix: string;
@@ -972,6 +1107,8 @@ export declare interface TestClient {
972
1107
  projectId: string;
973
1108
  dataset: string;
974
1109
  }[];
1110
+ /** List every resource known in this registry — datasets as `{ type: "dataset", id: "<projectId>.<dataset>" }`. */
1111
+ resources: () => TestClientResource[];
975
1112
  /**
976
1113
  * Register a handler for a `@sanity/client` member the fake doesn't
977
1114
  * implement (e.g. `listen`, `assets`). Accessing that member on the
@@ -1041,9 +1178,15 @@ export declare interface TestClientAccessControl {
1041
1178
  grants: Grant[];
1042
1179
  /**
1043
1180
  * URL path the engine's access resolver hits to fetch grants.
1044
- * Defaults to `/projects/<projectId>/datasets/<dataset>/acl`.
1181
+ * Defaults to the handle's resource ACL: `/projects/<projectId>/datasets/<dataset>/acl`,
1182
+ * or `<resource base>/acl` on a `resource`-configured handle.
1045
1183
  */
1046
1184
  aclPath?: string;
1185
+ /**
1186
+ * Access API entries, keyed `"<access type>:<id>"` — `"organization:<id>"`,
1187
+ * `"project:<projectId>"`, `"media-library:<id>"`, `"canvas:<id>"`, `"dashboard:<id>"`. See {@link ResourceAccess}.
1188
+ */
1189
+ access?: Record<string, ResourceAccess>;
1047
1190
  }
1048
1191
 
1049
1192
  /**
@@ -1081,6 +1224,24 @@ export declare interface TestClientIdentity {
1081
1224
  usersByProject?: Record<string, CurrentUser>;
1082
1225
  /** Grants served at the ACL path and enforced on reads/writes. */
1083
1226
  grants: Grant[];
1227
+ /**
1228
+ * Access API entries, keyed `"<access type>:<id>"` (`"organization:<id>"`,
1229
+ * `"media-library:<id>"`, `"canvas:<id>"`, `"dashboard:<id>"`,
1230
+ * `"project:<projectId>"`). On a non-project resource, an entry with
1231
+ * `roles` makes the identity a member there. Project membership needs no entry: every identity is a member of
1232
+ * every project with its project-scoped roles.
1233
+ */
1234
+ access?: Record<string, ResourceAccess>;
1235
+ }
1236
+
1237
+ /**
1238
+ * A resource, named exactly as `@sanity/client`'s `resource` config names
1239
+ * it: `{ type: "media-library", id: "ml…" }`, or `{ type: "dataset", id:
1240
+ * "<projectId>.<dataset>" }`.
1241
+ */
1242
+ export declare interface TestClientResource {
1243
+ type: ResourceType;
1244
+ id: string;
1084
1245
  }
1085
1246
 
1086
1247
  /**