@stapel/workspaces-react 0.6.0 → 0.8.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 +56 -0
- package/dist/api/generated/schema.d.ts +774 -7
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/api/types.d.ts +104 -7
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/workspacesApi.d.ts +55 -1
- package/dist/api/workspacesApi.d.ts.map +1 -1
- package/dist/api/workspacesApi.js +23 -0
- package/dist/api/workspacesApi.js.map +1 -1
- package/dist/default/InviteAcceptPage.d.ts +28 -0
- package/dist/default/InviteAcceptPage.d.ts.map +1 -0
- package/dist/default/InviteAcceptPage.js +141 -0
- package/dist/default/InviteAcceptPage.js.map +1 -0
- package/dist/default/MembersManager.d.ts +4 -4
- package/dist/default/MembersManager.d.ts.map +1 -1
- package/dist/default/MembersManager.js +61 -56
- package/dist/default/MembersManager.js.map +1 -1
- package/dist/default/index.d.ts +2 -0
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +1 -0
- package/dist/default/index.js.map +1 -1
- package/dist/flows/inviteAcceptFlow.d.ts +155 -0
- package/dist/flows/inviteAcceptFlow.d.ts.map +1 -0
- package/dist/flows/inviteAcceptFlow.js +126 -0
- package/dist/flows/inviteAcceptFlow.js.map +1 -0
- package/dist/headless/Can.d.ts +40 -0
- package/dist/headless/Can.d.ts.map +1 -0
- package/dist/headless/Can.js +30 -0
- package/dist/headless/Can.js.map +1 -0
- package/dist/headless/InviteAcceptFlow.d.ts +44 -0
- package/dist/headless/InviteAcceptFlow.d.ts.map +1 -0
- package/dist/headless/InviteAcceptFlow.js +67 -0
- package/dist/headless/InviteAcceptFlow.js.map +1 -0
- package/dist/headless/RoleSelect.d.ts +41 -0
- package/dist/headless/RoleSelect.d.ts.map +1 -0
- package/dist/headless/RoleSelect.js +34 -0
- package/dist/headless/RoleSelect.js.map +1 -0
- package/dist/i18n/generated/errors.gen.d.ts +48 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
- package/dist/i18n/generated/errors.gen.js +24 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -1
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -1
- package/dist/i18n/generated/errors.ru.gen.js +8 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -1
- package/dist/i18n/keys.d.ts +28 -0
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +64 -0
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +30 -0
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +17 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/model/capabilities.d.ts +21 -0
- package/dist/model/capabilities.d.ts.map +1 -0
- package/dist/model/capabilities.js +32 -0
- package/dist/model/capabilities.js.map +1 -0
- package/dist/model/emailMask.d.ts +22 -0
- package/dist/model/emailMask.d.ts.map +1 -0
- package/dist/model/emailMask.js +36 -0
- package/dist/model/emailMask.js.map +1 -0
- package/dist/model/mutations.d.ts +107 -3
- package/dist/model/mutations.d.ts.map +1 -1
- package/dist/model/mutations.js +190 -1
- package/dist/model/mutations.js.map +1 -1
- package/dist/model/queries.d.ts +108 -2
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +139 -1
- package/dist/model/queries.js.map +1 -1
- package/dist/model/queryKeys.d.ts +12 -1
- package/dist/model/queryKeys.d.ts.map +1 -1
- package/dist/model/queryKeys.js +25 -0
- package/dist/model/queryKeys.js.map +1 -1
- package/dist/model/stepUp.d.ts +25 -0
- package/dist/model/stepUp.d.ts.map +1 -0
- package/dist/model/stepUp.js +79 -0
- package/dist/model/stepUp.js.map +1 -0
- package/llms.txt +49 -15
- package/manifest.json +346 -3
- package/package.json +5 -5
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +774 -7
- package/src/api/types.ts +113 -7
- package/src/api/workspacesApi.ts +137 -0
- package/src/default/InviteAcceptPage.tsx +373 -0
- package/src/default/MembersManager.tsx +155 -145
- package/src/default/index.ts +2 -0
- package/src/flows/inviteAcceptFlow.ts +289 -0
- package/src/headless/Can.tsx +49 -0
- package/src/headless/InviteAcceptFlow.tsx +105 -0
- package/src/headless/RoleSelect.tsx +58 -0
- package/src/i18n/generated/errors.gen.ts +24 -0
- package/src/i18n/generated/errors.json +62 -0
- package/src/i18n/generated/errors.ru.gen.ts +8 -0
- package/src/i18n/keys.ts +68 -0
- package/src/i18n/ru.ts +34 -0
- package/src/index.ts +54 -1
- package/src/model/capabilities.ts +37 -0
- package/src/model/emailMask.ts +37 -0
- package/src/model/mutations.ts +248 -4
- package/src/model/queries.ts +205 -2
- package/src/model/queryKeys.ts +45 -1
- package/src/model/stepUp.ts +96 -0
package/dist/model/mutations.js
CHANGED
|
@@ -116,6 +116,157 @@ export function useRemoveMember(workspaceId) {
|
|
|
116
116
|
};
|
|
117
117
|
return useMutation(options);
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Withdraw a live invitation (POST /{id}/invitations/{invitationId}/revoke,
|
|
121
|
+
* #109). The variable is the invitation id; the reply is the UPDATED row, so
|
|
122
|
+
* it is written straight into the page cache the table reads — a revoke is
|
|
123
|
+
* the mirror of the invitee's decline and both must stay distinguishable in
|
|
124
|
+
* `status`, which a blind refetch-and-hope would blur. Only a `pending`
|
|
125
|
+
* invitation is revocable: the backend answers
|
|
126
|
+
* `error.400.invitation_already_used` / `_revoked` / `_expired` otherwise
|
|
127
|
+
* (each its own key, not a shrug). Also refreshes the member list — the seat
|
|
128
|
+
* the invitation reserved is freed on commit.
|
|
129
|
+
*/
|
|
130
|
+
export function useRevokeInvitation(workspaceId) {
|
|
131
|
+
const api = useWorkspacesApi();
|
|
132
|
+
const queryClient = useQueryClient();
|
|
133
|
+
const options = {
|
|
134
|
+
mutationFn: (invitationId) => api.revokeInvitation(workspaceId, invitationId),
|
|
135
|
+
onSuccess: () => {
|
|
136
|
+
void queryClient.invalidateQueries({
|
|
137
|
+
queryKey: workspacesQueryKeys.invitations(workspaceId),
|
|
138
|
+
});
|
|
139
|
+
void queryClient.invalidateQueries({
|
|
140
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
return useMutation(options);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Send the invitation email again (POST /{id}/invitations/{invitationId}/resend,
|
|
148
|
+
* #109). The variable is the invitation id.
|
|
149
|
+
*
|
|
150
|
+
* This is NOT an idempotent "poke": the backend rotates the token and
|
|
151
|
+
* restarts the TTL, so every earlier link — including the one already in the
|
|
152
|
+
* invitee's inbox — stops working, and the row's `expires_at` moves. Hence
|
|
153
|
+
* the invalidation: a table still showing the old expiry would be lying about
|
|
154
|
+
* a live credential. An EXPIRED invitation is accepted on purpose (a dead TTL
|
|
155
|
+
* is the commonest reason to resend); reviving it re-reserves a seat, so a
|
|
156
|
+
* plan ceiling can answer 402 here.
|
|
157
|
+
*/
|
|
158
|
+
export function useResendInvitation(workspaceId) {
|
|
159
|
+
const api = useWorkspacesApi();
|
|
160
|
+
const queryClient = useQueryClient();
|
|
161
|
+
const options = {
|
|
162
|
+
mutationFn: (invitationId) => api.resendInvitation(workspaceId, invitationId),
|
|
163
|
+
onSuccess: () => {
|
|
164
|
+
void queryClient.invalidateQueries({
|
|
165
|
+
queryKey: workspacesQueryKeys.invitations(workspaceId),
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
return useMutation(options);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Reset a member's password on the organization's order
|
|
173
|
+
* (POST /{id}/members/{userId}/password/reset, #110).
|
|
174
|
+
*
|
|
175
|
+
* **Step-up before the button.** Capability `members.password.reset` is
|
|
176
|
+
* declared `high`, so the backend wraps the endpoint in
|
|
177
|
+
* `requires_verification(scope="sensitive")`. Ask
|
|
178
|
+
* {@link "./queries.js".useCapabilityGate}(workspaceId,
|
|
179
|
+
* "members.password.reset") BEFORE offering the affordance: it answers both
|
|
180
|
+
* "may this caller" and "will a step-up be demanded". A step-up CHALLENGE is
|
|
181
|
+
* then driven by core's client and replayed transparently; the one case that
|
|
182
|
+
* is not transparent is the ENROLLMENT demand (the caller holds no factor to
|
|
183
|
+
* challenge) — read it off `error` with
|
|
184
|
+
* {@link "./stepUp.js".readVerificationEnrollment} and route to enrollment.
|
|
185
|
+
*
|
|
186
|
+
* **The one-shot credential.** `generated_password` comes back exactly once,
|
|
187
|
+
* only when the request omitted `password`, and can never be re-fetched. It
|
|
188
|
+
* is therefore deliberately kept OUT of the query cache: nothing here writes
|
|
189
|
+
* the response with `setQueryData`, and `gcTime: 0` drops the mutation result
|
|
190
|
+
* the moment the screen showing it unmounts. Writing it to a query would
|
|
191
|
+
* mean writing a live credential into every devtools panel AND into
|
|
192
|
+
* `localStorage`, because core's query runtime persists the whole per-user
|
|
193
|
+
* query cache (`createStapelQueryClient`). Hand it to the member out of band.
|
|
194
|
+
*
|
|
195
|
+
* Refreshes the member list (the reset moves the member's first-login state);
|
|
196
|
+
* a target that is not a resettable member of THIS workspace answers one
|
|
197
|
+
* byte-identical 404, never an existence oracle.
|
|
198
|
+
*/
|
|
199
|
+
export function useResetMemberPassword(workspaceId) {
|
|
200
|
+
const api = useWorkspacesApi();
|
|
201
|
+
const queryClient = useQueryClient();
|
|
202
|
+
const options = {
|
|
203
|
+
mutationFn: ({ userId, body }) => api.resetMemberPassword(workspaceId, userId, body),
|
|
204
|
+
// The result carries a live credential: never retained past the screen
|
|
205
|
+
// that displays it, and never persisted.
|
|
206
|
+
gcTime: 0,
|
|
207
|
+
onSuccess: () => {
|
|
208
|
+
void queryClient.invalidateQueries({
|
|
209
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
return useMutation(options);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Update a workspace's SECURITY settings (the `security` block of
|
|
217
|
+
* `PATCH /{id}`, org-program §C3) — `require_mfa` and the first-login
|
|
218
|
+
* `provisioned_user_policies`.
|
|
219
|
+
*
|
|
220
|
+
* Separate from {@link useUpdateWorkspace} because the backend treats this
|
|
221
|
+
* block as a different endpoint in all but the URL: an extra capability
|
|
222
|
+
* (`workspace.security.manage`, declared `high`) plus a step-up on the same
|
|
223
|
+
* `sensitive` scope as the password reset, and turning `require_mfa` on
|
|
224
|
+
* sweeps the current members. See {@link useResetMemberPassword} for how to
|
|
225
|
+
* wire that in front of the control.
|
|
226
|
+
*
|
|
227
|
+
* `provisioned_user_policies` is a LIST since stapel-workspaces 0.13.0 (#90)
|
|
228
|
+
* — independent checkboxes, not alternatives. An explicit `[]` is a
|
|
229
|
+
* deliberate, auditable choice ("demand nothing"), so it is sent as such and
|
|
230
|
+
* never dropped as "empty means unset".
|
|
231
|
+
*
|
|
232
|
+
* MERGES, because the backend does not: `PATCH` assigns `settings` wholesale
|
|
233
|
+
* (`ws.settings = data.settings`), so sending a bare `{security: …}` would
|
|
234
|
+
* silently drop every other key the workspace holds. The merge reads the
|
|
235
|
+
* workspace fresh rather than trusting the detail cache — a stale snapshot
|
|
236
|
+
* here would resurrect settings somebody else has since removed.
|
|
237
|
+
*/
|
|
238
|
+
export function useUpdateSecuritySettings(workspaceId) {
|
|
239
|
+
const api = useWorkspacesApi();
|
|
240
|
+
const queryClient = useQueryClient();
|
|
241
|
+
const options = {
|
|
242
|
+
mutationFn: async (patch) => {
|
|
243
|
+
const current = await api.getWorkspace(workspaceId);
|
|
244
|
+
const settings = (current.settings ?? {});
|
|
245
|
+
const security = (settings["security"] ?? {});
|
|
246
|
+
// `policies_configured` is derived and read-only on the wire — never
|
|
247
|
+
// sent back, whatever a caller spread into the patch.
|
|
248
|
+
const { policies_configured: _derived, ...writable } = {
|
|
249
|
+
...security,
|
|
250
|
+
...patch,
|
|
251
|
+
};
|
|
252
|
+
return api.updateWorkspace(workspaceId, {
|
|
253
|
+
settings: { ...settings, security: writable },
|
|
254
|
+
});
|
|
255
|
+
},
|
|
256
|
+
onSuccess: (updated) => {
|
|
257
|
+
queryClient.setQueryData(workspacesQueryKeys.detail(workspaceId), updated);
|
|
258
|
+
void queryClient.invalidateQueries({
|
|
259
|
+
queryKey: workspacesQueryKeys.list(),
|
|
260
|
+
});
|
|
261
|
+
// require_mfa ON suspends members without a strong factor; OFF lifts
|
|
262
|
+
// those suspensions. Either way the roster just moved.
|
|
263
|
+
void queryClient.invalidateQueries({
|
|
264
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
return useMutation(options);
|
|
269
|
+
}
|
|
119
270
|
/**
|
|
120
271
|
* Accept an invitation by its token — the caller joins the workspace. A dead
|
|
121
272
|
* token surfaces a localizable `StapelApiError` (`error.400.invitation_expired`
|
|
@@ -127,10 +278,48 @@ export function useAcceptInvitation() {
|
|
|
127
278
|
const queryClient = useQueryClient();
|
|
128
279
|
const options = {
|
|
129
280
|
mutationFn: (body) => api.acceptInvitation(body),
|
|
130
|
-
onSuccess: () => {
|
|
281
|
+
onSuccess: (_member, body) => {
|
|
131
282
|
void queryClient.invalidateQueries({
|
|
132
283
|
queryKey: workspacesQueryKeys.list(),
|
|
133
284
|
});
|
|
285
|
+
// The preview's `status` moved pending → accepted.
|
|
286
|
+
void queryClient.invalidateQueries({
|
|
287
|
+
queryKey: workspacesQueryKeys.invitationPreview(body.token),
|
|
288
|
+
});
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
return useMutation(options);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Mint a login grant for a NOT-yet-registered invitee (POST
|
|
295
|
+
* /invitations/{token}/claim, AllowAny — org-program §B2/§B3). The variable
|
|
296
|
+
* is the invite token; the result carries the single-use `grant_token` to
|
|
297
|
+
* exchange at AUTH's `POST /grant/exchange/` (the auth-react api — this pair
|
|
298
|
+
* deliberately does not call it; see `InviteAcceptFlow`'s `onLoginGrant`
|
|
299
|
+
* seam). 409 `email_already_registered` → switch to login. The invitation is
|
|
300
|
+
* NOT consumed here. The grant token is a credential: never log it.
|
|
301
|
+
*/
|
|
302
|
+
export function useClaimInvitation() {
|
|
303
|
+
const api = useWorkspacesApi();
|
|
304
|
+
const options = {
|
|
305
|
+
mutationFn: (token) => api.claimInvitation(token),
|
|
306
|
+
};
|
|
307
|
+
return useMutation(options);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Decline an invitation (POST /invitations/{token}/decline, authenticated +
|
|
311
|
+
* email-match — org-program §B2). The variable is the invite token. Decline ≠
|
|
312
|
+
* revoke — the preview's `status` becomes `declined`.
|
|
313
|
+
*/
|
|
314
|
+
export function useDeclineInvitation() {
|
|
315
|
+
const api = useWorkspacesApi();
|
|
316
|
+
const queryClient = useQueryClient();
|
|
317
|
+
const options = {
|
|
318
|
+
mutationFn: (token) => api.declineInvitation(token),
|
|
319
|
+
onSuccess: (_result, token) => {
|
|
320
|
+
void queryClient.invalidateQueries({
|
|
321
|
+
queryKey: workspacesQueryKeys.invitationPreview(token),
|
|
322
|
+
});
|
|
134
323
|
},
|
|
135
324
|
};
|
|
136
325
|
return useMutation(options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/model/mutations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/model/mutations.ts"],"names":[],"mappings":"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"}
|
package/dist/model/queries.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { UseQueryResult } from "@tanstack/react-query";
|
|
1
|
+
import type { InfiniteData, UseInfiniteQueryResult, UseQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { StapelApiError } from "@stapel/core";
|
|
3
|
-
import type { MemberPage, MembersParams, Workspace, WorkspaceList } from "../api/types.js";
|
|
3
|
+
import type { InvitationPage, InvitationPreview, InvitationsParams, MemberPage, MembersParams, RoleInfo, Workspace, WorkspaceList } from "../api/types.js";
|
|
4
|
+
import type { CapabilityLevel } from "./stepUp.js";
|
|
4
5
|
/**
|
|
5
6
|
* Read hooks over the workspaces API. Staleness follows core's query defaults;
|
|
6
7
|
* override per call site via a page that needs fresher data. Keys are
|
|
@@ -34,4 +35,109 @@ export declare function useWorkspace(workspaceId: string | null): UseQueryResult
|
|
|
34
35
|
* to a specific page or filter; omit for the newest page (default limit 100).
|
|
35
36
|
*/
|
|
36
37
|
export declare function useMembers(workspaceId: string | null, params?: MembersParams): UseQueryResult<MemberPage, StapelApiError>;
|
|
38
|
+
/**
|
|
39
|
+
* One page of a workspace's invitations (GET /{id}/invitations, #109) — the
|
|
40
|
+
* admin's "who has not accepted yet" table. Disabled until a `workspaceId` is
|
|
41
|
+
* given (and the session is ready — see {@link useWorkspace}).
|
|
42
|
+
*
|
|
43
|
+
* ANCHOR pagination, exactly like {@link useMembers}: pass a page's
|
|
44
|
+
* `next_anchor` as `anchor` to walk forward. There is no page NUMBER — an
|
|
45
|
+
* offset would skew the moment an invitation is revoked or accepted while the
|
|
46
|
+
* admin is reading, which on this screen is the normal case, not the edge one.
|
|
47
|
+
* For scroll-to-load-more use {@link useInfiniteInvitations}.
|
|
48
|
+
*
|
|
49
|
+
* `status` defaults to the backend's `pending` (live, seat-reserving
|
|
50
|
+
* invitations); pass `never_accepted` to include declined/revoked/expired, or
|
|
51
|
+
* `all` for the full history.
|
|
52
|
+
*/
|
|
53
|
+
export declare function useInvitations(workspaceId: string | null, params?: InvitationsParams): UseQueryResult<InvitationPage, StapelApiError>;
|
|
54
|
+
/**
|
|
55
|
+
* A workspace's invitations as an infinite (load-more) list. Follows the
|
|
56
|
+
* backend's ANCHOR pagination and nothing else: the page param IS the
|
|
57
|
+
* previous page's `next_anchor`, and the walk stops when `has_next` goes
|
|
58
|
+
* false. `data.pages.flatMap(p => p.items)` is the flat row list.
|
|
59
|
+
*
|
|
60
|
+
* `filters` (`status` / `search` / `limit`) are part of the query key, so
|
|
61
|
+
* flipping the status tab starts a fresh anchor walk rather than appending
|
|
62
|
+
* rows of one filter to the pages of another.
|
|
63
|
+
*/
|
|
64
|
+
export declare function useInfiniteInvitations(workspaceId: string | null, filters?: Omit<InvitationsParams, "anchor" | "direction">): UseInfiniteQueryResult<InfiniteData<InvitationPage, string | undefined>, StapelApiError>;
|
|
65
|
+
/**
|
|
66
|
+
* The effective role registry (GET /roles, org-program §A2): builtin four +
|
|
67
|
+
* the deployment's `STAPEL_WORKSPACES["ROLES"]` overlay, capability strings
|
|
68
|
+
* verbatim, rank-descending. Deployment-static data — role UI (RoleSelect)
|
|
69
|
+
* reads this instead of hardcoding the builtin four. Session-ready-gated like
|
|
70
|
+
* {@link useWorkspaces} (IsAuthenticated endpoint, mounts at screen top).
|
|
71
|
+
*/
|
|
72
|
+
export declare function useRoles(): UseQueryResult<readonly RoleInfo[], StapelApiError>;
|
|
73
|
+
/**
|
|
74
|
+
* Public invitation preview (GET /invitations/{token}, AllowAny — org-program
|
|
75
|
+
* §B2): what the `/invite/{token}` page renders BEFORE any auth decision.
|
|
76
|
+
* Deliberately NOT session-gated — the whole point is that the invitee may
|
|
77
|
+
* have no session at all; the token in the URL is the bearer secret.
|
|
78
|
+
*/
|
|
79
|
+
export declare function useInvitationPreview(token: string | null): UseQueryResult<InvitationPreview, StapelApiError>;
|
|
80
|
+
/** What {@link useCapabilities} returns: the caller's granted capability
|
|
81
|
+
* strings in one workspace plus the wildcard-aware `can()` check. */
|
|
82
|
+
export interface CapabilitiesResult {
|
|
83
|
+
/** Verbatim registry strings of the caller's role (wildcards included);
|
|
84
|
+
* empty while loading or when the caller is not a member. */
|
|
85
|
+
readonly capabilities: readonly string[];
|
|
86
|
+
/** Wildcard-aware check (`*` / `prefix.*` — the backend matcher, ported).
|
|
87
|
+
* UI convenience only: the backend re-checks on every operation. */
|
|
88
|
+
can(capability: string): boolean;
|
|
89
|
+
readonly isLoading: boolean;
|
|
90
|
+
readonly isError: boolean;
|
|
91
|
+
readonly error: StapelApiError | null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The caller's capabilities in one workspace (org-program §A2): reads
|
|
95
|
+
* `my_capabilities` off the workspace detail (`WorkspaceResponse`, additive
|
|
96
|
+
* field since stapel-workspaces 0.6.0) and exposes the ported wildcard
|
|
97
|
+
* matcher. Deny-by-default: `can()` is false while loading, on error, or when
|
|
98
|
+
* the backend predates the field.
|
|
99
|
+
*/
|
|
100
|
+
export declare function useCapabilities(workspaceId: string | null): CapabilitiesResult;
|
|
101
|
+
/** What {@link useCapabilityGate} answers about ONE capability, BEFORE the
|
|
102
|
+
* operation is attempted. */
|
|
103
|
+
export interface CapabilityGate {
|
|
104
|
+
/** The capability asked about, verbatim. */
|
|
105
|
+
readonly capability: string;
|
|
106
|
+
/** Does the caller's role carry it? Deny-by-default while loading. */
|
|
107
|
+
readonly allowed: boolean;
|
|
108
|
+
/** Its declared step-up level (ported registry — see `./stepUp.js`). */
|
|
109
|
+
readonly level: CapabilityLevel;
|
|
110
|
+
/** True when `level === "high"`: the backend ALSO demands a fresh
|
|
111
|
+
* verification (scope {@link SENSITIVE_SCOPE}) on top of the capability. */
|
|
112
|
+
readonly requiresStepUp: boolean;
|
|
113
|
+
/** The verification scope of that demand, or `null` at `standard`. */
|
|
114
|
+
readonly stepUpScope: string | null;
|
|
115
|
+
readonly isLoading: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Ask about one capability BEFORE offering the operation (org-program §A3).
|
|
119
|
+
*
|
|
120
|
+
* Two different answers, both needed in front of the button rather than
|
|
121
|
+
* behind it:
|
|
122
|
+
*
|
|
123
|
+
* * `allowed` — the caller's role carries the mandate. UI convenience only,
|
|
124
|
+
* deny-by-default; the backend re-checks. This is what replaces guessing
|
|
125
|
+
* access from the ROLE NAME: a deployment role like `secretary` can hold
|
|
126
|
+
* `members.invite` and would still fail a `role === "admin"` test forever,
|
|
127
|
+
* no matter what the registry says.
|
|
128
|
+
* * `requiresStepUp` — the operation is declared `high`, so a fresh step-up
|
|
129
|
+
* verification is demanded on top. Knowing this up front is what lets a
|
|
130
|
+
* screen say "you'll be asked to confirm" (or pre-drive enrollment)
|
|
131
|
+
* instead of showing a button that answers 403.
|
|
132
|
+
*
|
|
133
|
+
* Example — the administrative password reset:
|
|
134
|
+
* ```tsx
|
|
135
|
+
* const gate = useCapabilityGate(workspaceId, "members.password.reset");
|
|
136
|
+
* // gate.allowed === false → do not render the button at all
|
|
137
|
+
* // gate.requiresStepUp → render it with the "we will ask you to
|
|
138
|
+
* // confirm" affordance, wired to the app's
|
|
139
|
+
* // verification controller
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare function useCapabilityGate(workspaceId: string | null, capability: string): CapabilityGate;
|
|
37
143
|
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,iBAAiB,CAAC;AAKzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,IAAI,cAAc,CAAC,aAAa,EAAE,cAAc,CAAC,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC,CAQ3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAS5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,CAAC,EAAE,iBAAiB,GACzB,cAAc,CAAC,cAAc,EAAE,cAAc,CAAC,CAShD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,WAAW,CAAC,GACxD,sBAAsB,CACvB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,EAChD,cAAc,CACf,CAiBA;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,cAAc,CACxC,SAAS,QAAQ,EAAE,EACnB,cAAc,CACf,CAQA;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,cAAc,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAOnD;AAED;qEACqE;AACrE,MAAM,WAAW,kBAAkB;IACjC;iEAC6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;wEACoE;IACpE,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,kBAAkB,CAU9E;AAED;6BAC6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;gFAC4E;IAC5E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,MAAM,GACjB,cAAc,CAWhB"}
|
package/dist/model/queries.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { useQuery } from "@tanstack/react-query";
|
|
1
|
+
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
|
2
2
|
import { useActiveSessionReady } from "@stapel/core";
|
|
3
3
|
import { useWorkspacesApi } from "./context.js";
|
|
4
4
|
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
5
|
+
import { hasCapability } from "./capabilities.js";
|
|
6
|
+
import { SENSITIVE_SCOPE, capabilityLevel } from "./stepUp.js";
|
|
5
7
|
/**
|
|
6
8
|
* Read hooks over the workspaces API. Staleness follows core's query defaults;
|
|
7
9
|
* override per call site via a page that needs fresher data. Keys are
|
|
@@ -60,4 +62,140 @@ export function useMembers(workspaceId, params) {
|
|
|
60
62
|
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
61
63
|
});
|
|
62
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* One page of a workspace's invitations (GET /{id}/invitations, #109) — the
|
|
67
|
+
* admin's "who has not accepted yet" table. Disabled until a `workspaceId` is
|
|
68
|
+
* given (and the session is ready — see {@link useWorkspace}).
|
|
69
|
+
*
|
|
70
|
+
* ANCHOR pagination, exactly like {@link useMembers}: pass a page's
|
|
71
|
+
* `next_anchor` as `anchor` to walk forward. There is no page NUMBER — an
|
|
72
|
+
* offset would skew the moment an invitation is revoked or accepted while the
|
|
73
|
+
* admin is reading, which on this screen is the normal case, not the edge one.
|
|
74
|
+
* For scroll-to-load-more use {@link useInfiniteInvitations}.
|
|
75
|
+
*
|
|
76
|
+
* `status` defaults to the backend's `pending` (live, seat-reserving
|
|
77
|
+
* invitations); pass `never_accepted` to include declined/revoked/expired, or
|
|
78
|
+
* `all` for the full history.
|
|
79
|
+
*/
|
|
80
|
+
export function useInvitations(workspaceId, params) {
|
|
81
|
+
const api = useWorkspacesApi();
|
|
82
|
+
const sessionReady = useActiveSessionReady();
|
|
83
|
+
const p = params ?? {};
|
|
84
|
+
return useQuery({
|
|
85
|
+
queryKey: workspacesQueryKeys.invitationsPage(workspaceId ?? "", p),
|
|
86
|
+
queryFn: () => api.listInvitations(workspaceId, p),
|
|
87
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A workspace's invitations as an infinite (load-more) list. Follows the
|
|
92
|
+
* backend's ANCHOR pagination and nothing else: the page param IS the
|
|
93
|
+
* previous page's `next_anchor`, and the walk stops when `has_next` goes
|
|
94
|
+
* false. `data.pages.flatMap(p => p.items)` is the flat row list.
|
|
95
|
+
*
|
|
96
|
+
* `filters` (`status` / `search` / `limit`) are part of the query key, so
|
|
97
|
+
* flipping the status tab starts a fresh anchor walk rather than appending
|
|
98
|
+
* rows of one filter to the pages of another.
|
|
99
|
+
*/
|
|
100
|
+
export function useInfiniteInvitations(workspaceId, filters) {
|
|
101
|
+
const api = useWorkspacesApi();
|
|
102
|
+
const sessionReady = useActiveSessionReady();
|
|
103
|
+
const f = filters ?? {};
|
|
104
|
+
return useInfiniteQuery({
|
|
105
|
+
queryKey: workspacesQueryKeys.invitationsInfinite(workspaceId ?? "", f),
|
|
106
|
+
queryFn: ({ pageParam }) => api.listInvitations(workspaceId, {
|
|
107
|
+
...f,
|
|
108
|
+
direction: "next",
|
|
109
|
+
...(pageParam !== undefined ? { anchor: pageParam } : {}),
|
|
110
|
+
}),
|
|
111
|
+
initialPageParam: undefined,
|
|
112
|
+
getNextPageParam: (last) => last.has_next ? (last.next_anchor ?? undefined) : undefined,
|
|
113
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The effective role registry (GET /roles, org-program §A2): builtin four +
|
|
118
|
+
* the deployment's `STAPEL_WORKSPACES["ROLES"]` overlay, capability strings
|
|
119
|
+
* verbatim, rank-descending. Deployment-static data — role UI (RoleSelect)
|
|
120
|
+
* reads this instead of hardcoding the builtin four. Session-ready-gated like
|
|
121
|
+
* {@link useWorkspaces} (IsAuthenticated endpoint, mounts at screen top).
|
|
122
|
+
*/
|
|
123
|
+
export function useRoles() {
|
|
124
|
+
const api = useWorkspacesApi();
|
|
125
|
+
const sessionReady = useActiveSessionReady();
|
|
126
|
+
return useQuery({
|
|
127
|
+
queryKey: workspacesQueryKeys.roles(),
|
|
128
|
+
queryFn: async () => (await api.listRoles()).roles ?? [],
|
|
129
|
+
enabled: sessionReady,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Public invitation preview (GET /invitations/{token}, AllowAny — org-program
|
|
134
|
+
* §B2): what the `/invite/{token}` page renders BEFORE any auth decision.
|
|
135
|
+
* Deliberately NOT session-gated — the whole point is that the invitee may
|
|
136
|
+
* have no session at all; the token in the URL is the bearer secret.
|
|
137
|
+
*/
|
|
138
|
+
export function useInvitationPreview(token) {
|
|
139
|
+
const api = useWorkspacesApi();
|
|
140
|
+
return useQuery({
|
|
141
|
+
queryKey: workspacesQueryKeys.invitationPreview(token ?? ""),
|
|
142
|
+
queryFn: () => api.getInvitationPreview(token),
|
|
143
|
+
enabled: token !== null && token !== "",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The caller's capabilities in one workspace (org-program §A2): reads
|
|
148
|
+
* `my_capabilities` off the workspace detail (`WorkspaceResponse`, additive
|
|
149
|
+
* field since stapel-workspaces 0.6.0) and exposes the ported wildcard
|
|
150
|
+
* matcher. Deny-by-default: `can()` is false while loading, on error, or when
|
|
151
|
+
* the backend predates the field.
|
|
152
|
+
*/
|
|
153
|
+
export function useCapabilities(workspaceId) {
|
|
154
|
+
const query = useWorkspace(workspaceId);
|
|
155
|
+
const capabilities = query.data?.my_capabilities ?? [];
|
|
156
|
+
return {
|
|
157
|
+
capabilities,
|
|
158
|
+
can: (capability) => hasCapability(capabilities, capability),
|
|
159
|
+
isLoading: query.isLoading,
|
|
160
|
+
isError: query.isError,
|
|
161
|
+
error: query.error ?? null,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Ask about one capability BEFORE offering the operation (org-program §A3).
|
|
166
|
+
*
|
|
167
|
+
* Two different answers, both needed in front of the button rather than
|
|
168
|
+
* behind it:
|
|
169
|
+
*
|
|
170
|
+
* * `allowed` — the caller's role carries the mandate. UI convenience only,
|
|
171
|
+
* deny-by-default; the backend re-checks. This is what replaces guessing
|
|
172
|
+
* access from the ROLE NAME: a deployment role like `secretary` can hold
|
|
173
|
+
* `members.invite` and would still fail a `role === "admin"` test forever,
|
|
174
|
+
* no matter what the registry says.
|
|
175
|
+
* * `requiresStepUp` — the operation is declared `high`, so a fresh step-up
|
|
176
|
+
* verification is demanded on top. Knowing this up front is what lets a
|
|
177
|
+
* screen say "you'll be asked to confirm" (or pre-drive enrollment)
|
|
178
|
+
* instead of showing a button that answers 403.
|
|
179
|
+
*
|
|
180
|
+
* Example — the administrative password reset:
|
|
181
|
+
* ```tsx
|
|
182
|
+
* const gate = useCapabilityGate(workspaceId, "members.password.reset");
|
|
183
|
+
* // gate.allowed === false → do not render the button at all
|
|
184
|
+
* // gate.requiresStepUp → render it with the "we will ask you to
|
|
185
|
+
* // confirm" affordance, wired to the app's
|
|
186
|
+
* // verification controller
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function useCapabilityGate(workspaceId, capability) {
|
|
190
|
+
const { can, isLoading } = useCapabilities(workspaceId);
|
|
191
|
+
const level = capabilityLevel(capability);
|
|
192
|
+
return {
|
|
193
|
+
capability,
|
|
194
|
+
allowed: can(capability),
|
|
195
|
+
level,
|
|
196
|
+
requiresStepUp: level === "high",
|
|
197
|
+
stepUpScope: level === "high" ? SENSITIVE_SCOPE : null,
|
|
198
|
+
isLoading,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
63
201
|
//# sourceMappingURL=queries.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import type { MembersParams } from "../api/types.js";
|
|
1
|
+
import type { InvitationsParams, MembersParams } from "../api/types.js";
|
|
2
2
|
export declare const workspacesQueryKeys: {
|
|
3
3
|
readonly all: readonly ["workspaces"];
|
|
4
4
|
list(): readonly ["workspaces", "list"];
|
|
5
5
|
detail(workspaceId: string): readonly ["workspaces", "detail", string];
|
|
6
6
|
members(workspaceId: string): readonly ["workspaces", "members", string];
|
|
7
7
|
membersPage(workspaceId: string, params: MembersParams): readonly ["workspaces", "members", string, MembersParams];
|
|
8
|
+
invitations(workspaceId: string): readonly ["workspaces", "invitations", string];
|
|
9
|
+
invitationsPage(workspaceId: string, params: InvitationsParams): readonly ["workspaces", "invitations", string, InvitationsParams];
|
|
10
|
+
invitationsInfinite(workspaceId: string, filters: InvitationsParams): readonly [
|
|
11
|
+
"workspaces",
|
|
12
|
+
"invitations",
|
|
13
|
+
string,
|
|
14
|
+
"infinite",
|
|
15
|
+
InvitationsParams
|
|
16
|
+
];
|
|
17
|
+
roles(): readonly ["workspaces", "roles"];
|
|
18
|
+
invitationPreview(token: string): readonly ["workspaces", "invitation-preview", string];
|
|
8
19
|
};
|
|
9
20
|
//# sourceMappingURL=queryKeys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryKeys.d.ts","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"queryKeys.d.ts","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWxE,eAAO,MAAM,mBAAmB,EAAE;IAChC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IACtC,IAAI,IAAI,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IACzE,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,GACpB,SAAS,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7D,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACjF,eAAe,CACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,GACxB,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACrE,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,SAAS;QACV,YAAY;QACZ,aAAa;QACb,MAAM;QACN,UAAU;QACV,iBAAiB;KAClB,CAAC;IACF,KAAK,IAAI,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC1C,iBAAiB,CACf,KAAK,EAAE,MAAM,GACZ,SAAS,CAAC,YAAY,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;CAkC1D,CAAC"}
|
package/dist/model/queryKeys.js
CHANGED
|
@@ -14,5 +14,30 @@ export const workspacesQueryKeys = {
|
|
|
14
14
|
// invalidating `members(workspaceId)` (mutations.ts) drops every page.
|
|
15
15
|
members: (workspaceId) => [ROOT, "members", workspaceId],
|
|
16
16
|
membersPage: (workspaceId, params) => [ROOT, "members", workspaceId, params],
|
|
17
|
+
// Same prefix trick as `members`: the bare 3-tuple invalidates every page
|
|
18
|
+
// (and the infinite list, which keys on it) after a revoke / resend.
|
|
19
|
+
invitations: (workspaceId) => [ROOT, "invitations", workspaceId],
|
|
20
|
+
invitationsPage: (workspaceId, params) => [
|
|
21
|
+
ROOT,
|
|
22
|
+
"invitations",
|
|
23
|
+
workspaceId,
|
|
24
|
+
params,
|
|
25
|
+
],
|
|
26
|
+
// The infinite list carries its own marker segment: its cached value is an
|
|
27
|
+
// `InfiniteData` envelope, not a page, so it must never collide with a
|
|
28
|
+
// single-page key that happens to hold the same filters.
|
|
29
|
+
invitationsInfinite: (workspaceId, filters) => [
|
|
30
|
+
ROOT,
|
|
31
|
+
"invitations",
|
|
32
|
+
workspaceId,
|
|
33
|
+
"infinite",
|
|
34
|
+
filters,
|
|
35
|
+
],
|
|
36
|
+
roles: () => [ROOT, "roles"],
|
|
37
|
+
// NOTE: the key carries the invite TOKEN (a secret). Core's query persist
|
|
38
|
+
// scope is per-user and the preview response is already public-by-design
|
|
39
|
+
// (masked email only) — but hosts logging query keys should treat this one
|
|
40
|
+
// as sensitive.
|
|
41
|
+
invitationPreview: (token) => [ROOT, "invitation-preview", token],
|
|
17
42
|
};
|
|
18
43
|
//# sourceMappingURL=queryKeys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,YAAqB,CAAC;AAEnC,MAAM,CAAC,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,YAAqB,CAAC;AAEnC,MAAM,CAAC,MAAM,mBAAmB,GA4B5B;IACF,GAAG,EAAE,CAAC,IAAI,CAAC;IACX,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC;IACtD,kEAAkE;IAClE,uEAAuE;IACvE,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC;IACxD,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC;IAC5E,0EAA0E;IAC1E,qEAAqE;IACrE,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC;IAChE,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI;QACJ,aAAa;QACb,WAAW;QACX,MAAM;KACP;IACD,2EAA2E;IAC3E,uEAAuE;IACvE,yDAAyD;IACzD,mBAAmB,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI;QACJ,aAAa;QACb,WAAW;QACX,UAAU;QACV,OAAO;KACR;IACD,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;IAC5B,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,gBAAgB;IAChB,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,CAAC;CAClE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The verification scope every `high` workspace capability is gated under. */
|
|
2
|
+
export declare const SENSITIVE_SCOPE = "sensitive";
|
|
3
|
+
/** Step-up level of a capability. */
|
|
4
|
+
export type CapabilityLevel = "standard" | "high";
|
|
5
|
+
/** PORT of `BUILTIN_CAPABILITY_LEVELS` — everything unlisted is `standard`. */
|
|
6
|
+
export declare const BUILTIN_CAPABILITY_LEVELS: Readonly<Record<string, "high">>;
|
|
7
|
+
/** The declared step-up level of one capability string. */
|
|
8
|
+
export declare function capabilityLevel(capability: string): CapabilityLevel;
|
|
9
|
+
/**
|
|
10
|
+
* The 403 ENROLLMENT envelope: the caller must first enroll one of `factors`
|
|
11
|
+
* — there is no challenge to complete, so core cannot drive it.
|
|
12
|
+
*/
|
|
13
|
+
export interface VerificationEnrollment {
|
|
14
|
+
/** What the demand protects — `"sensitive"` for every `high` capability. */
|
|
15
|
+
readonly scope: string;
|
|
16
|
+
/** Interchangeable factors, any ONE of which unblocks the operation. */
|
|
17
|
+
readonly factors: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read the enrollment demand out of a rejected request, or `null` when the
|
|
21
|
+
* error is anything else (including a step-up CHALLENGE, which carries a
|
|
22
|
+
* `challenge_id` and is core's business, not the consumer's).
|
|
23
|
+
*/
|
|
24
|
+
export declare function readVerificationEnrollment(error: unknown): VerificationEnrollment | null;
|
|
25
|
+
//# sourceMappingURL=stepUp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepUp.d.ts","sourceRoot":"","sources":["../../src/model/stepUp.ts"],"names":[],"mappings":"AAiCA,+EAA+E;AAC/E,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,qCAAqC;AACrC,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,CAAC;AAElD,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItE,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAEnE;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAQD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,sBAAsB,GAAG,IAAI,CAoB/B"}
|