@sanity-labs/client-fake-for-test 0.8.0 → 0.9.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/README.md +29 -5
- package/dist/index.cjs +100 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -13
- package/dist/index.d.ts +79 -13
- package/dist/index.js +100 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -107,8 +107,9 @@ export declare interface CreateTestClientOptions {
|
|
|
107
107
|
datasets?: Record<string, SanityDocumentLike[]>;
|
|
108
108
|
/**
|
|
109
109
|
* Opt-in access-control simulation. When set, the client exposes
|
|
110
|
-
* `request({ url })` that serves `/users/me`
|
|
111
|
-
* path,
|
|
110
|
+
* `request({ url })` that serves `/users/me` (host-aware), the
|
|
111
|
+
* configured ACL path, and `/projects/<projectId>/users/<ids>`,
|
|
112
|
+
* AND every mutation is gated through the supplied `grants`
|
|
112
113
|
* — writes that the grants don't permit throw a `WriteAccessDeniedError`
|
|
113
114
|
* shaped like Sanity's 403. Lets tests demonstrate the full
|
|
114
115
|
* "engine soft-gate + lake hard-gate" contract end-to-end without
|
|
@@ -165,6 +166,14 @@ export declare interface CreateTestClientOptions {
|
|
|
165
166
|
* tests stay green.
|
|
166
167
|
*/
|
|
167
168
|
perspective?: Perspective;
|
|
169
|
+
/**
|
|
170
|
+
* Which API host the root handle models: the project host (default
|
|
171
|
+
* `true`) or the global host (`false`) — same flag as the real
|
|
172
|
+
* `createClient` config. A global-hosted handle's `/users/me` serves
|
|
173
|
+
* the identity's account-global record. `withConfig({ useProjectHostname })`
|
|
174
|
+
* mints siblings on the other host.
|
|
175
|
+
*/
|
|
176
|
+
useProjectHostname?: boolean;
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
/**
|
|
@@ -583,6 +592,19 @@ export declare type PatchOp =
|
|
|
583
592
|
|
|
584
593
|
export declare type Perspective = "raw" | "published" | "drafts" | string[];
|
|
585
594
|
|
|
595
|
+
/**
|
|
596
|
+
* A row served by the project-users directory endpoint
|
|
597
|
+
* (`/projects/<projectId>/users/<id>`), mirroring Sanity's project user
|
|
598
|
+
* retrieval API: the project-scoped `id` alongside its account-global
|
|
599
|
+
* `sanityUserId` — the one sanctioned bridge between the two namespaces.
|
|
600
|
+
*/
|
|
601
|
+
export declare interface ProjectUserRecord {
|
|
602
|
+
id: string;
|
|
603
|
+
sanityUserId: string;
|
|
604
|
+
displayName: string;
|
|
605
|
+
email?: string;
|
|
606
|
+
}
|
|
607
|
+
|
|
586
608
|
/** Strip `drafts.` / `versions.<name>.` prefix to recover the published id. */
|
|
587
609
|
export declare function publishedIdOf(id: string): string;
|
|
588
610
|
|
|
@@ -843,14 +865,16 @@ export declare interface TestClient {
|
|
|
843
865
|
publishedId: string;
|
|
844
866
|
}) => Promise<ActionResult>;
|
|
845
867
|
/**
|
|
846
|
-
* Current `(projectId, dataset)
|
|
847
|
-
*
|
|
868
|
+
* Current `(projectId, dataset)`, active perspective, and which API host
|
|
869
|
+
* the handle models (`useProjectHostname`). `token` is present iff the
|
|
870
|
+
* handle is bound to a registered identity.
|
|
848
871
|
*/
|
|
849
872
|
config: () => {
|
|
850
873
|
projectId: string;
|
|
851
874
|
dataset: string;
|
|
852
875
|
perspective: Perspective;
|
|
853
876
|
token?: string;
|
|
877
|
+
useProjectHostname: boolean;
|
|
854
878
|
};
|
|
855
879
|
/**
|
|
856
880
|
* Return a new client handle pointing at a different `(projectId, dataset)`
|
|
@@ -863,6 +887,14 @@ export declare interface TestClient {
|
|
|
863
887
|
projectId: string;
|
|
864
888
|
dataset: string;
|
|
865
889
|
perspective: Perspective;
|
|
890
|
+
/**
|
|
891
|
+
* Model the global API host (`false`) instead of the project host
|
|
892
|
+
* (default `true`). A global-hosted sibling's `/users/me` serves the
|
|
893
|
+
* identity's account-global record (`globalUser`, falling back to the
|
|
894
|
+
* project record) — mirroring `@sanity/client`, where a non-project
|
|
895
|
+
* config routes requests to `api.sanity.io`.
|
|
896
|
+
*/
|
|
897
|
+
useProjectHostname: boolean;
|
|
866
898
|
/**
|
|
867
899
|
* Rebind the acting identity (and its grants) on a sibling that shares
|
|
868
900
|
* the same store — the test analogue of a token-scoped client. Lets two
|
|
@@ -873,10 +905,11 @@ export declare interface TestClient {
|
|
|
873
905
|
/**
|
|
874
906
|
* Bind the sibling to a token registered in the family's identity
|
|
875
907
|
* registry (`createTestClient({ identities })` / `addIdentity`): its
|
|
876
|
-
* `/users/me` serves that identity's
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
908
|
+
* `/users/me` serves that identity's record for the sibling's project
|
|
909
|
+
* and host, its ACL path serves that identity's grants, and
|
|
910
|
+
* reads/writes are gated through them — the token determines
|
|
911
|
+
* identity, exactly like production. Unknown tokens throw. Mutually
|
|
912
|
+
* exclusive with `accessControl`.
|
|
880
913
|
*/
|
|
881
914
|
token: string;
|
|
882
915
|
}>,
|
|
@@ -970,8 +1003,18 @@ export declare interface TestClient {
|
|
|
970
1003
|
}
|
|
971
1004
|
|
|
972
1005
|
export declare interface TestClientAccessControl {
|
|
973
|
-
/** What `client.request({ url: "/users/me" })` returns. */
|
|
1006
|
+
/** What `client.request({ url: "/users/me" })` returns on a project-hosted handle. */
|
|
974
1007
|
currentUser: CurrentUser;
|
|
1008
|
+
/**
|
|
1009
|
+
* What `/users/me` returns on a global-hosted handle
|
|
1010
|
+
* (`useProjectHostname: false`, at creation or via `withConfig`).
|
|
1011
|
+
* Sanity serves the
|
|
1012
|
+
* account-global user there (`g*` id, no roles) while the project host
|
|
1013
|
+
* serves the project-scoped record (`p*` id, project roles). Omit to
|
|
1014
|
+
* serve `currentUser` from both — the single-id collapse that is also
|
|
1015
|
+
* exactly how robot tokens behave in production.
|
|
1016
|
+
*/
|
|
1017
|
+
globalUser?: CurrentUser;
|
|
975
1018
|
/** What `client.request({ url: aclPath })` returns. */
|
|
976
1019
|
grants: Grant[];
|
|
977
1020
|
/**
|
|
@@ -984,13 +1027,36 @@ export declare interface TestClientAccessControl {
|
|
|
984
1027
|
/**
|
|
985
1028
|
* One entry in the token→identity registry (`createTestClient({ identities })`).
|
|
986
1029
|
* A handle bound to the entry's token behaves exactly like one configured
|
|
987
|
-
* with `accessControl: { currentUser:
|
|
988
|
-
*
|
|
989
|
-
*
|
|
1030
|
+
* with `accessControl: { currentUser: projectUserOf(identity, projectId),
|
|
1031
|
+
* globalUser, grants }` — `/users/me` serves the record for the handle's
|
|
1032
|
+
* project and host, the default ACL path serves `grants`, and reads/writes
|
|
1033
|
+
* are gated through them.
|
|
990
1034
|
*/
|
|
991
1035
|
export declare interface TestClientIdentity {
|
|
992
|
-
/**
|
|
1036
|
+
/**
|
|
1037
|
+
* The project-scoped user record: what `/users/me` returns on a
|
|
1038
|
+
* project-hosted handle, and the id `identity()` resolves to in grant
|
|
1039
|
+
* filters and mutation guards. Per-project variants go in
|
|
1040
|
+
* `usersByProject`; this is the record for any project without one.
|
|
1041
|
+
*/
|
|
993
1042
|
user: CurrentUser;
|
|
1043
|
+
/**
|
|
1044
|
+
* The account-global user record, served by `/users/me` on a
|
|
1045
|
+
* global-hosted handle (`useProjectHostname: false`, at creation or
|
|
1046
|
+
* via `withConfig`).
|
|
1047
|
+
* The same person carries a different id per project (`p*`) and one
|
|
1048
|
+
* global id (`g*`); registering both lets tests model that split.
|
|
1049
|
+
* Omit for single-id principals (robot tokens resolve to one `p-*` id
|
|
1050
|
+
* on every host).
|
|
1051
|
+
*/
|
|
1052
|
+
globalUser?: CurrentUser;
|
|
1053
|
+
/**
|
|
1054
|
+
* Per-project user records, keyed by projectId — the same token
|
|
1055
|
+
* resolves to a different project-scoped id in each project, which is
|
|
1056
|
+
* what these model. A handle's project falls back to `user` when its
|
|
1057
|
+
* projectId has no entry.
|
|
1058
|
+
*/
|
|
1059
|
+
usersByProject?: Record<string, CurrentUser>;
|
|
994
1060
|
/** Grants served at the ACL path and enforced on reads/writes. */
|
|
995
1061
|
grants: Grant[];
|
|
996
1062
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -107,8 +107,9 @@ export declare interface CreateTestClientOptions {
|
|
|
107
107
|
datasets?: Record<string, SanityDocumentLike[]>;
|
|
108
108
|
/**
|
|
109
109
|
* Opt-in access-control simulation. When set, the client exposes
|
|
110
|
-
* `request({ url })` that serves `/users/me`
|
|
111
|
-
* path,
|
|
110
|
+
* `request({ url })` that serves `/users/me` (host-aware), the
|
|
111
|
+
* configured ACL path, and `/projects/<projectId>/users/<ids>`,
|
|
112
|
+
* AND every mutation is gated through the supplied `grants`
|
|
112
113
|
* — writes that the grants don't permit throw a `WriteAccessDeniedError`
|
|
113
114
|
* shaped like Sanity's 403. Lets tests demonstrate the full
|
|
114
115
|
* "engine soft-gate + lake hard-gate" contract end-to-end without
|
|
@@ -165,6 +166,14 @@ export declare interface CreateTestClientOptions {
|
|
|
165
166
|
* tests stay green.
|
|
166
167
|
*/
|
|
167
168
|
perspective?: Perspective;
|
|
169
|
+
/**
|
|
170
|
+
* Which API host the root handle models: the project host (default
|
|
171
|
+
* `true`) or the global host (`false`) — same flag as the real
|
|
172
|
+
* `createClient` config. A global-hosted handle's `/users/me` serves
|
|
173
|
+
* the identity's account-global record. `withConfig({ useProjectHostname })`
|
|
174
|
+
* mints siblings on the other host.
|
|
175
|
+
*/
|
|
176
|
+
useProjectHostname?: boolean;
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
/**
|
|
@@ -583,6 +592,19 @@ export declare type PatchOp =
|
|
|
583
592
|
|
|
584
593
|
export declare type Perspective = "raw" | "published" | "drafts" | string[];
|
|
585
594
|
|
|
595
|
+
/**
|
|
596
|
+
* A row served by the project-users directory endpoint
|
|
597
|
+
* (`/projects/<projectId>/users/<id>`), mirroring Sanity's project user
|
|
598
|
+
* retrieval API: the project-scoped `id` alongside its account-global
|
|
599
|
+
* `sanityUserId` — the one sanctioned bridge between the two namespaces.
|
|
600
|
+
*/
|
|
601
|
+
export declare interface ProjectUserRecord {
|
|
602
|
+
id: string;
|
|
603
|
+
sanityUserId: string;
|
|
604
|
+
displayName: string;
|
|
605
|
+
email?: string;
|
|
606
|
+
}
|
|
607
|
+
|
|
586
608
|
/** Strip `drafts.` / `versions.<name>.` prefix to recover the published id. */
|
|
587
609
|
export declare function publishedIdOf(id: string): string;
|
|
588
610
|
|
|
@@ -843,14 +865,16 @@ export declare interface TestClient {
|
|
|
843
865
|
publishedId: string;
|
|
844
866
|
}) => Promise<ActionResult>;
|
|
845
867
|
/**
|
|
846
|
-
* Current `(projectId, dataset)
|
|
847
|
-
*
|
|
868
|
+
* Current `(projectId, dataset)`, active perspective, and which API host
|
|
869
|
+
* the handle models (`useProjectHostname`). `token` is present iff the
|
|
870
|
+
* handle is bound to a registered identity.
|
|
848
871
|
*/
|
|
849
872
|
config: () => {
|
|
850
873
|
projectId: string;
|
|
851
874
|
dataset: string;
|
|
852
875
|
perspective: Perspective;
|
|
853
876
|
token?: string;
|
|
877
|
+
useProjectHostname: boolean;
|
|
854
878
|
};
|
|
855
879
|
/**
|
|
856
880
|
* Return a new client handle pointing at a different `(projectId, dataset)`
|
|
@@ -863,6 +887,14 @@ export declare interface TestClient {
|
|
|
863
887
|
projectId: string;
|
|
864
888
|
dataset: string;
|
|
865
889
|
perspective: Perspective;
|
|
890
|
+
/**
|
|
891
|
+
* Model the global API host (`false`) instead of the project host
|
|
892
|
+
* (default `true`). A global-hosted sibling's `/users/me` serves the
|
|
893
|
+
* identity's account-global record (`globalUser`, falling back to the
|
|
894
|
+
* project record) — mirroring `@sanity/client`, where a non-project
|
|
895
|
+
* config routes requests to `api.sanity.io`.
|
|
896
|
+
*/
|
|
897
|
+
useProjectHostname: boolean;
|
|
866
898
|
/**
|
|
867
899
|
* Rebind the acting identity (and its grants) on a sibling that shares
|
|
868
900
|
* the same store — the test analogue of a token-scoped client. Lets two
|
|
@@ -873,10 +905,11 @@ export declare interface TestClient {
|
|
|
873
905
|
/**
|
|
874
906
|
* Bind the sibling to a token registered in the family's identity
|
|
875
907
|
* registry (`createTestClient({ identities })` / `addIdentity`): its
|
|
876
|
-
* `/users/me` serves that identity's
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
908
|
+
* `/users/me` serves that identity's record for the sibling's project
|
|
909
|
+
* and host, its ACL path serves that identity's grants, and
|
|
910
|
+
* reads/writes are gated through them — the token determines
|
|
911
|
+
* identity, exactly like production. Unknown tokens throw. Mutually
|
|
912
|
+
* exclusive with `accessControl`.
|
|
880
913
|
*/
|
|
881
914
|
token: string;
|
|
882
915
|
}>,
|
|
@@ -970,8 +1003,18 @@ export declare interface TestClient {
|
|
|
970
1003
|
}
|
|
971
1004
|
|
|
972
1005
|
export declare interface TestClientAccessControl {
|
|
973
|
-
/** What `client.request({ url: "/users/me" })` returns. */
|
|
1006
|
+
/** What `client.request({ url: "/users/me" })` returns on a project-hosted handle. */
|
|
974
1007
|
currentUser: CurrentUser;
|
|
1008
|
+
/**
|
|
1009
|
+
* What `/users/me` returns on a global-hosted handle
|
|
1010
|
+
* (`useProjectHostname: false`, at creation or via `withConfig`).
|
|
1011
|
+
* Sanity serves the
|
|
1012
|
+
* account-global user there (`g*` id, no roles) while the project host
|
|
1013
|
+
* serves the project-scoped record (`p*` id, project roles). Omit to
|
|
1014
|
+
* serve `currentUser` from both — the single-id collapse that is also
|
|
1015
|
+
* exactly how robot tokens behave in production.
|
|
1016
|
+
*/
|
|
1017
|
+
globalUser?: CurrentUser;
|
|
975
1018
|
/** What `client.request({ url: aclPath })` returns. */
|
|
976
1019
|
grants: Grant[];
|
|
977
1020
|
/**
|
|
@@ -984,13 +1027,36 @@ export declare interface TestClientAccessControl {
|
|
|
984
1027
|
/**
|
|
985
1028
|
* One entry in the token→identity registry (`createTestClient({ identities })`).
|
|
986
1029
|
* A handle bound to the entry's token behaves exactly like one configured
|
|
987
|
-
* with `accessControl: { currentUser:
|
|
988
|
-
*
|
|
989
|
-
*
|
|
1030
|
+
* with `accessControl: { currentUser: projectUserOf(identity, projectId),
|
|
1031
|
+
* globalUser, grants }` — `/users/me` serves the record for the handle's
|
|
1032
|
+
* project and host, the default ACL path serves `grants`, and reads/writes
|
|
1033
|
+
* are gated through them.
|
|
990
1034
|
*/
|
|
991
1035
|
export declare interface TestClientIdentity {
|
|
992
|
-
/**
|
|
1036
|
+
/**
|
|
1037
|
+
* The project-scoped user record: what `/users/me` returns on a
|
|
1038
|
+
* project-hosted handle, and the id `identity()` resolves to in grant
|
|
1039
|
+
* filters and mutation guards. Per-project variants go in
|
|
1040
|
+
* `usersByProject`; this is the record for any project without one.
|
|
1041
|
+
*/
|
|
993
1042
|
user: CurrentUser;
|
|
1043
|
+
/**
|
|
1044
|
+
* The account-global user record, served by `/users/me` on a
|
|
1045
|
+
* global-hosted handle (`useProjectHostname: false`, at creation or
|
|
1046
|
+
* via `withConfig`).
|
|
1047
|
+
* The same person carries a different id per project (`p*`) and one
|
|
1048
|
+
* global id (`g*`); registering both lets tests model that split.
|
|
1049
|
+
* Omit for single-id principals (robot tokens resolve to one `p-*` id
|
|
1050
|
+
* on every host).
|
|
1051
|
+
*/
|
|
1052
|
+
globalUser?: CurrentUser;
|
|
1053
|
+
/**
|
|
1054
|
+
* Per-project user records, keyed by projectId — the same token
|
|
1055
|
+
* resolves to a different project-scoped id in each project, which is
|
|
1056
|
+
* what these model. A handle's project falls back to `user` when its
|
|
1057
|
+
* projectId has no entry.
|
|
1058
|
+
*/
|
|
1059
|
+
usersByProject?: Record<string, CurrentUser>;
|
|
994
1060
|
/** Grants served at the ACL path and enforced on reads/writes. */
|
|
995
1061
|
grants: Grant[];
|
|
996
1062
|
}
|
package/dist/index.js
CHANGED
|
@@ -59,15 +59,62 @@ async function enforceWriteAccess(args) {
|
|
|
59
59
|
function defaultAclPath(projectId, dataset) {
|
|
60
60
|
return `/projects/${projectId}/datasets/${dataset}/acl`;
|
|
61
61
|
}
|
|
62
|
-
function
|
|
62
|
+
function projectUserOf(identity, projectId) {
|
|
63
|
+
return identity.usersByProject?.[projectId] ?? identity.user;
|
|
64
|
+
}
|
|
65
|
+
function serveProjectUsers(args) {
|
|
66
|
+
const { requestedIds, pathProjectId, identities } = args, toRecord = (identity) => {
|
|
67
|
+
const projectUser = projectUserOf(identity, pathProjectId);
|
|
68
|
+
return {
|
|
69
|
+
id: projectUser.id,
|
|
70
|
+
sanityUserId: identity.globalUser?.id ?? projectUser.id,
|
|
71
|
+
displayName: projectUser.name ?? projectUser.id,
|
|
72
|
+
...projectUser.email !== void 0 ? { email: projectUser.email } : {}
|
|
73
|
+
};
|
|
74
|
+
}, byId = /* @__PURE__ */ new Map();
|
|
75
|
+
for (const identity of identities) {
|
|
76
|
+
const resolvedId = projectUserOf(identity, pathProjectId).id, existing = byId.get(resolvedId);
|
|
77
|
+
if (existing !== void 0 && JSON.stringify(toRecord(existing)) !== JSON.stringify(toRecord(identity)))
|
|
78
|
+
throw fakeError(
|
|
79
|
+
`request(): two registered identities resolve to project user "${resolvedId}" in project "${pathProjectId}" with different records. The directory cannot answer unambiguously \u2014 fix the identity registrations so duplicate ids carry identical records.`
|
|
80
|
+
);
|
|
81
|
+
byId.set(resolvedId, identity);
|
|
82
|
+
}
|
|
83
|
+
const ids = requestedIds.split(","), [firstId] = ids;
|
|
84
|
+
if (ids.length === 1 && firstId !== void 0) {
|
|
85
|
+
const identity = byId.get(firstId);
|
|
86
|
+
if (identity === void 0)
|
|
87
|
+
throw Object.assign(
|
|
88
|
+
fakeError(
|
|
89
|
+
`request(): no registered identity resolves to project user "${firstId}" in project "${pathProjectId}". Register it via createTestClient({ identities }) or addIdentity().`
|
|
90
|
+
),
|
|
91
|
+
{ statusCode: 404 }
|
|
92
|
+
);
|
|
93
|
+
return toRecord(identity);
|
|
94
|
+
}
|
|
95
|
+
return ids.flatMap((id) => {
|
|
96
|
+
const identity = byId.get(id);
|
|
97
|
+
return identity === void 0 ? [] : [toRecord(identity)];
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const PROJECT_USERS_PATH = /^\/projects\/([^/]+)\/users\/([^/]+)$/;
|
|
101
|
+
function makeRequestImpl(ctx) {
|
|
102
|
+
const { getAccess, projectId, dataset, useProjectHostname, listIdentities } = ctx;
|
|
63
103
|
return async (opts) => {
|
|
64
104
|
const accessControl = getAccess(), aclPath = accessControl.aclPath ?? defaultAclPath(projectId, dataset), path = opts.uri ?? opts.url;
|
|
65
105
|
if (path === "/users/me")
|
|
66
|
-
return accessControl.currentUser;
|
|
106
|
+
return useProjectHostname ? accessControl.currentUser : accessControl.globalUser ?? accessControl.currentUser;
|
|
67
107
|
if (path === aclPath)
|
|
68
108
|
return accessControl.grants;
|
|
109
|
+
const projectUsers = path?.match(PROJECT_USERS_PATH), [, pathProjectId, requestedIds] = projectUsers ?? [];
|
|
110
|
+
if (pathProjectId !== void 0 && requestedIds !== void 0)
|
|
111
|
+
return serveProjectUsers({
|
|
112
|
+
requestedIds,
|
|
113
|
+
pathProjectId,
|
|
114
|
+
identities: listIdentities()
|
|
115
|
+
});
|
|
69
116
|
throw fakeError(
|
|
70
|
-
`request(): no handler for path "${path}". With access control configured, the fake
|
|
117
|
+
`request(): no handler for path "${path}". With access control configured, the fake serves "/users/me", "${aclPath}", and "/projects/<projectId>/users/<ids>". For any other endpoint, register a stub (client.stub("request", fn)) or intercept the HTTP call with a tool like MSW.`
|
|
71
118
|
);
|
|
72
119
|
};
|
|
73
120
|
}
|
|
@@ -778,7 +825,7 @@ const ISSUES_URL = "https://github.com/sanity-labs/client-fake-for-test/issues",
|
|
|
778
825
|
},
|
|
779
826
|
request: {
|
|
780
827
|
what: "generic HTTP request hook \u2014 only wired up when the handle has an acting identity",
|
|
781
|
-
workaround: "Create the client with `accessControl`, or bind a registered token (`identities` + `token` / `withConfig({ token })`), to enable request() (it serves /users/me
|
|
828
|
+
workaround: "Create the client with `accessControl`, or bind a registered token (`identities` + `token` / `withConfig({ token })`), to enable request() (it serves /users/me, the ACL path, and /projects/<projectId>/users/<ids>). Or register a stub."
|
|
782
829
|
},
|
|
783
830
|
dryRun: {
|
|
784
831
|
what: "not a method \u2014 did you mean the `{ dryRun }` mutation option?",
|
|
@@ -961,15 +1008,16 @@ function createTestClient(options = {}) {
|
|
|
961
1008
|
const { projectId, dataset } = parseRegistryKey(key);
|
|
962
1009
|
ensureStore(projectId, dataset).seed(docs);
|
|
963
1010
|
}
|
|
964
|
-
return makeHandle(
|
|
1011
|
+
return makeHandle({
|
|
965
1012
|
backend,
|
|
966
|
-
defaultProjectId,
|
|
967
|
-
defaultDataset,
|
|
968
|
-
options.accessControl,
|
|
969
|
-
options.perspective ?? "raw",
|
|
970
|
-
options.mutationGuard,
|
|
971
|
-
options.token
|
|
972
|
-
|
|
1013
|
+
projectId: defaultProjectId,
|
|
1014
|
+
dataset: defaultDataset,
|
|
1015
|
+
accessControl: options.accessControl,
|
|
1016
|
+
perspective: options.perspective ?? "raw",
|
|
1017
|
+
mutationGuard: options.mutationGuard,
|
|
1018
|
+
token: options.token,
|
|
1019
|
+
useProjectHostname: options.useProjectHostname ?? !0
|
|
1020
|
+
});
|
|
973
1021
|
}
|
|
974
1022
|
function dedupeIds(results) {
|
|
975
1023
|
const seen = /* @__PURE__ */ new Set(), out = [];
|
|
@@ -1021,13 +1069,26 @@ function toTxnMutations(operations) {
|
|
|
1021
1069
|
}
|
|
1022
1070
|
];
|
|
1023
1071
|
}
|
|
1024
|
-
function makeHandle(
|
|
1025
|
-
const {
|
|
1072
|
+
function makeHandle(handleArgs) {
|
|
1073
|
+
const {
|
|
1074
|
+
backend,
|
|
1075
|
+
projectId,
|
|
1076
|
+
dataset,
|
|
1077
|
+
accessControl,
|
|
1078
|
+
perspective,
|
|
1079
|
+
mutationGuard,
|
|
1080
|
+
token,
|
|
1081
|
+
useProjectHostname
|
|
1082
|
+
} = handleArgs, { registry } = backend, activeAccess = () => {
|
|
1026
1083
|
if (token === void 0) return accessControl;
|
|
1027
1084
|
const identity = backend.identities.get(token);
|
|
1028
1085
|
if (identity === void 0)
|
|
1029
1086
|
throw fakeError(`no identity is registered for token "${token}" (was it removed?).`);
|
|
1030
|
-
return {
|
|
1087
|
+
return {
|
|
1088
|
+
currentUser: projectUserOf(identity, projectId),
|
|
1089
|
+
...identity.globalUser !== void 0 ? { globalUser: identity.globalUser } : {},
|
|
1090
|
+
grants: identity.grants
|
|
1091
|
+
};
|
|
1031
1092
|
}, requireActiveAccess = () => {
|
|
1032
1093
|
const access = activeAccess();
|
|
1033
1094
|
if (access === void 0)
|
|
@@ -1348,20 +1409,35 @@ function makeHandle(backend, projectId, dataset, accessControl, perspective, mut
|
|
|
1348
1409
|
versionId: `versions.${releaseId}.${publishedId}`,
|
|
1349
1410
|
publishedId
|
|
1350
1411
|
}),
|
|
1351
|
-
...token !== void 0 || accessControl !== void 0 ? {
|
|
1352
|
-
|
|
1412
|
+
...token !== void 0 || accessControl !== void 0 ? {
|
|
1413
|
+
request: makeRequestImpl({
|
|
1414
|
+
getAccess: requireActiveAccess,
|
|
1415
|
+
projectId,
|
|
1416
|
+
dataset,
|
|
1417
|
+
useProjectHostname,
|
|
1418
|
+
listIdentities: () => [...backend.identities.values()]
|
|
1419
|
+
})
|
|
1420
|
+
} : {},
|
|
1421
|
+
config: () => ({
|
|
1422
|
+
projectId,
|
|
1423
|
+
dataset,
|
|
1424
|
+
perspective,
|
|
1425
|
+
...token !== void 0 ? { token } : {},
|
|
1426
|
+
useProjectHostname
|
|
1427
|
+
}),
|
|
1353
1428
|
withConfig: (config) => {
|
|
1354
1429
|
rejectAmbiguousIdentity("withConfig()", config), config.token !== void 0 && requireIdentity(backend, config.token, "withConfig()");
|
|
1355
1430
|
const rebinds = config.token !== void 0 || config.accessControl !== void 0;
|
|
1356
|
-
return makeHandle(
|
|
1431
|
+
return makeHandle({
|
|
1357
1432
|
backend,
|
|
1358
|
-
config.projectId ?? projectId,
|
|
1359
|
-
config.dataset ?? dataset,
|
|
1360
|
-
rebinds ? config.accessControl : accessControl,
|
|
1361
|
-
config.perspective ?? perspective,
|
|
1433
|
+
projectId: config.projectId ?? projectId,
|
|
1434
|
+
dataset: config.dataset ?? dataset,
|
|
1435
|
+
accessControl: rebinds ? config.accessControl : accessControl,
|
|
1436
|
+
perspective: config.perspective ?? perspective,
|
|
1362
1437
|
mutationGuard,
|
|
1363
|
-
rebinds ? config.token : token
|
|
1364
|
-
|
|
1438
|
+
token: rebinds ? config.token : token,
|
|
1439
|
+
useProjectHostname: config.useProjectHostname ?? useProjectHostname
|
|
1440
|
+
});
|
|
1365
1441
|
},
|
|
1366
1442
|
seed: (documents) => store.seed(documents),
|
|
1367
1443
|
add: (documents) => store.add(documents),
|