@sanity/access-ui 6.9.1
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/LICENSE +21 -0
- package/lib/index.d.ts +210 -0
- package/lib/index.js +468 -0
- package/lib/index.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 - 2026 Sanity.io
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { SanityClient } from "@sanity/client";
|
|
3
|
+
/**
|
|
4
|
+
* An access request as returned by the Access API (`GET /access/requests/me`).
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the DTO from the Access API service. The generated `@sanity/access-api`
|
|
7
|
+
* client is only published to Sanity's internal registry, so this package inlines
|
|
8
|
+
* the small slice of the wire contract it needs.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
interface AccessRequest {
|
|
13
|
+
id: string;
|
|
14
|
+
status: 'pending' | 'accepted' | 'declined';
|
|
15
|
+
resourceId: string;
|
|
16
|
+
resourceType: 'organization' | 'project';
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
updatedByUserId: string;
|
|
20
|
+
requestedByUserId: string;
|
|
21
|
+
requestedRole?: string;
|
|
22
|
+
type: 'access' | 'role';
|
|
23
|
+
note?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The kind of resource an access request targets.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
type AccessResourceType = 'organization' | 'project';
|
|
31
|
+
/**
|
|
32
|
+
* Where the caller stands on requesting access to a resource:
|
|
33
|
+
* - `pending` — a request is in review (less than 2 weeks old)
|
|
34
|
+
* - `denied` — a recent request was declined (less than 2 weeks old); can't re-request yet
|
|
35
|
+
* - `expired` — a prior request aged out; can request again
|
|
36
|
+
* - `none` — no relevant request; can request
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
type AccessRequestState = 'pending' | 'denied' | 'expired' | 'none';
|
|
41
|
+
/**
|
|
42
|
+
* Outcome of submitting an access request, mapping the Access API's error
|
|
43
|
+
* contract to a discriminated union:
|
|
44
|
+
* - `submitted` — the request was created
|
|
45
|
+
* - `denied` — 409; a recent request was declined or is already pending
|
|
46
|
+
* - `over-limit` — 429; the caller is over their cross-project request limit
|
|
47
|
+
* - `email-domain-blocked` — 409; the caller's email domain may not request access
|
|
48
|
+
* - `requests-disabled` — 409; the organization has disabled access requests
|
|
49
|
+
* - `sso-enforced` — 403 `saml_enforcement_required`; the organization only admits
|
|
50
|
+
* members through its SSO login flow, so the request can never be approved.
|
|
51
|
+
* `redirectUrl` is the IdP login URL when the API provides one.
|
|
52
|
+
* - `error` — any other failure
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
type SubmitAccessRequestResult = {
|
|
57
|
+
type: 'submitted';
|
|
58
|
+
request: AccessRequest | null;
|
|
59
|
+
} | {
|
|
60
|
+
type: 'denied';
|
|
61
|
+
message?: string;
|
|
62
|
+
} | {
|
|
63
|
+
type: 'over-limit';
|
|
64
|
+
message?: string;
|
|
65
|
+
} | {
|
|
66
|
+
type: 'email-domain-blocked';
|
|
67
|
+
message?: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: 'requests-disabled';
|
|
70
|
+
message?: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: 'sso-enforced';
|
|
73
|
+
redirectUrl?: string;
|
|
74
|
+
message?: string;
|
|
75
|
+
} | {
|
|
76
|
+
type: 'error';
|
|
77
|
+
error: unknown;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The current user rendered in the request-access screen. A structural subset of
|
|
81
|
+
* `CurrentUser` from `@sanity/types`, so both studio and app callers can pass
|
|
82
|
+
* their own user object without an extra dependency.
|
|
83
|
+
*
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
interface AccessUser {
|
|
87
|
+
name?: string;
|
|
88
|
+
email?: string;
|
|
89
|
+
provider?: string;
|
|
90
|
+
profileImage?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The Access API only accepts notes up to this length.
|
|
94
|
+
*
|
|
95
|
+
* @public
|
|
96
|
+
*/
|
|
97
|
+
declare const MAX_ACCESS_REQUEST_NOTE_LENGTH = 150;
|
|
98
|
+
/**
|
|
99
|
+
* Fetches the caller's own access requests across all resources
|
|
100
|
+
* (`GET /access/requests/me`).
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
declare function listMyAccessRequests(client: SanityClient): Promise<AccessRequest[]>;
|
|
105
|
+
/**
|
|
106
|
+
* Submits an access request (`POST /access/{resourceType}/{resourceId}/requests`)
|
|
107
|
+
* and maps the Access API's error contract to a {@link SubmitAccessRequestResult}.
|
|
108
|
+
* Never throws for API rejections; unexpected failures come back as
|
|
109
|
+
* `{type: 'error'}` so callers decide how to surface them.
|
|
110
|
+
*
|
|
111
|
+
* @public
|
|
112
|
+
*/
|
|
113
|
+
declare function submitAccessRequest(options: {
|
|
114
|
+
client: SanityClient;
|
|
115
|
+
resourceType: AccessResourceType;
|
|
116
|
+
resourceId: string;
|
|
117
|
+
note?: string;
|
|
118
|
+
requestUrl?: string;
|
|
119
|
+
}): Promise<SubmitAccessRequestResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Derives where the caller stands on requesting access to a resource from
|
|
122
|
+
* their existing access requests.
|
|
123
|
+
*
|
|
124
|
+
* A declined request blocks re-requesting for two weeks. A pending request
|
|
125
|
+
* younger than two weeks is in review; older pending requests count as
|
|
126
|
+
* expired, and the caller may request again.
|
|
127
|
+
*
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
declare function deriveAccessRequestState(requests: AccessRequest[] | null | undefined, resourceId: string, now?: number): AccessRequestState;
|
|
131
|
+
/**
|
|
132
|
+
* All user-facing strings in the request-access screen. Every label can be
|
|
133
|
+
* overridden, so hosts with their own i18n stack (studio i18n, react-i18next)
|
|
134
|
+
* inject translated copy while standalone hosts get the English defaults.
|
|
135
|
+
*
|
|
136
|
+
* @public
|
|
137
|
+
*/
|
|
138
|
+
interface RequestAccessLabels {
|
|
139
|
+
title: ReactNode;
|
|
140
|
+
sentTitle: ReactNode;
|
|
141
|
+
deniedTitle: ReactNode;
|
|
142
|
+
errorTitle: ReactNode;
|
|
143
|
+
describeNoAccess: (context: {
|
|
144
|
+
email?: string;
|
|
145
|
+
}) => ReactNode;
|
|
146
|
+
promptProject: ReactNode;
|
|
147
|
+
promptOrganization: ReactNode;
|
|
148
|
+
notePlaceholder: string;
|
|
149
|
+
noteAriaLabel: string;
|
|
150
|
+
submit: ReactNode;
|
|
151
|
+
sentDescription: ReactNode;
|
|
152
|
+
pendingMessage: ReactNode;
|
|
153
|
+
deniedMessage: (context: {
|
|
154
|
+
message?: string;
|
|
155
|
+
}) => ReactNode;
|
|
156
|
+
overLimitMessage: (context: {
|
|
157
|
+
message?: string;
|
|
158
|
+
}) => ReactNode;
|
|
159
|
+
expiredMessage: ReactNode;
|
|
160
|
+
ssoEnforcedMessage: (context: {
|
|
161
|
+
providerTitle?: string;
|
|
162
|
+
}) => ReactNode;
|
|
163
|
+
ssoSignInCta: ReactNode;
|
|
164
|
+
submitFailedMessage: ReactNode;
|
|
165
|
+
wrongAccount: ReactNode;
|
|
166
|
+
signOut: ReactNode;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Human-readable title for a login provider id, e.g. `google` → `Google`,
|
|
170
|
+
* `saml-xyz` → `SAML/SSO`.
|
|
171
|
+
*
|
|
172
|
+
* @public
|
|
173
|
+
*/
|
|
174
|
+
declare function getProviderTitle(provider?: string): string | undefined;
|
|
175
|
+
/** @public */
|
|
176
|
+
interface RequestAccessFormProps {
|
|
177
|
+
/** Client authenticated as the requesting user. The Access API version is applied internally. */
|
|
178
|
+
client: SanityClient;
|
|
179
|
+
resourceType?: AccessResourceType;
|
|
180
|
+
/** Project or organization id to request access to. */
|
|
181
|
+
resourceId: string;
|
|
182
|
+
/** The signed-in user, rendered in the description and account footer. */
|
|
183
|
+
currentUser?: AccessUser | null;
|
|
184
|
+
/**
|
|
185
|
+
* Called when the user chooses "Sign out". The account footer's sign-out
|
|
186
|
+
* action is only rendered when provided; hosts own the actual sign-out
|
|
187
|
+
* mechanism (studio: `auth.logout()`, dashboard: logout route navigation).
|
|
188
|
+
*/
|
|
189
|
+
onSignOut?: () => void;
|
|
190
|
+
/** Called after a request is successfully submitted, e.g. for analytics. */
|
|
191
|
+
onRequestSubmitted?: () => void;
|
|
192
|
+
/** Optional slot rendered above the title, e.g. a resource preview. */
|
|
193
|
+
preview?: ReactNode;
|
|
194
|
+
/** Label overrides for hosts with their own i18n stack. */
|
|
195
|
+
labels?: Partial<RequestAccessLabels>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The shared request-access screen: explains that the signed-in account lacks
|
|
199
|
+
* access, lets the user request it with an optional note, and reflects the
|
|
200
|
+
* request lifecycle (pending, denied, expired, over-limit, SSO-enforced).
|
|
201
|
+
*
|
|
202
|
+
* Fetches the caller's existing requests on mount and suspends while loading;
|
|
203
|
+
* an internal `Suspense` boundary renders a spinner, so hosts can mount it
|
|
204
|
+
* directly. Remount with a `key` when `client` or `resourceId` change.
|
|
205
|
+
*
|
|
206
|
+
* @public
|
|
207
|
+
*/
|
|
208
|
+
declare function RequestAccessForm(props: RequestAccessFormProps): import("react").JSX.Element;
|
|
209
|
+
export { type AccessRequest, type AccessRequestState, type AccessResourceType, type AccessUser, MAX_ACCESS_REQUEST_NOTE_LENGTH, RequestAccessForm, type RequestAccessFormProps, type RequestAccessLabels, type SubmitAccessRequestResult, deriveAccessRequestState, getProviderTitle, listMyAccessRequests, submitAccessRequest };
|
|
210
|
+
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { LaunchIcon } from "@sanity/icons/Launch";
|
|
3
|
+
import { Avatar, Box, Button, Card, Flex, Spinner, Stack, Text, TextArea } from "@sanity/ui";
|
|
4
|
+
import { Suspense, use, useId, useState, useTransition } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
/**
|
|
7
|
+
* The Access API only accepts notes up to this length.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
const MAX_ACCESS_REQUEST_NOTE_LENGTH = 150;
|
|
12
|
+
function withAccessApiVersion(client) {
|
|
13
|
+
return client.withConfig({ apiVersion: "2024-07-01" });
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Fetches the caller's own access requests across all resources
|
|
17
|
+
* (`GET /access/requests/me`).
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
async function listMyAccessRequests(client) {
|
|
22
|
+
return await withAccessApiVersion(client).request({
|
|
23
|
+
url: "/access/requests/me",
|
|
24
|
+
tag: "access-ui.list-requests"
|
|
25
|
+
}) ?? [];
|
|
26
|
+
}
|
|
27
|
+
function getErrorResponseDetails(err) {
|
|
28
|
+
if (typeof err != "object" || !err) return {};
|
|
29
|
+
let response = err.response;
|
|
30
|
+
if (typeof response != "object" || !response) return {};
|
|
31
|
+
let { statusCode } = response, body = response.body, details = { statusCode: typeof statusCode == "number" ? statusCode : void 0 };
|
|
32
|
+
if (typeof body == "object" && body) {
|
|
33
|
+
let { message, code, redirectUrl } = body;
|
|
34
|
+
details.message = typeof message == "string" ? message : void 0, details.code = typeof code == "string" ? code : void 0, details.redirectUrl = typeof redirectUrl == "string" ? redirectUrl : void 0;
|
|
35
|
+
}
|
|
36
|
+
return details;
|
|
37
|
+
}
|
|
38
|
+
function mapSubmitError(err) {
|
|
39
|
+
let { statusCode, message, code, redirectUrl } = getErrorResponseDetails(err);
|
|
40
|
+
return statusCode === 403 && code === "saml_enforcement_required" ? {
|
|
41
|
+
type: "sso-enforced",
|
|
42
|
+
redirectUrl,
|
|
43
|
+
message
|
|
44
|
+
} : statusCode === 429 ? {
|
|
45
|
+
type: "over-limit",
|
|
46
|
+
message
|
|
47
|
+
} : statusCode === 409 ? message?.includes("email domain") ? {
|
|
48
|
+
type: "email-domain-blocked",
|
|
49
|
+
message
|
|
50
|
+
} : message?.includes("disabled for organization") ? {
|
|
51
|
+
type: "requests-disabled",
|
|
52
|
+
message
|
|
53
|
+
} : {
|
|
54
|
+
type: "denied",
|
|
55
|
+
message: message?.replace(/^Conflict -\s*/, "")
|
|
56
|
+
} : {
|
|
57
|
+
type: "error",
|
|
58
|
+
error: err
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Submits an access request (`POST /access/{resourceType}/{resourceId}/requests`)
|
|
63
|
+
* and maps the Access API's error contract to a {@link SubmitAccessRequestResult}.
|
|
64
|
+
* Never throws for API rejections; unexpected failures come back as
|
|
65
|
+
* `{type: 'error'}` so callers decide how to surface them.
|
|
66
|
+
*
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
async function submitAccessRequest(options) {
|
|
70
|
+
let { client, resourceType, resourceId, note, requestUrl } = options;
|
|
71
|
+
try {
|
|
72
|
+
return {
|
|
73
|
+
type: "submitted",
|
|
74
|
+
request: await withAccessApiVersion(client).request({
|
|
75
|
+
url: `/access/${resourceType}/${resourceId}/requests`,
|
|
76
|
+
method: "post",
|
|
77
|
+
tag: "access-ui.submit-request",
|
|
78
|
+
body: {
|
|
79
|
+
note,
|
|
80
|
+
requestUrl,
|
|
81
|
+
type: "access"
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
} catch (err) {
|
|
86
|
+
return mapSubmitError(err);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Derives where the caller stands on requesting access to a resource from
|
|
91
|
+
* their existing access requests.
|
|
92
|
+
*
|
|
93
|
+
* A declined request blocks re-requesting for two weeks. A pending request
|
|
94
|
+
* younger than two weeks is in review; older pending requests count as
|
|
95
|
+
* expired, and the caller may request again.
|
|
96
|
+
*
|
|
97
|
+
* @public
|
|
98
|
+
*/
|
|
99
|
+
function deriveAccessRequestState(requests, resourceId, now = Date.now()) {
|
|
100
|
+
if (!requests || requests.length === 0) return "none";
|
|
101
|
+
let isRecent = (request) => now - new Date(request.createdAt).getTime() < 12096e5, forResource = requests.filter((request) => request.resourceId === resourceId);
|
|
102
|
+
return forResource.some((request) => request.status === "declined" && isRecent(request)) ? "denied" : forResource.some((request) => request.status === "pending" && isRecent(request)) ? "pending" : forResource.some((request) => request.status === "pending") ? "expired" : "none";
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Human-readable title for a login provider id, e.g. `google` → `Google`,
|
|
106
|
+
* `saml-xyz` → `SAML/SSO`.
|
|
107
|
+
*
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
function getProviderTitle(provider) {
|
|
111
|
+
if (provider === "google") return "Google";
|
|
112
|
+
if (provider === "github") return "GitHub";
|
|
113
|
+
if (provider === "sanity") return "Sanity";
|
|
114
|
+
if (provider === "vercel") return "Vercel";
|
|
115
|
+
if (provider?.startsWith("saml-")) return "SAML/SSO";
|
|
116
|
+
}
|
|
117
|
+
/** @internal */
|
|
118
|
+
const defaultLabels = {
|
|
119
|
+
title: "Request access",
|
|
120
|
+
sentTitle: "Access request sent",
|
|
121
|
+
deniedTitle: "Access request declined",
|
|
122
|
+
errorTitle: "Access request couldn’t be sent",
|
|
123
|
+
describeNoAccess: ({ email }) => email ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
124
|
+
"Your account ",
|
|
125
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
126
|
+
"(",
|
|
127
|
+
email,
|
|
128
|
+
")"
|
|
129
|
+
] }),
|
|
130
|
+
" doesn’t have access to this content."
|
|
131
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: "Your account doesn’t have access to this content." }),
|
|
132
|
+
promptProject: "Send a request to the project admin(s).",
|
|
133
|
+
promptOrganization: "Send a request to the organization admin(s).",
|
|
134
|
+
notePlaceholder: "Message (optional)",
|
|
135
|
+
noteAriaLabel: "Message",
|
|
136
|
+
submit: "Request access",
|
|
137
|
+
sentDescription: "Your request has been sent. You will receive a notification if access is approved.",
|
|
138
|
+
pendingMessage: "Your request to access this content is pending approval.",
|
|
139
|
+
deniedMessage: ({ message }) => message ?? "Your request to access this content has been declined.",
|
|
140
|
+
overLimitMessage: ({ message }) => message ?? "You’ve reached the limit for access requests across all projects. Please wait before submitting more requests, or contact an admin.",
|
|
141
|
+
expiredMessage: "Your previous request has expired. You may request access again below.",
|
|
142
|
+
ssoEnforcedMessage: ({ providerTitle }) => providerTitle ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
+
"You’re signed in with ",
|
|
144
|
+
/* @__PURE__ */ jsx("strong", { children: providerTitle }),
|
|
145
|
+
", but this organization requires signing in with SSO. Access can’t be requested with this account."
|
|
146
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: "This organization requires signing in with SSO. Access can’t be requested with this account." }),
|
|
147
|
+
ssoSignInCta: "Sign in with SSO",
|
|
148
|
+
submitFailedMessage: "There was a problem submitting your request. Please try again.",
|
|
149
|
+
wrongAccount: "Wrong account?",
|
|
150
|
+
signOut: "Sign out"
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* The shared request-access screen: explains that the signed-in account lacks
|
|
154
|
+
* access, lets the user request it with an optional note, and reflects the
|
|
155
|
+
* request lifecycle (pending, denied, expired, over-limit, SSO-enforced).
|
|
156
|
+
*
|
|
157
|
+
* Fetches the caller's existing requests on mount and suspends while loading;
|
|
158
|
+
* an internal `Suspense` boundary renders a spinner, so hosts can mount it
|
|
159
|
+
* directly. Remount with a `key` when `client` or `resourceId` change.
|
|
160
|
+
*
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
function RequestAccessForm(props) {
|
|
164
|
+
let $ = c(6), { client } = props, t0;
|
|
165
|
+
$[0] === client ? t0 = $[1] : (t0 = () => listMyAccessRequests(client).catch(_temp), $[0] = client, $[1] = t0);
|
|
166
|
+
let [requestsPromise] = useState(t0), t1;
|
|
167
|
+
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(Flex, {
|
|
168
|
+
align: "center",
|
|
169
|
+
height: "fill",
|
|
170
|
+
justify: "center",
|
|
171
|
+
padding: 5,
|
|
172
|
+
children: /* @__PURE__ */ jsx(Spinner, { muted: !0 })
|
|
173
|
+
}), $[2] = t1) : t1 = $[2];
|
|
174
|
+
let t2;
|
|
175
|
+
return $[3] !== props || $[4] !== requestsPromise ? (t2 = /* @__PURE__ */ jsx(Card, {
|
|
176
|
+
border: !0,
|
|
177
|
+
height: "fill",
|
|
178
|
+
overflow: "hidden",
|
|
179
|
+
radius: 3,
|
|
180
|
+
tone: "default",
|
|
181
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
182
|
+
fallback: t1,
|
|
183
|
+
children: /* @__PURE__ */ jsx(RequestAccessFormContent, {
|
|
184
|
+
...props,
|
|
185
|
+
requestsPromise
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
}), $[3] = props, $[4] = requestsPromise, $[5] = t2) : t2 = $[5], t2;
|
|
189
|
+
}
|
|
190
|
+
function _temp() {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function deriveViewState(options) {
|
|
194
|
+
let { fetchedRequests, resourceId, submitResult, labels } = options;
|
|
195
|
+
if (submitResult) switch (submitResult.type) {
|
|
196
|
+
case "submitted": return { view: "sent" };
|
|
197
|
+
case "sso-enforced": return {
|
|
198
|
+
view: "sso-enforced",
|
|
199
|
+
redirectUrl: submitResult.redirectUrl
|
|
200
|
+
};
|
|
201
|
+
case "denied": return {
|
|
202
|
+
view: "blocked",
|
|
203
|
+
title: labels.errorTitle,
|
|
204
|
+
message: labels.deniedMessage({ message: submitResult.message })
|
|
205
|
+
};
|
|
206
|
+
case "over-limit": return {
|
|
207
|
+
view: "blocked",
|
|
208
|
+
title: labels.errorTitle,
|
|
209
|
+
message: labels.overLimitMessage({ message: submitResult.message })
|
|
210
|
+
};
|
|
211
|
+
case "email-domain-blocked":
|
|
212
|
+
case "requests-disabled": return {
|
|
213
|
+
view: "blocked",
|
|
214
|
+
title: labels.errorTitle,
|
|
215
|
+
message: submitResult.message
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
let state = deriveAccessRequestState(fetchedRequests, resourceId);
|
|
219
|
+
return state === "pending" ? { view: "pending" } : state === "denied" ? {
|
|
220
|
+
view: "blocked",
|
|
221
|
+
title: labels.deniedTitle,
|
|
222
|
+
message: labels.deniedMessage({})
|
|
223
|
+
} : {
|
|
224
|
+
view: "form",
|
|
225
|
+
expired: state === "expired"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function RequestAccessFormContent(props) {
|
|
229
|
+
let $ = c(119), { client, resourceType: t0, resourceId, currentUser, onSignOut, onRequestSubmitted, preview, requestsPromise } = props, resourceType = t0 === void 0 ? "project" : t0, t1;
|
|
230
|
+
$[0] === props.labels ? t1 = $[1] : (t1 = {
|
|
231
|
+
...defaultLabels,
|
|
232
|
+
...props.labels
|
|
233
|
+
}, $[0] = props.labels, $[1] = t1);
|
|
234
|
+
let labels = t1, fetchedRequests = use(requestsPromise), titleId = useId(), [note, setNote] = useState(""), [submitResult, setSubmitResult] = useState(null), [isSubmitting, startSubmit] = useTransition(), t2;
|
|
235
|
+
$[2] !== fetchedRequests || $[3] !== labels || $[4] !== resourceId || $[5] !== submitResult ? (t2 = deriveViewState({
|
|
236
|
+
fetchedRequests,
|
|
237
|
+
resourceId,
|
|
238
|
+
submitResult,
|
|
239
|
+
labels
|
|
240
|
+
}), $[2] = fetchedRequests, $[3] = labels, $[4] = resourceId, $[5] = submitResult, $[6] = t2) : t2 = $[6];
|
|
241
|
+
let state = t2, T0, T1, handleSubmit, providerTitle, submitFailed, t10, t11, t12, t13, t3, t4, t5, t6, t7, t8, t9;
|
|
242
|
+
if ($[7] !== client || $[8] !== currentUser?.email || $[9] !== currentUser?.provider || $[10] !== isSubmitting || $[11] !== labels || $[12] !== note || $[13] !== onRequestSubmitted || $[14] !== preview || $[15] !== resourceId || $[16] !== resourceType || $[17] !== state.message || $[18] !== state.redirectUrl || $[19] !== state.title || $[20] !== state.view || $[21] !== submitResult?.type || $[22] !== titleId) {
|
|
243
|
+
providerTitle = getProviderTitle(currentUser?.provider), submitFailed = submitResult?.type === "error";
|
|
244
|
+
let t14 = labels.title, t15;
|
|
245
|
+
$[39] !== currentUser?.email || $[40] !== labels ? (t15 = labels.describeNoAccess({ email: currentUser?.email }), $[39] = currentUser?.email, $[40] = labels, $[41] = t15) : t15 = $[41];
|
|
246
|
+
let t16;
|
|
247
|
+
$[42] !== labels.title || $[43] !== t15 ? (t16 = {
|
|
248
|
+
title: t14,
|
|
249
|
+
description: t15
|
|
250
|
+
}, $[42] = labels.title, $[43] = t15, $[44] = t16) : t16 = $[44];
|
|
251
|
+
let t17;
|
|
252
|
+
$[45] !== labels.sentDescription || $[46] !== labels.sentTitle ? (t17 = {
|
|
253
|
+
title: labels.sentTitle,
|
|
254
|
+
description: labels.sentDescription
|
|
255
|
+
}, $[45] = labels.sentDescription, $[46] = labels.sentTitle, $[47] = t17) : t17 = $[47];
|
|
256
|
+
let t18;
|
|
257
|
+
$[48] !== labels.pendingMessage || $[49] !== labels.sentTitle ? (t18 = {
|
|
258
|
+
title: labels.sentTitle,
|
|
259
|
+
description: labels.pendingMessage
|
|
260
|
+
}, $[48] = labels.pendingMessage, $[49] = labels.sentTitle, $[50] = t18) : t18 = $[50];
|
|
261
|
+
let t19;
|
|
262
|
+
$[51] === labels.errorTitle ? t19 = $[52] : (t19 = {
|
|
263
|
+
title: labels.errorTitle,
|
|
264
|
+
description: null
|
|
265
|
+
}, $[51] = labels.errorTitle, $[52] = t19);
|
|
266
|
+
let t20;
|
|
267
|
+
$[53] !== t16 || $[54] !== t17 || $[55] !== t18 || $[56] !== t19 ? (t20 = {
|
|
268
|
+
form: t16,
|
|
269
|
+
sent: t17,
|
|
270
|
+
pending: t18,
|
|
271
|
+
"sso-enforced": t19
|
|
272
|
+
}, $[53] = t16, $[54] = t17, $[55] = t18, $[56] = t19, $[57] = t20) : t20 = $[57];
|
|
273
|
+
let heading = t20, t21;
|
|
274
|
+
$[58] !== heading || $[59] !== state.title || $[60] !== state.view ? (t21 = state.view === "blocked" ? {
|
|
275
|
+
title: state.title,
|
|
276
|
+
description: null
|
|
277
|
+
} : heading[state.view], $[58] = heading, $[59] = state.title, $[60] = state.view, $[61] = t21) : t21 = $[61];
|
|
278
|
+
let { title, description } = t21, t22;
|
|
279
|
+
$[62] !== client || $[63] !== isSubmitting || $[64] !== note || $[65] !== onRequestSubmitted || $[66] !== resourceId || $[67] !== resourceType ? (t22 = (event) => {
|
|
280
|
+
event.preventDefault(), !isSubmitting && startSubmit(async () => {
|
|
281
|
+
let result = await submitAccessRequest({
|
|
282
|
+
client,
|
|
283
|
+
resourceType,
|
|
284
|
+
resourceId,
|
|
285
|
+
note: note.trim() || void 0,
|
|
286
|
+
requestUrl: getRequestUrl()
|
|
287
|
+
});
|
|
288
|
+
setSubmitResult(result), result.type === "submitted" && onRequestSubmitted?.();
|
|
289
|
+
});
|
|
290
|
+
}, $[62] = client, $[63] = isSubmitting, $[64] = note, $[65] = onRequestSubmitted, $[66] = resourceId, $[67] = resourceType, $[68] = t22) : t22 = $[68], handleSubmit = t22, T1 = Flex, t12 = "column", t13 = "fill", T0 = Flex, t3 = "column", t4 = 1, t5 = 4, t6 = 4, $[69] === preview ? t7 = $[70] : (t7 = preview ? /* @__PURE__ */ jsx(Flex, {
|
|
291
|
+
justify: "center",
|
|
292
|
+
padding: 2,
|
|
293
|
+
children: preview
|
|
294
|
+
}) : null, $[69] = preview, $[70] = t7), $[71] !== title || $[72] !== titleId ? (t8 = /* @__PURE__ */ jsx(Text, {
|
|
295
|
+
as: "h1",
|
|
296
|
+
id: titleId,
|
|
297
|
+
size: 2,
|
|
298
|
+
weight: "semibold",
|
|
299
|
+
children: title
|
|
300
|
+
}), $[71] = title, $[72] = titleId, $[73] = t8) : t8 = $[73], $[74] === description ? t9 = $[75] : (t9 = description === null ? null : /* @__PURE__ */ jsx(Text, {
|
|
301
|
+
as: "p",
|
|
302
|
+
muted: !0,
|
|
303
|
+
size: 1,
|
|
304
|
+
children: description
|
|
305
|
+
}), $[74] = description, $[75] = t9), $[76] !== state.message || $[77] !== state.view ? (t10 = state.view === "blocked" ? /* @__PURE__ */ jsx(Card, {
|
|
306
|
+
border: !0,
|
|
307
|
+
padding: 3,
|
|
308
|
+
radius: 2,
|
|
309
|
+
role: "alert",
|
|
310
|
+
tone: "caution",
|
|
311
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
312
|
+
as: "p",
|
|
313
|
+
muted: !0,
|
|
314
|
+
size: 1,
|
|
315
|
+
children: state.message
|
|
316
|
+
})
|
|
317
|
+
}) : null, $[76] = state.message, $[77] = state.view, $[78] = t10) : t10 = $[78], t11 = state.view === "sso-enforced" ? /* @__PURE__ */ jsxs(Stack, {
|
|
318
|
+
gap: 4,
|
|
319
|
+
children: [/* @__PURE__ */ jsx(Card, {
|
|
320
|
+
border: !0,
|
|
321
|
+
padding: 3,
|
|
322
|
+
radius: 2,
|
|
323
|
+
role: "alert",
|
|
324
|
+
tone: "caution",
|
|
325
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
326
|
+
as: "p",
|
|
327
|
+
muted: !0,
|
|
328
|
+
size: 1,
|
|
329
|
+
children: labels.ssoEnforcedMessage({ providerTitle })
|
|
330
|
+
})
|
|
331
|
+
}), state.redirectUrl ? /* @__PURE__ */ jsx(Button, {
|
|
332
|
+
as: "a",
|
|
333
|
+
href: state.redirectUrl,
|
|
334
|
+
iconRight: LaunchIcon,
|
|
335
|
+
mode: "ghost",
|
|
336
|
+
text: labels.ssoSignInCta,
|
|
337
|
+
width: "fill"
|
|
338
|
+
}) : null]
|
|
339
|
+
}) : null, $[7] = client, $[8] = currentUser?.email, $[9] = currentUser?.provider, $[10] = isSubmitting, $[11] = labels, $[12] = note, $[13] = onRequestSubmitted, $[14] = preview, $[15] = resourceId, $[16] = resourceType, $[17] = state.message, $[18] = state.redirectUrl, $[19] = state.title, $[20] = state.view, $[21] = submitResult?.type, $[22] = titleId, $[23] = T0, $[24] = T1, $[25] = handleSubmit, $[26] = providerTitle, $[27] = submitFailed, $[28] = t10, $[29] = t11, $[30] = t12, $[31] = t13, $[32] = t3, $[33] = t4, $[34] = t5, $[35] = t6, $[36] = t7, $[37] = t8, $[38] = t9;
|
|
340
|
+
} else T0 = $[23], T1 = $[24], handleSubmit = $[25], providerTitle = $[26], submitFailed = $[27], t10 = $[28], t11 = $[29], t12 = $[30], t13 = $[31], t3 = $[32], t4 = $[33], t5 = $[34], t6 = $[35], t7 = $[36], t8 = $[37], t9 = $[38];
|
|
341
|
+
let t14;
|
|
342
|
+
$[79] !== handleSubmit || $[80] !== isSubmitting || $[81] !== labels.expiredMessage || $[82] !== labels.noteAriaLabel || $[83] !== labels.notePlaceholder || $[84] !== labels.promptOrganization || $[85] !== labels.promptProject || $[86] !== labels.submit || $[87] !== labels.submitFailedMessage || $[88] !== note || $[89] !== resourceType || $[90] !== state.expired || $[91] !== state.view || $[92] !== submitFailed || $[93] !== titleId ? (t14 = state.view === "form" ? /* @__PURE__ */ jsxs(Stack, {
|
|
343
|
+
as: "form",
|
|
344
|
+
"aria-labelledby": titleId,
|
|
345
|
+
onSubmit: handleSubmit,
|
|
346
|
+
gap: 4,
|
|
347
|
+
children: [
|
|
348
|
+
/* @__PURE__ */ jsx(Text, {
|
|
349
|
+
as: "p",
|
|
350
|
+
size: 1,
|
|
351
|
+
children: state.expired ? labels.expiredMessage : resourceType === "organization" ? labels.promptOrganization : labels.promptProject
|
|
352
|
+
}),
|
|
353
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
354
|
+
gap: 2,
|
|
355
|
+
children: [/* @__PURE__ */ jsx(TextArea, {
|
|
356
|
+
"aria-label": labels.noteAriaLabel,
|
|
357
|
+
disabled: isSubmitting,
|
|
358
|
+
fontSize: 1,
|
|
359
|
+
maxLength: 150,
|
|
360
|
+
onChange: (event_0) => setNote(event_0.currentTarget.value),
|
|
361
|
+
placeholder: labels.notePlaceholder,
|
|
362
|
+
rows: 3,
|
|
363
|
+
value: note
|
|
364
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
365
|
+
align: "right",
|
|
366
|
+
muted: !0,
|
|
367
|
+
size: 0,
|
|
368
|
+
children: `${note.length}/150`
|
|
369
|
+
})]
|
|
370
|
+
}),
|
|
371
|
+
submitFailed ? /* @__PURE__ */ jsx(Card, {
|
|
372
|
+
border: !0,
|
|
373
|
+
padding: 3,
|
|
374
|
+
radius: 2,
|
|
375
|
+
role: "alert",
|
|
376
|
+
tone: "critical",
|
|
377
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
378
|
+
as: "p",
|
|
379
|
+
muted: !0,
|
|
380
|
+
size: 1,
|
|
381
|
+
children: labels.submitFailedMessage
|
|
382
|
+
})
|
|
383
|
+
}) : null,
|
|
384
|
+
/* @__PURE__ */ jsx(Button, {
|
|
385
|
+
disabled: isSubmitting,
|
|
386
|
+
loading: isSubmitting,
|
|
387
|
+
text: labels.submit,
|
|
388
|
+
type: "submit",
|
|
389
|
+
width: "fill"
|
|
390
|
+
})
|
|
391
|
+
]
|
|
392
|
+
}) : null, $[79] = handleSubmit, $[80] = isSubmitting, $[81] = labels.expiredMessage, $[82] = labels.noteAriaLabel, $[83] = labels.notePlaceholder, $[84] = labels.promptOrganization, $[85] = labels.promptProject, $[86] = labels.submit, $[87] = labels.submitFailedMessage, $[88] = note, $[89] = resourceType, $[90] = state.expired, $[91] = state.view, $[92] = submitFailed, $[93] = titleId, $[94] = t14) : t14 = $[94];
|
|
393
|
+
let t15;
|
|
394
|
+
$[95] !== T0 || $[96] !== t10 || $[97] !== t11 || $[98] !== t14 || $[99] !== t3 || $[100] !== t4 || $[101] !== t5 || $[102] !== t6 || $[103] !== t7 || $[104] !== t8 || $[105] !== t9 ? (t15 = /* @__PURE__ */ jsxs(T0, {
|
|
395
|
+
direction: t3,
|
|
396
|
+
flex: t4,
|
|
397
|
+
gap: t5,
|
|
398
|
+
padding: t6,
|
|
399
|
+
children: [
|
|
400
|
+
t7,
|
|
401
|
+
t8,
|
|
402
|
+
t9,
|
|
403
|
+
t10,
|
|
404
|
+
t11,
|
|
405
|
+
t14
|
|
406
|
+
]
|
|
407
|
+
}), $[95] = T0, $[96] = t10, $[97] = t11, $[98] = t14, $[99] = t3, $[100] = t4, $[101] = t5, $[102] = t6, $[103] = t7, $[104] = t8, $[105] = t9, $[106] = t15) : t15 = $[106];
|
|
408
|
+
let t16;
|
|
409
|
+
$[107] !== currentUser || $[108] !== labels.signOut || $[109] !== labels.wrongAccount || $[110] !== onSignOut || $[111] !== providerTitle ? (t16 = currentUser ? /* @__PURE__ */ jsx(Card, {
|
|
410
|
+
borderTop: !0,
|
|
411
|
+
padding: 3,
|
|
412
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
413
|
+
align: "center",
|
|
414
|
+
direction: "column",
|
|
415
|
+
gap: 3,
|
|
416
|
+
children: [/* @__PURE__ */ jsxs(Flex, {
|
|
417
|
+
align: "center",
|
|
418
|
+
gap: 2,
|
|
419
|
+
justify: "center",
|
|
420
|
+
children: [/* @__PURE__ */ jsx(Avatar, {
|
|
421
|
+
initials: getInitials(currentUser),
|
|
422
|
+
size: 0,
|
|
423
|
+
src: currentUser.profileImage
|
|
424
|
+
}), /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, {
|
|
425
|
+
muted: !0,
|
|
426
|
+
size: 1,
|
|
427
|
+
textOverflow: "ellipsis",
|
|
428
|
+
children: [currentUser.email ?? currentUser.name, providerTitle ? ` · ${providerTitle}` : ""]
|
|
429
|
+
}) })]
|
|
430
|
+
}), onSignOut ? /* @__PURE__ */ jsx(Button, {
|
|
431
|
+
fontSize: 0,
|
|
432
|
+
mode: "bleed",
|
|
433
|
+
onClick: onSignOut,
|
|
434
|
+
padding: 2,
|
|
435
|
+
textWeight: "regular",
|
|
436
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
437
|
+
muted: !0,
|
|
438
|
+
size: 1,
|
|
439
|
+
children: [
|
|
440
|
+
labels.wrongAccount,
|
|
441
|
+
" ",
|
|
442
|
+
/* @__PURE__ */ jsx("strong", { children: labels.signOut })
|
|
443
|
+
]
|
|
444
|
+
})
|
|
445
|
+
}) : null]
|
|
446
|
+
})
|
|
447
|
+
}) : null, $[107] = currentUser, $[108] = labels.signOut, $[109] = labels.wrongAccount, $[110] = onSignOut, $[111] = providerTitle, $[112] = t16) : t16 = $[112];
|
|
448
|
+
let t17;
|
|
449
|
+
return $[113] !== T1 || $[114] !== t12 || $[115] !== t13 || $[116] !== t15 || $[117] !== t16 ? (t17 = /* @__PURE__ */ jsxs(T1, {
|
|
450
|
+
direction: t12,
|
|
451
|
+
height: t13,
|
|
452
|
+
children: [t15, t16]
|
|
453
|
+
}), $[113] = T1, $[114] = t12, $[115] = t13, $[116] = t15, $[117] = t16, $[118] = t17) : t17 = $[118], t17;
|
|
454
|
+
}
|
|
455
|
+
function getRequestUrl() {
|
|
456
|
+
if (typeof window > "u") return;
|
|
457
|
+
let url = new URL(window.location.href);
|
|
458
|
+
return url.hash = "", url.toString();
|
|
459
|
+
}
|
|
460
|
+
function getInitials(user) {
|
|
461
|
+
let source = user.name ?? user.email;
|
|
462
|
+
if (!source) return;
|
|
463
|
+
let initials = source.trim().split(/\s+/).slice(0, 2).map((part) => part[0]).join("");
|
|
464
|
+
return initials ? initials.toUpperCase() : void 0;
|
|
465
|
+
}
|
|
466
|
+
export { MAX_ACCESS_REQUEST_NOTE_LENGTH, RequestAccessForm, deriveAccessRequestState, getProviderTitle, listMyAccessRequests, submitAccessRequest };
|
|
467
|
+
|
|
468
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["SanityClient","AccessRequest","AccessResourceType","SubmitAccessRequestResult","MAX_ACCESS_REQUEST_NOTE_LENGTH","ACCESS_API_VERSION","SAML_ENFORCEMENT_REQUIRED","withAccessApiVersion","client","withConfig","apiVersion","listMyAccessRequests","Promise","requests","request","url","tag","ErrorResponseDetails","statusCode","message","code","redirectUrl","getErrorResponseDetails","err","response","body","details","undefined","mapSubmitError","type","includes","replace","error","submitAccessRequest","options","resourceType","resourceId","note","requestUrl","method","AccessRequest","AccessRequestState","REQUEST_LIFETIME_MS","deriveAccessRequestState","requests","resourceId","now","Date","length","isRecent","request","createdAt","getTime","forResource","filter","some","status","getProviderTitle","provider","startsWith","undefined","ReactNode","RequestAccessLabels","title","sentTitle","deniedTitle","errorTitle","describeNoAccess","context","email","promptProject","promptOrganization","notePlaceholder","noteAriaLabel","submit","sentDescription","pendingMessage","deniedMessage","message","overLimitMessage","expiredMessage","ssoEnforcedMessage","providerTitle","ssoSignInCta","submitFailedMessage","wrongAccount","signOut","defaultLabels","SanityClient","LaunchIcon","Avatar","Box","Button","Card","Flex","Spinner","Stack","Text","TextArea","ReactNode","SubmitEvent","Suspense","use","useId","useMemo","useState","useTransition","listMyAccessRequests","MAX_ACCESS_REQUEST_NOTE_LENGTH","submitAccessRequest","deriveAccessRequestState","defaultLabels","RequestAccessLabels","getProviderTitle","AccessRequest","AccessResourceType","AccessUser","SubmitAccessRequestResult","RequestAccessFormProps","client","resourceType","resourceId","currentUser","onSignOut","onRequestSubmitted","preview","labels","Partial","RequestAccessForm","props","$","_c","t0","catch","_temp","requestsPromise","t1","Symbol","for","t2","ViewState","view","expired","title","message","redirectUrl","deriveViewState","options","fetchedRequests","submitResult","type","errorTitle","deniedMessage","overLimitMessage","state","deniedTitle","RequestAccessFormContent","undefined","titleId","note","setNote","setSubmitResult","isSubmitting","startSubmit","T0","T1","handleSubmit","providerTitle","submitFailed","t10","t11","t12","t13","t3","t4","t5","t6","t7","t8","t9","email","provider","t14","t15","describeNoAccess","t16","description","t17","sentDescription","sentTitle","t18","pendingMessage","t19","t20","heading","t21","t22","event","preventDefault","result","trim","requestUrl","getRequestUrl","ssoEnforcedMessage","ssoSignInCta","expiredMessage","noteAriaLabel","notePlaceholder","promptOrganization","promptProject","submit","submitFailedMessage","event_0","currentTarget","value","length","signOut","wrongAccount","getInitials","profileImage","name","window","url","URL","location","href","hash","toString","user","source","parts","split","initials","slice","map","part","join","toUpperCase"],"sources":["../src/accessRequests.ts","../src/deriveAccessRequestState.ts","../src/providerTitle.ts","../src/labels.tsx","../src/RequestAccessForm.tsx"],"sourcesContent":["import {type SanityClient} from '@sanity/client'\n\nimport {type AccessRequest, type AccessResourceType, type SubmitAccessRequestResult} from './types'\n\n/**\n * The Access API only accepts notes up to this length.\n *\n * @public\n */\nexport const MAX_ACCESS_REQUEST_NOTE_LENGTH = 150\n\nconst ACCESS_API_VERSION = '2024-07-01'\n\n/**\n * Structured 403 code thrown by the Access API when the target organization\n * only admits members through its SSO login flow.\n */\nconst SAML_ENFORCEMENT_REQUIRED = 'saml_enforcement_required'\n\nfunction withAccessApiVersion(client: SanityClient): SanityClient {\n return client.withConfig({apiVersion: ACCESS_API_VERSION})\n}\n\n/**\n * Fetches the caller's own access requests across all resources\n * (`GET /access/requests/me`).\n *\n * @public\n */\nexport async function listMyAccessRequests(client: SanityClient): Promise<AccessRequest[]> {\n const requests = await withAccessApiVersion(client).request<AccessRequest[] | null>({\n url: '/access/requests/me',\n tag: 'access-ui.list-requests',\n })\n return requests ?? []\n}\n\ninterface ErrorResponseDetails {\n statusCode?: number\n message?: string\n code?: string\n redirectUrl?: string\n}\n\nfunction getErrorResponseDetails(err: unknown): ErrorResponseDetails {\n if (typeof err !== 'object' || err === null) return {}\n const response = (err as {response?: unknown}).response\n if (typeof response !== 'object' || response === null) return {}\n const {statusCode} = response as {statusCode?: unknown}\n const body = (response as {body?: unknown}).body\n const details: ErrorResponseDetails = {\n statusCode: typeof statusCode === 'number' ? statusCode : undefined,\n }\n if (typeof body === 'object' && body !== null) {\n const {message, code, redirectUrl} = body as {\n message?: unknown\n code?: unknown\n redirectUrl?: unknown\n }\n details.message = typeof message === 'string' ? message : undefined\n details.code = typeof code === 'string' ? code : undefined\n details.redirectUrl = typeof redirectUrl === 'string' ? redirectUrl : undefined\n }\n return details\n}\n\nfunction mapSubmitError(err: unknown): SubmitAccessRequestResult {\n const {statusCode, message, code, redirectUrl} = getErrorResponseDetails(err)\n\n if (statusCode === 403 && code === SAML_ENFORCEMENT_REQUIRED) {\n return {type: 'sso-enforced', redirectUrl, message}\n }\n if (statusCode === 429) {\n return {type: 'over-limit', message}\n }\n if (statusCode === 409) {\n if (message?.includes('email domain')) return {type: 'email-domain-blocked', message}\n if (message?.includes('disabled for organization')) return {type: 'requests-disabled', message}\n return {type: 'denied', message: message?.replace(/^Conflict -\\s*/, '')}\n }\n return {type: 'error', error: err}\n}\n\n/**\n * Submits an access request (`POST /access/{resourceType}/{resourceId}/requests`)\n * and maps the Access API's error contract to a {@link SubmitAccessRequestResult}.\n * Never throws for API rejections; unexpected failures come back as\n * `{type: 'error'}` so callers decide how to surface them.\n *\n * @public\n */\nexport async function submitAccessRequest(options: {\n client: SanityClient\n resourceType: AccessResourceType\n resourceId: string\n note?: string\n requestUrl?: string\n}): Promise<SubmitAccessRequestResult> {\n const {client, resourceType, resourceId, note, requestUrl} = options\n try {\n const request = await withAccessApiVersion(client).request<AccessRequest | null>({\n url: `/access/${resourceType}/${resourceId}/requests`,\n method: 'post',\n tag: 'access-ui.submit-request',\n body: {note, requestUrl, type: 'access'},\n })\n return {type: 'submitted', request}\n } catch (err) {\n return mapSubmitError(err)\n }\n}\n","import {type AccessRequest, type AccessRequestState} from './types'\n\n/**\n * Access requests are considered active for two weeks, matching the Access\n * API's request lifetime.\n */\nconst REQUEST_LIFETIME_MS = 14 * 24 * 60 * 60 * 1000\n\n/**\n * Derives where the caller stands on requesting access to a resource from\n * their existing access requests.\n *\n * A declined request blocks re-requesting for two weeks. A pending request\n * younger than two weeks is in review; older pending requests count as\n * expired, and the caller may request again.\n *\n * @public\n */\nexport function deriveAccessRequestState(\n requests: AccessRequest[] | null | undefined,\n resourceId: string,\n now: number = Date.now(),\n): AccessRequestState {\n if (!requests || requests.length === 0) return 'none'\n\n const isRecent = (request: AccessRequest) =>\n now - new Date(request.createdAt).getTime() < REQUEST_LIFETIME_MS\n\n const forResource = requests.filter((request) => request.resourceId === resourceId)\n\n if (forResource.some((request) => request.status === 'declined' && isRecent(request))) {\n return 'denied'\n }\n if (forResource.some((request) => request.status === 'pending' && isRecent(request))) {\n return 'pending'\n }\n if (forResource.some((request) => request.status === 'pending')) {\n return 'expired'\n }\n return 'none'\n}\n","/**\n * Human-readable title for a login provider id, e.g. `google` → `Google`,\n * `saml-xyz` → `SAML/SSO`.\n *\n * @public\n */\nexport function getProviderTitle(provider?: string): string | undefined {\n if (provider === 'google') return 'Google'\n if (provider === 'github') return 'GitHub'\n if (provider === 'sanity') return 'Sanity'\n if (provider === 'vercel') return 'Vercel'\n if (provider?.startsWith('saml-')) return 'SAML/SSO'\n return undefined\n}\n","import {type ReactNode} from 'react'\n\n/**\n * All user-facing strings in the request-access screen. Every label can be\n * overridden, so hosts with their own i18n stack (studio i18n, react-i18next)\n * inject translated copy while standalone hosts get the English defaults.\n *\n * @public\n */\nexport interface RequestAccessLabels {\n title: ReactNode\n sentTitle: ReactNode\n deniedTitle: ReactNode\n errorTitle: ReactNode\n describeNoAccess: (context: {email?: string}) => ReactNode\n promptProject: ReactNode\n promptOrganization: ReactNode\n notePlaceholder: string\n noteAriaLabel: string\n submit: ReactNode\n sentDescription: ReactNode\n pendingMessage: ReactNode\n deniedMessage: (context: {message?: string}) => ReactNode\n overLimitMessage: (context: {message?: string}) => ReactNode\n expiredMessage: ReactNode\n ssoEnforcedMessage: (context: {providerTitle?: string}) => ReactNode\n ssoSignInCta: ReactNode\n submitFailedMessage: ReactNode\n wrongAccount: ReactNode\n signOut: ReactNode\n}\n\n/** @internal */\nexport const defaultLabels: RequestAccessLabels = {\n title: 'Request access',\n sentTitle: 'Access request sent',\n deniedTitle: 'Access request declined',\n errorTitle: 'Access request couldn’t be sent',\n describeNoAccess: ({email}) =>\n email ? (\n <>\n Your account <strong>({email})</strong> doesn’t have access to this content.\n </>\n ) : (\n <>Your account doesn’t have access to this content.</>\n ),\n promptProject: 'Send a request to the project admin(s).',\n promptOrganization: 'Send a request to the organization admin(s).',\n notePlaceholder: 'Message (optional)',\n noteAriaLabel: 'Message',\n submit: 'Request access',\n sentDescription:\n 'Your request has been sent. You will receive a notification if access is approved.',\n pendingMessage: 'Your request to access this content is pending approval.',\n deniedMessage: ({message}) => message ?? 'Your request to access this content has been declined.',\n overLimitMessage: ({message}) =>\n message ??\n 'You’ve reached the limit for access requests across all projects. Please wait before submitting more requests, or contact an admin.',\n expiredMessage: 'Your previous request has expired. You may request access again below.',\n ssoEnforcedMessage: ({providerTitle}) =>\n providerTitle ? (\n <>\n You’re signed in with <strong>{providerTitle}</strong>, but this organization requires\n signing in with SSO. Access can’t be requested with this account.\n </>\n ) : (\n <>\n This organization requires signing in with SSO. Access can’t be requested with this account.\n </>\n ),\n ssoSignInCta: 'Sign in with SSO',\n submitFailedMessage: 'There was a problem submitting your request. Please try again.',\n wrongAccount: 'Wrong account?',\n signOut: 'Sign out',\n}\n","import {type SanityClient} from '@sanity/client'\nimport {LaunchIcon} from '@sanity/icons/Launch'\nimport {Avatar, Box, Button, Card, Flex, Spinner, Stack, Text, TextArea} from '@sanity/ui'\nimport {\n type ReactNode,\n type SubmitEvent,\n Suspense,\n use,\n useId,\n useMemo,\n useState,\n useTransition,\n} from 'react'\n\nimport {\n listMyAccessRequests,\n MAX_ACCESS_REQUEST_NOTE_LENGTH,\n submitAccessRequest,\n} from './accessRequests'\nimport {deriveAccessRequestState} from './deriveAccessRequestState'\nimport {defaultLabels, type RequestAccessLabels} from './labels'\nimport {getProviderTitle} from './providerTitle'\nimport {\n type AccessRequest,\n type AccessResourceType,\n type AccessUser,\n type SubmitAccessRequestResult,\n} from './types'\n\n/** @public */\nexport interface RequestAccessFormProps {\n /** Client authenticated as the requesting user. The Access API version is applied internally. */\n client: SanityClient\n resourceType?: AccessResourceType\n /** Project or organization id to request access to. */\n resourceId: string\n /** The signed-in user, rendered in the description and account footer. */\n currentUser?: AccessUser | null\n /**\n * Called when the user chooses \"Sign out\". The account footer's sign-out\n * action is only rendered when provided; hosts own the actual sign-out\n * mechanism (studio: `auth.logout()`, dashboard: logout route navigation).\n */\n onSignOut?: () => void\n /** Called after a request is successfully submitted, e.g. for analytics. */\n onRequestSubmitted?: () => void\n /** Optional slot rendered above the title, e.g. a resource preview. */\n preview?: ReactNode\n /** Label overrides for hosts with their own i18n stack. */\n labels?: Partial<RequestAccessLabels>\n}\n\n/**\n * The shared request-access screen: explains that the signed-in account lacks\n * access, lets the user request it with an optional note, and reflects the\n * request lifecycle (pending, denied, expired, over-limit, SSO-enforced).\n *\n * Fetches the caller's existing requests on mount and suspends while loading;\n * an internal `Suspense` boundary renders a spinner, so hosts can mount it\n * directly. Remount with a `key` when `client` or `resourceId` change.\n *\n * @public\n */\nexport function RequestAccessForm(props: RequestAccessFormProps) {\n const {client} = props\n\n // Created once (lazy init): recreating the promise per render would refetch\n // and re-suspend forever. Callers remount with `key` to reset.\n const [requestsPromise] = useState(() =>\n listMyAccessRequests(client).catch((): AccessRequest[] | null => null),\n )\n\n return (\n <Card border height=\"fill\" overflow=\"hidden\" radius={3} tone=\"default\">\n <Suspense\n fallback={\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={5}>\n <Spinner muted />\n </Flex>\n }\n >\n <RequestAccessFormContent {...props} requestsPromise={requestsPromise} />\n </Suspense>\n </Card>\n )\n}\n\ntype ViewState =\n | {view: 'form'; expired: boolean}\n | {view: 'sent'}\n | {view: 'pending'}\n | {view: 'blocked'; title: ReactNode; message: ReactNode}\n | {view: 'sso-enforced'; redirectUrl?: string}\n\nfunction deriveViewState(options: {\n fetchedRequests: AccessRequest[] | null\n resourceId: string\n submitResult: SubmitAccessRequestResult | null\n labels: RequestAccessLabels\n}): ViewState {\n const {fetchedRequests, resourceId, submitResult, labels} = options\n\n if (submitResult) {\n switch (submitResult.type) {\n case 'submitted':\n return {view: 'sent'}\n case 'sso-enforced':\n return {view: 'sso-enforced', redirectUrl: submitResult.redirectUrl}\n case 'denied':\n return {\n view: 'blocked',\n title: labels.errorTitle,\n message: labels.deniedMessage({message: submitResult.message}),\n }\n case 'over-limit':\n return {\n view: 'blocked',\n title: labels.errorTitle,\n message: labels.overLimitMessage({message: submitResult.message}),\n }\n case 'email-domain-blocked':\n case 'requests-disabled':\n return {view: 'blocked', title: labels.errorTitle, message: submitResult.message}\n case 'error':\n // Fall through to the fetched state; the form stays up with an inline error.\n break\n default:\n }\n }\n\n const state = deriveAccessRequestState(fetchedRequests, resourceId)\n if (state === 'pending') return {view: 'pending'}\n // Derived from prefetch: the user hasn't submitted anything this session,\n // so the title must describe the prior decline, not a failed send.\n if (state === 'denied') {\n return {view: 'blocked', title: labels.deniedTitle, message: labels.deniedMessage({})}\n }\n return {view: 'form', expired: state === 'expired'}\n}\n\nfunction RequestAccessFormContent(\n props: RequestAccessFormProps & {\n requestsPromise: Promise<AccessRequest[] | null>\n },\n) {\n const {\n client,\n resourceType = 'project',\n resourceId,\n currentUser,\n onSignOut,\n onRequestSubmitted,\n preview,\n requestsPromise,\n } = props\n\n const labels = useMemo(() => ({...defaultLabels, ...props.labels}), [props.labels])\n const fetchedRequests = use(requestsPromise)\n const titleId = useId()\n\n const [note, setNote] = useState('')\n const [submitResult, setSubmitResult] = useState<SubmitAccessRequestResult | null>(null)\n const [isSubmitting, startSubmit] = useTransition()\n\n const state = deriveViewState({\n fetchedRequests,\n resourceId,\n submitResult,\n labels,\n })\n const providerTitle = getProviderTitle(currentUser?.provider)\n const submitFailed = submitResult?.type === 'error'\n\n const heading: Record<\n Exclude<ViewState['view'], 'blocked'>,\n {title: ReactNode; description: ReactNode | null}\n > = {\n 'form': {\n title: labels.title,\n description: labels.describeNoAccess({email: currentUser?.email}),\n },\n 'sent': {title: labels.sentTitle, description: labels.sentDescription},\n 'pending': {title: labels.sentTitle, description: labels.pendingMessage},\n 'sso-enforced': {title: labels.errorTitle, description: null},\n }\n const {title, description} =\n state.view === 'blocked' ? {title: state.title, description: null} : heading[state.view]\n\n const handleSubmit = (event: SubmitEvent<HTMLFormElement>) => {\n event.preventDefault()\n if (isSubmitting) return\n startSubmit(async () => {\n const result = await submitAccessRequest({\n client,\n resourceType,\n resourceId,\n note: note.trim() || undefined,\n requestUrl: getRequestUrl(),\n })\n setSubmitResult(result)\n if (result.type === 'submitted') onRequestSubmitted?.()\n })\n }\n\n return (\n <Flex direction=\"column\" height=\"fill\">\n <Flex direction=\"column\" flex={1} gap={4} padding={4}>\n {preview ? (\n <Flex justify=\"center\" padding={2}>\n {preview}\n </Flex>\n ) : null}\n\n <Text as=\"h1\" id={titleId} size={2} weight=\"semibold\">\n {title}\n </Text>\n\n {description !== null ? (\n <Text as=\"p\" muted size={1}>\n {description}\n </Text>\n ) : null}\n\n {state.view === 'blocked' ? (\n <Card border padding={3} radius={2} role=\"alert\" tone=\"caution\">\n <Text as=\"p\" muted size={1}>\n {state.message}\n </Text>\n </Card>\n ) : null}\n\n {state.view === 'sso-enforced' ? (\n <Stack gap={4}>\n <Card border padding={3} radius={2} role=\"alert\" tone=\"caution\">\n <Text as=\"p\" muted size={1}>\n {labels.ssoEnforcedMessage({providerTitle})}\n </Text>\n </Card>\n {state.redirectUrl ? (\n <Button\n as=\"a\"\n href={state.redirectUrl}\n iconRight={LaunchIcon}\n mode=\"ghost\"\n text={labels.ssoSignInCta}\n width=\"fill\"\n />\n ) : null}\n </Stack>\n ) : null}\n\n {state.view === 'form' ? (\n <Stack as=\"form\" aria-labelledby={titleId} onSubmit={handleSubmit} gap={4}>\n <Text as=\"p\" size={1}>\n {state.expired\n ? labels.expiredMessage\n : resourceType === 'organization'\n ? labels.promptOrganization\n : labels.promptProject}\n </Text>\n <Stack gap={2}>\n <TextArea\n aria-label={labels.noteAriaLabel}\n disabled={isSubmitting}\n fontSize={1}\n maxLength={MAX_ACCESS_REQUEST_NOTE_LENGTH}\n onChange={(event) => setNote(event.currentTarget.value)}\n placeholder={labels.notePlaceholder}\n rows={3}\n value={note}\n />\n <Text align=\"right\" muted size={0}>\n {`${note.length}/${MAX_ACCESS_REQUEST_NOTE_LENGTH}`}\n </Text>\n </Stack>\n {submitFailed ? (\n <Card border padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text as=\"p\" muted size={1}>\n {labels.submitFailedMessage}\n </Text>\n </Card>\n ) : null}\n <Button\n disabled={isSubmitting}\n loading={isSubmitting}\n text={labels.submit}\n type=\"submit\"\n width=\"fill\"\n />\n </Stack>\n ) : null}\n </Flex>\n\n {currentUser ? (\n <Card borderTop padding={3}>\n <Flex align=\"center\" direction=\"column\" gap={3}>\n <Flex align=\"center\" gap={2} justify=\"center\">\n <Avatar initials={getInitials(currentUser)} size={0} src={currentUser.profileImage} />\n <Box>\n <Text muted size={1} textOverflow=\"ellipsis\">\n {currentUser.email ?? currentUser.name}\n {providerTitle ? ` · ${providerTitle}` : ''}\n </Text>\n </Box>\n </Flex>\n {onSignOut ? (\n <Button\n fontSize={0}\n mode=\"bleed\"\n onClick={onSignOut}\n padding={2}\n textWeight=\"regular\"\n >\n <Text muted size={1}>\n {labels.wrongAccount} <strong>{labels.signOut}</strong>\n </Text>\n </Button>\n ) : null}\n </Flex>\n </Card>\n ) : null}\n </Flex>\n )\n}\n\n// The URL fragment can carry auth tokens (e.g. the #token= login handoff),\n// so it must never reach the Access API's logs.\nfunction getRequestUrl(): string | undefined {\n if (typeof window === 'undefined') return undefined\n const url = new URL(window.location.href)\n url.hash = ''\n return url.toString()\n}\n\nfunction getInitials(user: AccessUser): string | undefined {\n const source = user.name ?? user.email\n if (!source) return undefined\n const parts = source.trim().split(/\\s+/)\n const initials = parts\n .slice(0, 2)\n .map((part) => part[0])\n .join('')\n return initials ? initials.toUpperCase() : undefined\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sanity/access-ui",
|
|
3
|
+
"version": "6.9.1",
|
|
4
|
+
"description": "Shared request-access screen and access-request logic for Sanity applications",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"access",
|
|
7
|
+
"request-access",
|
|
8
|
+
"sanity",
|
|
9
|
+
"ui"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://www.sanity.io/",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/sanity-io/sanity/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Sanity.io <hello@sanity.io>",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/sanity-io/sanity.git",
|
|
20
|
+
"directory": "packages/@sanity/access-ui"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"lib"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"types": "./lib/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./lib/index.js",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@sanity/client": "^7.26.2",
|
|
37
|
+
"@sanity/icons": "^5.2.1",
|
|
38
|
+
"@sanity/ui": "^4.0.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@rolldown/plugin-babel": "^0.2.3",
|
|
42
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
43
|
+
"@testing-library/react": "^16.3.2",
|
|
44
|
+
"@testing-library/user-event": "^14.6.3",
|
|
45
|
+
"@types/react": "^19.2.18",
|
|
46
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
47
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
48
|
+
"jsdom": "^29.1.1",
|
|
49
|
+
"react": "^19.2.8",
|
|
50
|
+
"react-dom": "^19.2.8",
|
|
51
|
+
"styled-components": "^6.5.1",
|
|
52
|
+
"tsdown": "^0.22.14",
|
|
53
|
+
"typescript": "^7.0.2",
|
|
54
|
+
"vite": "^8.2.1",
|
|
55
|
+
"vitest": "^4.1.10",
|
|
56
|
+
"@repo/tsdown.config": "6.10.0-next.6+de9c7a4bfd",
|
|
57
|
+
"@repo/tsconfig": "6.10.0-next.6+de9c7a4bfd",
|
|
58
|
+
"@repo/test-config": "6.10.0-next.6+de9c7a4bfd"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^19.2.2"
|
|
62
|
+
},
|
|
63
|
+
"browserslist": [
|
|
64
|
+
"node >=22.12",
|
|
65
|
+
"baseline 2024"
|
|
66
|
+
],
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=22.12"
|
|
69
|
+
},
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsdown",
|
|
72
|
+
"test": "vitest",
|
|
73
|
+
"watch": "tsdown --watch"
|
|
74
|
+
}
|
|
75
|
+
}
|