@sanity/sdk 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_exports/_internal.d.ts +52 -21
- package/dist/_exports/_internal.d.ts.map +1 -1
- package/dist/_exports/_internal.js +10 -9
- package/dist/_exports/_internal.js.map +1 -1
- package/dist/_exports/agent.d.ts +7 -7
- package/dist/_exports/agent.d.ts.map +1 -1
- package/dist/_exports/agent.js +1 -1
- package/dist/_exports/comlink.d.ts +9 -9
- package/dist/_exports/comlink.d.ts.map +1 -1
- package/dist/_exports/comlink.js +3 -2
- package/dist/_exports/comlink.js.map +1 -1
- package/dist/_exports/dashboard.d.ts +2 -0
- package/dist/_exports/dashboard.js +2 -0
- package/dist/{authStore-C-OEkGaM.d.ts → authStore-BO2vch3I.d.ts} +516 -63
- package/dist/authStore-BO2vch3I.d.ts.map +1 -0
- package/dist/{clientStore-gUALQ0qW.js → clientStore-BI4D8HhJ.js} +124 -7
- package/dist/clientStore-BI4D8HhJ.js.map +1 -0
- package/dist/{createSanityInstance-DCePpBYW.d.ts → createSanityInstance-BQIqyGLX.d.ts} +16 -1
- package/dist/createSanityInstance-BQIqyGLX.d.ts.map +1 -0
- package/dist/{object-BwynGPRZ.js → createStateSourceAction-DdAhEfnZ.js} +2 -82
- package/dist/createStateSourceAction-DdAhEfnZ.js.map +1 -0
- package/dist/defineProperty-Bho9Ngsi.js +31 -0
- package/dist/{getNodeState-E0hjqFOo.js → getNodeState-B4nG0sjm.js} +3 -2
- package/dist/{getNodeState-E0hjqFOo.js.map → getNodeState-B4nG0sjm.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +335 -51
- package/dist/index.js.map +1 -1
- package/dist/object-CxXlSVg7.js +83 -0
- package/dist/object-CxXlSVg7.js.map +1 -0
- package/dist/topicStore-Ct7IFNtY.js +565 -0
- package/dist/topicStore-Ct7IFNtY.js.map +1 -0
- package/dist/topicStore-D0WqhQGF.d.ts +435 -0
- package/dist/topicStore-D0WqhQGF.d.ts.map +1 -0
- package/dist/{version-C90rNWaX.js → version-BcRmCiYi.js} +6 -6
- package/dist/{version-C90rNWaX.js.map → version-BcRmCiYi.js.map} +1 -1
- package/package.json +19 -18
- package/src/_exports/_internal.ts +12 -0
- package/src/_exports/dashboard.ts +36 -0
- package/src/_exports/index.ts +17 -1
- package/src/applications/applications.test-d.ts +28 -4
- package/src/applications/applications.ts +39 -14
- package/src/auth/authMode.test.ts +24 -0
- package/src/auth/authMode.ts +8 -3
- package/src/auth/authStore.ts +12 -0
- package/src/auth/authStrategy.ts +2 -0
- package/src/auth/logout.test.ts +45 -0
- package/src/auth/logout.ts +1 -0
- package/src/auth/oauth/oauthActions.test.ts +457 -0
- package/src/auth/oauth/oauthActions.ts +389 -0
- package/src/auth/oauth/oauthAuth.test.ts +206 -0
- package/src/auth/oauth/oauthAuth.ts +168 -0
- package/src/auth/oauth/pkce.test.ts +44 -0
- package/src/auth/oauth/pkce.ts +60 -0
- package/src/auth/oauth/types.ts +12 -0
- package/src/config/authConfig.ts +18 -0
- package/src/dashboard/messageBus/__fixtures__/test-topics.ts +18 -0
- package/src/dashboard/messageBus/bus.test.ts +1033 -0
- package/src/dashboard/messageBus/bus.ts +1246 -0
- package/src/dashboard/messageBus/store.test.ts +142 -0
- package/src/dashboard/messageBus/store.ts +74 -0
- package/src/dashboard/messageBus/topicStore.test.ts +172 -0
- package/src/dashboard/messageBus/topicStore.ts +184 -0
- package/src/dashboard/messageBus/topics.test.ts +71 -0
- package/src/dashboard/messageBus/topics.ts +260 -0
- package/src/document/actions.ts +3 -3
- package/src/document/applyDocumentActions.ts +3 -3
- package/src/document/documentStore.ts +12 -12
- package/src/document/processMutations.ts +58 -22
- package/src/installations/installations.test-d.ts +3 -3
- package/src/installations/installations.ts +2 -19
- package/src/projection/getProjectionState.ts +2 -2
- package/src/projection/resolveProjection.ts +2 -2
- package/src/query/queryStore.ts +3 -3
- package/src/typegen/defineProjection.test.ts +17 -0
- package/src/typegen/defineProjection.ts +19 -0
- package/src/typegen/groqCompat.ts +122 -0
- package/src/typegen/resolve.ts +37 -0
- package/src/utils/createGroqSearchFilter.test.ts +8 -0
- package/src/utils/createGroqSearchFilter.ts +6 -3
- package/dist/authStore-C-OEkGaM.d.ts.map +0 -1
- package/dist/clientStore-gUALQ0qW.js.map +0 -1
- package/dist/createSanityInstance-DCePpBYW.d.ts.map +0 -1
- package/dist/object-BwynGPRZ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import {
|
|
3
|
-
import { A as clearPendingTransaction, B as assertDatasetResource, C as getCommentsState, D as toCommentsKeyParts, E as resolveComments, F as rollbackCommentUpdate, G as defineMutation, H as provisionAddonDataset, I as setCommentCreateError, K as randomId, L as setPendingTransaction, M as receiveComment, N as removeCommentById, O as addComment, P as restoreComments, R as normalizeComment, T as resolveCommentThreads, U as COMMENTS_API_VERSION, V as getAddonDatasetState, W as defineFetcher, _ as updateLastLoadMoreRequest, a as resolveQuery, b as commentsStore, c as getAllReleasesState, d as getUsersKey, f as initializeRequest, g as setUsersError, h as setUsersData, j as getCommentsKey, k as applyCommentUpdate, l as addSubscription, m as removeSubscription, o as getPerspectiveState, p as parseUsersKey, q as randomUuid, r as getQueryState, s as getActiveReleasesState, t as CORE_SDK_VERSION, u as cancelRequest, v as PROJECT_API_VERSION, x as getCommentThreadsState, y as USERS_STATE_CLEAR_DELAY, z as toCommentFieldPath } from "./version-
|
|
1
|
+
import { D as getAuthLogger, E as REQUEST_TAG_PREFIX, O as configureLogging$1, S as AuthStateType, T as DEFAULT_BASE, b as getTokenFromLocation, c as getDashboardOrganizationId, d as getTokenState, f as setAuthToken, h as getCleanedUrl, i as authStore, k as createLogger, l as getIsInDashboardState, m as getAuthCode, n as getClient, o as getAuthState, p as createLoggedInAuthState, r as getClientState, s as getCurrentUserState, u as getLoginUrlState, w as DEFAULT_API_VERSION, y as getDefaultLocation } from "./clientStore-BI4D8HhJ.js";
|
|
2
|
+
import { c as isReleasePerspective, d as isMediaLibraryResource, i as bindActionGlobally, l as isCanvasResource, n as bindActionByResource, o as defineStore, r as bindActionByResourceAndPerspective, t as createStateSourceAction, u as isDatasetResource } from "./createStateSourceAction-DdAhEfnZ.js";
|
|
3
|
+
import { A as clearPendingTransaction, B as assertDatasetResource, C as getCommentsState, D as toCommentsKeyParts, E as resolveComments, F as rollbackCommentUpdate, G as defineMutation, H as provisionAddonDataset, I as setCommentCreateError, K as randomId, L as setPendingTransaction, M as receiveComment, N as removeCommentById, O as addComment, P as restoreComments, R as normalizeComment, T as resolveCommentThreads, U as COMMENTS_API_VERSION, V as getAddonDatasetState, W as defineFetcher, _ as updateLastLoadMoreRequest, a as resolveQuery, b as commentsStore, c as getAllReleasesState, d as getUsersKey, f as initializeRequest, g as setUsersError, h as setUsersData, j as getCommentsKey, k as applyCommentUpdate, l as addSubscription, m as removeSubscription, o as getPerspectiveState, p as parseUsersKey, q as randomUuid, r as getQueryState, s as getActiveReleasesState, t as CORE_SDK_VERSION, u as cancelRequest, v as PROJECT_API_VERSION, x as getCommentThreadsState, y as USERS_STATE_CLEAR_DELAY, z as toCommentFieldPath } from "./version-BcRmCiYi.js";
|
|
4
|
+
import { r as omitProperty, t as isDeepEqual } from "./object-CxXlSVg7.js";
|
|
4
5
|
import { n as setCleanupTimeout } from "./setCleanupTimeout-BiM6q1KF.js";
|
|
5
|
-
import { t as
|
|
6
|
+
import { t as _defineProperty } from "./defineProperty-Bho9Ngsi.js";
|
|
7
|
+
import { t as getNodeState } from "./getNodeState-B4nG0sjm.js";
|
|
6
8
|
import { ClientError, CorsOriginError } from "@sanity/client";
|
|
7
9
|
import { EMPTY, NEVER, Observable, Subject, Subscription, auditTime, catchError, combineLatest, concat, concatMap, debounceTime, defer, distinctUntilChanged, filter, first, firstValueFrom, from, fromEvent, groupBy, map, merge, mergeMap, of, pairwise, partition, race, retry, share, shareReplay, skip, startWith, switchMap, take, takeUntil, tap, throttle, throwError, timer, withLatestFrom } from "rxjs";
|
|
8
10
|
import { isKeySegment, isKeyedObject } from "@sanity/types";
|
|
@@ -10,7 +12,6 @@ import { DocumentId, getDraftId, getPublishedId, getVersionId, isDraftId, isPubl
|
|
|
10
12
|
import { getIndexForKey, getIndexForKey as getIndexForKey$1, getPathDepth, joinPaths, jsonMatch, jsonMatch as jsonMatch$1, slicePath, slicePath as slicePath$1, stringifyPath, stringifyPath as stringifyPath$1 } from "@sanity/json-match";
|
|
11
13
|
import { SanityEncoder } from "@sanity/mutate";
|
|
12
14
|
import { createDocumentLoaderFromClient } from "@sanity/mutate/_unstable_store";
|
|
13
|
-
import "groq";
|
|
14
15
|
import { evaluateSync, parse } from "groq-js";
|
|
15
16
|
import { catchError as catchError$1, distinctUntilChanged as distinctUntilChanged$1, map as map$1, mergeMap as mergeMap$1, retry as retry$1, scan, share as share$1, switchMap as switchMap$1 } from "rxjs/operators";
|
|
16
17
|
import { applyPatches, parsePatch } from "@sanity/diff-match-patch";
|
|
@@ -387,12 +388,273 @@ const handleAuthCallback = bindActionGlobally(authStore, async ({ state, instanc
|
|
|
387
388
|
} catch (error) {
|
|
388
389
|
throw logger.error("Logout request failed", { error }), error;
|
|
389
390
|
} finally {
|
|
390
|
-
logger.info("User logged out, clearing stored tokens"), state.set("logoutSuccess", {
|
|
391
|
+
logger.info("User logged out, clearing stored tokens"), state.set("logoutSuccess", {
|
|
392
|
+
authState: {
|
|
393
|
+
type: "logged-out",
|
|
394
|
+
isDestroyingSession: !1
|
|
395
|
+
},
|
|
396
|
+
oauthTokens: void 0
|
|
397
|
+
}), storageArea?.removeItem(storageKey), storageArea?.removeItem(`${storageKey}_last_refresh`);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
/**
|
|
401
|
+
* Encodes a byte array as a base64url string (RFC 4648 §5) with no padding,
|
|
402
|
+
* as required for PKCE `code_verifier`/`code_challenge` values.
|
|
403
|
+
*
|
|
404
|
+
* @internal
|
|
405
|
+
*/
|
|
406
|
+
function base64UrlEncode(bytes) {
|
|
407
|
+
let binary = "";
|
|
408
|
+
for (let byte of bytes) binary += String.fromCharCode(byte);
|
|
409
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
410
|
+
}
|
|
411
|
+
function randomString() {
|
|
412
|
+
let bytes = /* @__PURE__ */ new Uint8Array(32);
|
|
413
|
+
return crypto.getRandomValues(bytes), base64UrlEncode(bytes);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Generates a PKCE `code_verifier`
|
|
417
|
+
*
|
|
418
|
+
* @internal
|
|
419
|
+
*/
|
|
420
|
+
function generateCodeVerifier() {
|
|
421
|
+
return randomString();
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Generates the `state` parameter used to defend against CSRF on the OAuth
|
|
425
|
+
* callback.
|
|
426
|
+
*
|
|
427
|
+
* @internal
|
|
428
|
+
*/
|
|
429
|
+
function generateState() {
|
|
430
|
+
return randomString();
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Derives the PKCE `code_challenge` from a `code_verifier` using
|
|
434
|
+
* `base64url(sha256(verifier))` (the `S256` method).
|
|
435
|
+
*
|
|
436
|
+
* @internal
|
|
437
|
+
*/
|
|
438
|
+
async function generateCodeChallenge(codeVerifier) {
|
|
439
|
+
let data = new TextEncoder().encode(codeVerifier), digest = await crypto.subtle.digest("SHA-256", data);
|
|
440
|
+
return base64UrlEncode(new Uint8Array(digest));
|
|
441
|
+
}
|
|
442
|
+
/** sessionStorage key for the PKCE `code_verifier`. */
|
|
443
|
+
const OAUTH_VERIFIER_KEY = "__sanity_oauth_verifier", OAUTH_STATE_KEY = "__sanity_oauth_state";
|
|
444
|
+
/** Builds the RFC 8707 resource indicator for an organisation. */
|
|
445
|
+
function getResourceIndicator(organizationId) {
|
|
446
|
+
return `urn:io.sanity:organization:${organizationId}`;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Serialises tokens for storage, converting `expiresAt` to an ISO string.
|
|
450
|
+
*
|
|
451
|
+
* @internal
|
|
452
|
+
*/
|
|
453
|
+
function serializeTokens(tokens) {
|
|
454
|
+
return JSON.stringify({
|
|
455
|
+
accessToken: tokens.accessToken,
|
|
456
|
+
tokenType: tokens.tokenType,
|
|
457
|
+
expiresIn: tokens.expiresIn,
|
|
458
|
+
expiresAt: tokens.expiresAt.toISOString(),
|
|
459
|
+
...tokens.refreshToken !== void 0 && { refreshToken: tokens.refreshToken }
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Reads the store options, throwing when the instance was not configured for
|
|
464
|
+
* OAuth.
|
|
465
|
+
*/
|
|
466
|
+
function getOAuthOptions(state) {
|
|
467
|
+
let { options } = state;
|
|
468
|
+
if (!options.oauth) throw Error("OAuth is not configured on this instance (missing `auth.oauth`).");
|
|
469
|
+
return options;
|
|
470
|
+
}
|
|
471
|
+
/** Creates a client for the (unauthenticated) public OAuth token/revoke calls. */
|
|
472
|
+
function createOAuthClient(options) {
|
|
473
|
+
return options.clientFactory({
|
|
474
|
+
apiVersion: "v1",
|
|
475
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
476
|
+
useProjectHostname: !1,
|
|
477
|
+
useCdn: !1,
|
|
478
|
+
...options.apiHost && { apiHost: options.apiHost }
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
/** Converts a token endpoint response to the {@link OAuthTokens} shape. */
|
|
482
|
+
function toOAuthTokens(response) {
|
|
483
|
+
return {
|
|
484
|
+
accessToken: response.access_token,
|
|
485
|
+
tokenType: "bearer",
|
|
486
|
+
expiresIn: response.expires_in,
|
|
487
|
+
expiresAt: new Date(Date.now() + response.expires_in * 1e3),
|
|
488
|
+
...response.refresh_token !== void 0 && { refreshToken: response.refresh_token }
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Starts the OAuth authorization-code + PKCE flow: generates a `code_verifier`,
|
|
493
|
+
* `code_challenge` and `state`, persists the verifier and state to
|
|
494
|
+
* `sessionStorage`, then navigates the browser to the authorize endpoint.
|
|
495
|
+
*
|
|
496
|
+
* @public
|
|
497
|
+
*/
|
|
498
|
+
const startOAuthAuthorization = bindActionGlobally(authStore, async ({ state, instance }) => {
|
|
499
|
+
let logger = getAuthLogger(instance), options = getOAuthOptions(state.get()), codeVerifier = generateCodeVerifier(), oauthState = generateState(), codeChallenge = await generateCodeChallenge(codeVerifier), session = typeof sessionStorage < "u" ? sessionStorage : void 0;
|
|
500
|
+
session?.setItem(OAUTH_VERIFIER_KEY, codeVerifier), session?.setItem(OAUTH_STATE_KEY, oauthState);
|
|
501
|
+
let authorizeUrl = new URL("/v1/auth/oauth/authorize", options.apiHost ?? "https://api.sanity.io");
|
|
502
|
+
authorizeUrl.searchParams.set("response_type", "code"), authorizeUrl.searchParams.set("client_id", options.oauth.clientId), authorizeUrl.searchParams.set("redirect_uri", options.oauth.redirectUri), authorizeUrl.searchParams.set("state", oauthState), authorizeUrl.searchParams.set("code_challenge", codeChallenge), authorizeUrl.searchParams.set("code_challenge_method", "S256"), authorizeUrl.searchParams.append("resource", getResourceIndicator(options.oauth.organizationId)), logger.info("Starting OAuth authorization"), typeof window < "u" && typeof window.location?.assign == "function" && window.location.assign(authorizeUrl.toString());
|
|
503
|
+
}), handleOAuthCallback = bindActionGlobally(authStore, async ({ state, instance }, locationHref = getDefaultLocation()) => {
|
|
504
|
+
let logger = getAuthLogger(instance), options = getOAuthOptions(state.get()), { authState } = state.get();
|
|
505
|
+
if (authState.type === "logging-in" && authState.isExchangingToken) return logger.debug("Skipping OAuth callback - token exchange already in progress"), !1;
|
|
506
|
+
let callbackUrl = new URL(locationHref, DEFAULT_BASE), code = callbackUrl.searchParams.get("code"), returnedState = callbackUrl.searchParams.get("state"), error = callbackUrl.searchParams.get("error"), errorDescription = callbackUrl.searchParams.get("error_description"), session = typeof sessionStorage < "u" ? sessionStorage : void 0, cleanedUrlObj = new URL(locationHref, DEFAULT_BASE);
|
|
507
|
+
for (let param of [
|
|
508
|
+
"code",
|
|
509
|
+
"state",
|
|
510
|
+
"error",
|
|
511
|
+
"error_description"
|
|
512
|
+
]) cleanedUrlObj.searchParams.delete(param);
|
|
513
|
+
let cleanedUrl = cleanedUrlObj.toString();
|
|
514
|
+
if (error) return logger.warn("OAuth callback returned an error", {
|
|
515
|
+
error,
|
|
516
|
+
errorDescription
|
|
517
|
+
}), clearOAuthArtifacts(session), state.set("oauthCallbackError", { authState: {
|
|
518
|
+
type: "error",
|
|
519
|
+
error: Error(errorDescription ? `${error}: ${errorDescription}` : error)
|
|
520
|
+
} }), cleanedUrl;
|
|
521
|
+
if (!code) return logger.debug("No OAuth code found in callback URL"), !1;
|
|
522
|
+
let storedState = session?.getItem("__sanity_oauth_state") ?? null;
|
|
523
|
+
if (!returnedState || !storedState || returnedState !== storedState) return logger.error("OAuth state mismatch — rejecting callback"), clearOAuthArtifacts(session), state.set("oauthStateMismatch", { authState: {
|
|
524
|
+
type: "error",
|
|
525
|
+
error: /* @__PURE__ */ Error("OAuth state mismatch")
|
|
526
|
+
} }), cleanedUrl;
|
|
527
|
+
let codeVerifier = session?.getItem("__sanity_oauth_verifier") ?? null;
|
|
528
|
+
if (!codeVerifier) return logger.error("OAuth code verifier missing — cannot exchange code"), clearOAuthArtifacts(session), state.set("oauthVerifierMissing", { authState: {
|
|
529
|
+
type: "error",
|
|
530
|
+
error: /* @__PURE__ */ Error("OAuth code verifier missing")
|
|
531
|
+
} }), cleanedUrl;
|
|
532
|
+
logger.info("Exchanging OAuth code for tokens"), state.set("oauthExchange", { authState: {
|
|
533
|
+
type: "logging-in",
|
|
534
|
+
isExchangingToken: !0
|
|
535
|
+
} });
|
|
536
|
+
try {
|
|
537
|
+
let client = createOAuthClient(options), params = new URLSearchParams({
|
|
538
|
+
grant_type: "authorization_code",
|
|
539
|
+
code,
|
|
540
|
+
code_verifier: codeVerifier,
|
|
541
|
+
redirect_uri: options.oauth.redirectUri,
|
|
542
|
+
client_id: options.oauth.clientId,
|
|
543
|
+
resource: getResourceIndicator(options.oauth.organizationId)
|
|
544
|
+
}), tokens = toOAuthTokens(await client.request({
|
|
545
|
+
method: "POST",
|
|
546
|
+
url: "/auth/oauth/token",
|
|
547
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
548
|
+
body: params.toString(),
|
|
549
|
+
tag: "oauth.token"
|
|
550
|
+
}));
|
|
551
|
+
return options.storageArea?.setItem(options.storageKey, serializeTokens(tokens)), clearOAuthArtifacts(session), logger.info("OAuth tokens obtained, user logged in"), state.set("oauthLoggedIn", {
|
|
552
|
+
authState: createLoggedInAuthState(tokens.accessToken, null),
|
|
553
|
+
oauthTokens: tokens
|
|
554
|
+
}), cleanedUrl;
|
|
555
|
+
} catch (exchangeError) {
|
|
556
|
+
return logger.error("Failed to exchange OAuth code for tokens", { error: exchangeError }), clearOAuthArtifacts(session), state.set("oauthExchangeError", { authState: {
|
|
557
|
+
type: "error",
|
|
558
|
+
error: exchangeError
|
|
559
|
+
} }), cleanedUrl;
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
/**
|
|
563
|
+
* A refresh failure is unrecoverable only when the token endpoint rejects the
|
|
564
|
+
* refresh token itself (a 4xx). Rate-limit (429) and request-timeout (408)
|
|
565
|
+
* responses, 5xx errors and network failures are transient, so the session is
|
|
566
|
+
* kept intact for the caller to retry rather than forcing a logout.
|
|
567
|
+
*/
|
|
568
|
+
function isUnrecoverableRefreshError(error) {
|
|
569
|
+
return error instanceof ClientError && error.statusCode !== 408 && error.statusCode !== 429;
|
|
570
|
+
}
|
|
571
|
+
let refreshInFlight = null;
|
|
572
|
+
/**
|
|
573
|
+
* Refreshes the OAuth tokens using the `refresh_token` grant. Concurrent
|
|
574
|
+
* callers share a single in-flight request. An unrecoverable failure (a 4xx
|
|
575
|
+
* rejecting the refresh token) clears the tokens and transitions to
|
|
576
|
+
* `LOGGED_OUT`; transient failures (network, 5xx, rate limits) leave the
|
|
577
|
+
* session intact and rethrow so the caller can retry.
|
|
578
|
+
*
|
|
579
|
+
* @public
|
|
580
|
+
*/
|
|
581
|
+
const refreshOAuthTokens = bindActionGlobally(authStore, (context) => refreshInFlight || (refreshInFlight = doRefreshOAuthTokens(context).finally(() => {
|
|
582
|
+
refreshInFlight = null;
|
|
583
|
+
}), refreshInFlight));
|
|
584
|
+
async function doRefreshOAuthTokens({ state, instance }) {
|
|
585
|
+
let logger = getAuthLogger(instance), options = getOAuthOptions(state.get()), current = state.get().oauthTokens;
|
|
586
|
+
if (!current?.refreshToken) return logger.warn("No refresh token available — logging out"), options.storageArea?.removeItem(options.storageKey), state.set("oauthRefreshNoToken", {
|
|
587
|
+
authState: {
|
|
391
588
|
type: "logged-out",
|
|
392
589
|
isDestroyingSession: !1
|
|
393
|
-
}
|
|
590
|
+
},
|
|
591
|
+
oauthTokens: void 0
|
|
592
|
+
}), null;
|
|
593
|
+
try {
|
|
594
|
+
let client = createOAuthClient(options), params = new URLSearchParams({
|
|
595
|
+
grant_type: "refresh_token",
|
|
596
|
+
refresh_token: current.refreshToken,
|
|
597
|
+
client_id: options.oauth.clientId,
|
|
598
|
+
resource: getResourceIndicator(options.oauth.organizationId)
|
|
599
|
+
}), tokens = toOAuthTokens(await client.request({
|
|
600
|
+
method: "POST",
|
|
601
|
+
url: "/auth/oauth/token",
|
|
602
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
603
|
+
body: params.toString(),
|
|
604
|
+
tag: "oauth.refresh"
|
|
605
|
+
}));
|
|
606
|
+
return tokens.refreshToken ||= current.refreshToken, options.storageArea?.setItem(options.storageKey, serializeTokens(tokens)), logger.info("OAuth tokens refreshed"), state.set("oauthRefreshed", {
|
|
607
|
+
authState: createLoggedInAuthState(tokens.accessToken, null),
|
|
608
|
+
oauthTokens: tokens
|
|
609
|
+
}), tokens;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
throw isUnrecoverableRefreshError(error) ? (logger.error("OAuth token refresh failed — logging out", { error }), options.storageArea?.removeItem(options.storageKey), state.set("oauthRefreshFailed", {
|
|
612
|
+
authState: {
|
|
613
|
+
type: "logged-out",
|
|
614
|
+
isDestroyingSession: !1
|
|
615
|
+
},
|
|
616
|
+
oauthTokens: void 0
|
|
617
|
+
}), error) : (logger.warn("OAuth token refresh failed — keeping session for retry", { error }), error);
|
|
394
618
|
}
|
|
395
|
-
}
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Revokes the OAuth tokens then clears local storage and transitions to `LOGGED_OUT`.
|
|
622
|
+
* Local state is cleared even if the revoke request fails.
|
|
623
|
+
*
|
|
624
|
+
* @public
|
|
625
|
+
*/
|
|
626
|
+
const revokeOAuthTokens = bindActionGlobally(authStore, async ({ state, instance }) => {
|
|
627
|
+
let logger = getAuthLogger(instance), options = getOAuthOptions(state.get()), current = state.get().oauthTokens, token = current?.refreshToken ?? current?.accessToken;
|
|
628
|
+
try {
|
|
629
|
+
if (token) {
|
|
630
|
+
let client = createOAuthClient(options), params = new URLSearchParams({
|
|
631
|
+
token,
|
|
632
|
+
client_id: options.oauth.clientId
|
|
633
|
+
});
|
|
634
|
+
await client.request({
|
|
635
|
+
method: "POST",
|
|
636
|
+
url: "/auth/oauth/revoke",
|
|
637
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
638
|
+
body: params.toString(),
|
|
639
|
+
tag: "oauth.revoke"
|
|
640
|
+
}), logger.info("OAuth tokens revoked");
|
|
641
|
+
}
|
|
642
|
+
} catch (error) {
|
|
643
|
+
logger.warn("OAuth revoke request failed — clearing local state anyway", { error });
|
|
644
|
+
} finally {
|
|
645
|
+
options.storageArea?.removeItem(options.storageKey), state.set("oauthRevoked", {
|
|
646
|
+
authState: {
|
|
647
|
+
type: "logged-out",
|
|
648
|
+
isDestroyingSession: !1
|
|
649
|
+
},
|
|
650
|
+
oauthTokens: void 0
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}), getOAuthTokensState = bindActionGlobally(authStore, createStateSourceAction(({ state }) => state.oauthTokens ?? null));
|
|
654
|
+
/** Removes the transient PKCE artifacts from session storage. */
|
|
655
|
+
function clearOAuthArtifacts(session) {
|
|
656
|
+
session?.removeItem(OAUTH_VERIFIER_KEY), session?.removeItem(OAUTH_STATE_KEY);
|
|
657
|
+
}
|
|
396
658
|
function weaken(node) {
|
|
397
659
|
return Array.isArray(node) ? node.map(weaken) : node && typeof node == "object" ? "_ref" in node ? {
|
|
398
660
|
...node,
|
|
@@ -1228,7 +1490,29 @@ function unsetDeep(input, path) {
|
|
|
1228
1490
|
let segment = _segment;
|
|
1229
1491
|
return typeof segment == "number" && Array.isArray(input) && (segment = segment < 0 ? input.length + segment : segment), segment in input ? restOfPath.length ? Array.isArray(input) ? input.map((nestedInput, index) => index === segment ? unsetDeep(nestedInput, restOfPath) : nestedInput) : Object.fromEntries(Object.entries(input).map(([key, value]) => key === segment ? [key, unsetDeep(value, restOfPath)] : [key, value])) : Array.isArray(input) ? input.filter((_nestedInput, index) => index !== segment) : Object.fromEntries(Object.entries(input).filter(([key]) => key !== segment.toString())) : input;
|
|
1230
1492
|
}
|
|
1231
|
-
|
|
1493
|
+
/**
|
|
1494
|
+
* Exposes the patch operations used by {@link processMutations}.
|
|
1495
|
+
*
|
|
1496
|
+
* @remarks
|
|
1497
|
+
* Property order determines execution order in {@link processMutations}:
|
|
1498
|
+
* `ifRevisionID`, `set`, `setIfMissing`, `unset`, `inc`, `dec`, `insert`,
|
|
1499
|
+
* then `diffMatchPatch`. Reordering the properties changes mutation results.
|
|
1500
|
+
* Freezes the collection to prevent callers from replacing the functions
|
|
1501
|
+
* used by the SDK's mutation evaluator.
|
|
1502
|
+
*
|
|
1503
|
+
* @see https://www.sanity.io/docs/http-mutations#5b4db1396e56
|
|
1504
|
+
*
|
|
1505
|
+
* @example
|
|
1506
|
+
* ```ts
|
|
1507
|
+
* const document = {items: [{_key: 'a', title: 'Before'}]}
|
|
1508
|
+
* const updated = patchOperations.set<typeof document>(document, {
|
|
1509
|
+
* 'items[_key=="a"].title': 'After',
|
|
1510
|
+
* })
|
|
1511
|
+
* ```
|
|
1512
|
+
*
|
|
1513
|
+
* @internal
|
|
1514
|
+
*/
|
|
1515
|
+
const patchOperations = Object.freeze({
|
|
1232
1516
|
ifRevisionID,
|
|
1233
1517
|
set,
|
|
1234
1518
|
setIfMissing,
|
|
@@ -1237,7 +1521,7 @@ const patchOperations = {
|
|
|
1237
1521
|
dec,
|
|
1238
1522
|
insert,
|
|
1239
1523
|
diffMatchPatch
|
|
1240
|
-
};
|
|
1524
|
+
});
|
|
1241
1525
|
/**
|
|
1242
1526
|
* Implements ID generation:
|
|
1243
1527
|
*
|
|
@@ -1265,18 +1549,31 @@ function getDocumentIds(selection) {
|
|
|
1265
1549
|
return [];
|
|
1266
1550
|
}
|
|
1267
1551
|
/**
|
|
1268
|
-
* Applies
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1552
|
+
* Applies mutations to an in-memory set of Sanity documents.
|
|
1553
|
+
* Deleted documents remain in the returned set with a value of `null`.
|
|
1554
|
+
*
|
|
1555
|
+
* Include every document affected by `mutations` in `documents`, using `null`
|
|
1556
|
+
* for documents that do not exist.
|
|
1557
|
+
*
|
|
1558
|
+
* Returns `documents` itself when `mutations` is empty. Otherwise, returns a
|
|
1559
|
+
* shallow copy of that object. The result can reuse document objects and
|
|
1560
|
+
* nested objects from `documents`. Mutating a reused object through the
|
|
1561
|
+
* result also changes the input.
|
|
1274
1562
|
*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1563
|
+
* Sets `_rev` to `transactionId` on created, replaced, and patched documents.
|
|
1564
|
+
* Uses `timestamp` for timestamps unless the mutation preserves them.
|
|
1565
|
+
* Ignores `merge` patches; `inc` and `dec` skip values that are not numbers.
|
|
1566
|
+
* Generates document IDs when omitted or ending in `.`.
|
|
1567
|
+
* Patch operations can generate missing array keys.
|
|
1277
1568
|
*
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1569
|
+
* Does not persist documents or run Content Lake's server validation.
|
|
1570
|
+
*
|
|
1571
|
+
* @throws If a selection uses a query, a `create` targets an existing document,
|
|
1572
|
+
* or a `patch` targets a document that does not exist.
|
|
1573
|
+
* @throws If a patch operation fails, including a revision check failure or
|
|
1574
|
+
* `diffMatchPatch` applied to a value other than a string or `undefined`.
|
|
1575
|
+
*
|
|
1576
|
+
* @internal
|
|
1280
1577
|
*/
|
|
1281
1578
|
function processMutations({ documents, mutations, transactionId, timestamp }) {
|
|
1282
1579
|
if (!mutations.length) return documents;
|
|
@@ -1336,36 +1633,6 @@ function processMutations({ documents, mutations, transactionId, timestamp }) {
|
|
|
1336
1633
|
}
|
|
1337
1634
|
return dataset;
|
|
1338
1635
|
}
|
|
1339
|
-
function _typeof(o) {
|
|
1340
|
-
"@babel/helpers - typeof";
|
|
1341
|
-
return _typeof = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(o) {
|
|
1342
|
-
return typeof o;
|
|
1343
|
-
} : function(o) {
|
|
1344
|
-
return o && typeof Symbol == "function" && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
1345
|
-
}, _typeof(o);
|
|
1346
|
-
}
|
|
1347
|
-
function toPrimitive(t, r) {
|
|
1348
|
-
if (_typeof(t) != "object" || !t) return t;
|
|
1349
|
-
var e = t[Symbol.toPrimitive];
|
|
1350
|
-
if (e !== void 0) {
|
|
1351
|
-
var i = e.call(t, r || "default");
|
|
1352
|
-
if (_typeof(i) != "object") return i;
|
|
1353
|
-
throw TypeError("@@toPrimitive must return a primitive value.");
|
|
1354
|
-
}
|
|
1355
|
-
return (r === "string" ? String : Number)(t);
|
|
1356
|
-
}
|
|
1357
|
-
function toPropertyKey(t) {
|
|
1358
|
-
var i = toPrimitive(t, "string");
|
|
1359
|
-
return _typeof(i) == "symbol" ? i : i + "";
|
|
1360
|
-
}
|
|
1361
|
-
function _defineProperty(e, r, t) {
|
|
1362
|
-
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
1363
|
-
value: t,
|
|
1364
|
-
enumerable: !0,
|
|
1365
|
-
configurable: !0,
|
|
1366
|
-
writable: !0
|
|
1367
|
-
}) : e[r] = t, e;
|
|
1368
|
-
}
|
|
1369
1636
|
var OutOfSyncError = class extends Error {
|
|
1370
1637
|
constructor(message, state) {
|
|
1371
1638
|
super(message), _defineProperty(
|
|
@@ -4228,6 +4495,23 @@ function resolveProjection(...args) {
|
|
|
4228
4495
|
*/
|
|
4229
4496
|
const _resolveProjection = bindActionByResourceAndPerspective(projectionStore, ({ instance }, options) => firstValueFrom(getProjectionState(instance, options).observable.pipe(filter((state) => !!state?.data))));
|
|
4230
4497
|
/**
|
|
4498
|
+
* Preserves a projection string's literal type and returns the string unchanged.
|
|
4499
|
+
* Use this import when migrating an app with existing experimental Typegen output.
|
|
4500
|
+
*
|
|
4501
|
+
* Current Typegen does not scan this helper. New or changed projections need an
|
|
4502
|
+
* explicit result type until projection generation is supported.
|
|
4503
|
+
*
|
|
4504
|
+
* @example
|
|
4505
|
+
* ```ts
|
|
4506
|
+
* const preview = defineProjection('{title, "author": author->name}')
|
|
4507
|
+
* ```
|
|
4508
|
+
*
|
|
4509
|
+
* @beta
|
|
4510
|
+
*/
|
|
4511
|
+
function defineProjection(projection) {
|
|
4512
|
+
return projection;
|
|
4513
|
+
}
|
|
4514
|
+
/**
|
|
4231
4515
|
* @public
|
|
4232
4516
|
* Extracts the project ID from a CorsOriginError message.
|
|
4233
4517
|
* @param error - The error to extract the project ID from.
|
|
@@ -4265,6 +4549,6 @@ function isImportError(error) {
|
|
|
4265
4549
|
let message = error.message || "";
|
|
4266
4550
|
return /Loading chunk [\w-]+ failed/i.test(message) || /Failed to fetch dynamically imported module/i.test(message) || /error loading dynamically imported module/i.test(message) || /Import(?:ing)? a module script failed/i.test(message) || /Unable to preload CSS/i.test(message);
|
|
4267
4551
|
}
|
|
4268
|
-
export { AuthStateType, CORE_SDK_VERSION, application, applications, applyDocumentActions, archiveRelease, checkPermissions, configureLogging, createComment, createDatasetHandle, createDocument, createDocumentHandle, createDocumentTypeHandle, createProjectHandle, createRelease, createSanityInstance, datasets, deleteApplication, deleteDocument, deleteRelease, discardDocument, editDocument, editRelease, favorites, getActiveReleasesState, getAllReleasesState, getAuthState, getClient, getClientState, getCommentThreadsState, getCommentsState, getCorsErrorProjectId, getCurrentUserState, getDashboardOrganizationId, getDocumentPresence, getDocumentState, getDocumentSyncStatus, getIndexForKey, getIsInDashboardState, getLoginUrlState, getPathDepth, getPermissionsState, getPerspectiveState, getPresence, getProjectionState, getQueryState, getReleaseDocumentId, getTokenState, getUserState, getUsersState, handleAuthCallback, installation, installations, isCanvasResource, isDatasetResource, isImportError, isMediaLibraryResource, joinPaths, jsonMatch, loadMoreUsers, logout, observeOrganizationVerificationState, organization, organizations, project, projects, publishDocument, publishRelease, removeComment, replyToComment, reportPresence, resolveCommentThreads, resolveComments, resolveDocument, resolvePermissions, resolveProjection, resolveQuery, resolveUser, resolveUsers, scheduleRelease, setAuthToken, setCommentStatus, setFavorite, slicePath, stringifyPath, subscribeDocumentEvents, unarchiveRelease, unpublishDocument, unscheduleRelease, updateApplication, updateComment };
|
|
4552
|
+
export { AuthStateType, CORE_SDK_VERSION, application, applications, applyDocumentActions, archiveRelease, checkPermissions, configureLogging, createComment, createDatasetHandle, createDocument, createDocumentHandle, createDocumentTypeHandle, createProjectHandle, createRelease, createSanityInstance, datasets, defineProjection, deleteApplication, deleteDocument, deleteRelease, discardDocument, editDocument, editRelease, favorites, getActiveReleasesState, getAllReleasesState, getAuthState, getClient, getClientState, getCommentThreadsState, getCommentsState, getCorsErrorProjectId, getCurrentUserState, getDashboardOrganizationId, getDocumentPresence, getDocumentState, getDocumentSyncStatus, getIndexForKey, getIsInDashboardState, getLoginUrlState, getOAuthTokensState, getPathDepth, getPermissionsState, getPerspectiveState, getPresence, getProjectionState, getQueryState, getReleaseDocumentId, getTokenState, getUserState, getUsersState, handleAuthCallback, handleOAuthCallback, installation, installations, isCanvasResource, isDatasetResource, isImportError, isMediaLibraryResource, joinPaths, jsonMatch, loadMoreUsers, logout, observeOrganizationVerificationState, organization, organizations, patchOperations, processMutations, project, projects, publishDocument, publishRelease, refreshOAuthTokens, removeComment, replyToComment, reportPresence, resolveCommentThreads, resolveComments, resolveDocument, resolvePermissions, resolveProjection, resolveQuery, resolveUser, resolveUsers, revokeOAuthTokens, scheduleRelease, setAuthToken, setCommentStatus, setFavorite, slicePath, startOAuthAuthorization, stringifyPath, subscribeDocumentEvents, unarchiveRelease, unpublishDocument, unscheduleRelease, updateApplication, updateComment };
|
|
4269
4553
|
|
|
4270
4554
|
//# sourceMappingURL=index.js.map
|