@sanity/client 6.28.4-beta.0 → 6.28.4-resources.4

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.
@@ -2015,8 +2015,8 @@
2015
2015
  }
2016
2016
  function shouldRetry(err, attempt, options) {
2017
2017
  if (options.maxRetries === 0) return false;
2018
- const isSafe = options.method === "GET" || options.method === "HEAD", isQuery = (options.uri || options.url).startsWith("/data/query"), isRetriableResponse = err.response && (err.response.statusCode === 429 || err.response.statusCode === 502 || err.response.statusCode === 503);
2019
- return (isSafe || isQuery) && isRetriableResponse ? true : P.shouldRetry(err, attempt, options);
2018
+ const isSafe = options.method === "GET" || options.method === "HEAD", isQuery2 = (options.uri || options.url).startsWith("/data/query"), isRetriableResponse = err.response && (err.response.statusCode === 429 || err.response.statusCode === 502 || err.response.statusCode === 503);
2019
+ return (isSafe || isQuery2) && isRetriableResponse ? true : P.shouldRetry(err, attempt, options);
2020
2020
  }
2021
2021
  const BASE_URL = "https://www.sanity.io/help/";
2022
2022
  function generateHelpUrl(slug) {
@@ -2063,6 +2063,26 @@
2063
2063
  "Tag can only contain alphanumeric characters, underscores, dashes and dots, and be between one and 75 characters long."
2064
2064
  );
2065
2065
  return tag;
2066
+ }, resourceConfig = (config) => {
2067
+ if (!config["~experimental_resource"])
2068
+ throw new Error("`resource` must be provided to perform resource queries");
2069
+ const { type, id } = config["~experimental_resource"];
2070
+ switch (type) {
2071
+ case "dataset": {
2072
+ if (id.split(".").length !== 2)
2073
+ throw new Error('Dataset resource ID must be in the format "project.dataset"');
2074
+ return;
2075
+ }
2076
+ case "dashboard":
2077
+ case "media-library":
2078
+ case "canvas":
2079
+ return;
2080
+ default:
2081
+ throw new Error(`Unsupported resource type: ${type.toString()}`);
2082
+ }
2083
+ }, resourceGuard = (service, config) => {
2084
+ if (config["~experimental_resource"])
2085
+ throw new Error(`\`${service}\` does not support resource-based operations`);
2066
2086
  };
2067
2087
  function once(fn) {
2068
2088
  let didCall = false, returnValue;
@@ -2109,21 +2129,11 @@
2109
2129
  if (!(/^\d{4}-\d{2}-\d{2}$/.test(apiVersion) && apiDate instanceof Date && apiDate.getTime() > 0))
2110
2130
  throw new Error("Invalid API version string, expected `1` or date in format `YYYY-MM-DD`");
2111
2131
  }
2112
- const VALID_PERSPECTIVE = /^[a-z0-9_]+$/i;
2113
2132
  function validateApiPerspective(perspective) {
2114
- if (Array.isArray(perspective) && perspective.includes("raw"))
2133
+ if (Array.isArray(perspective) && perspective.length > 1 && perspective.includes("raw"))
2115
2134
  throw new TypeError(
2116
2135
  'Invalid API perspective value: "raw". The raw-perspective can not be combined with other perspectives'
2117
2136
  );
2118
- const invalid = (Array.isArray(perspective) ? perspective : [perspective]).filter(
2119
- (perspectiveName) => typeof perspectiveName != "string" || !VALID_PERSPECTIVE.test(perspectiveName)
2120
- );
2121
- if (invalid.length > 0) {
2122
- const formatted = invalid.map((v) => JSON.stringify(v));
2123
- throw new TypeError(
2124
- `Invalid API perspective value${invalid.length === 1 ? "" : "s"}: ${formatted.join(", ")}, expected \`published\`, \`drafts\`, \`raw\` or a release identifier string`
2125
- );
2126
- }
2127
2137
  }
2128
2138
  const initConfig = (config, prevConfig) => {
2129
2139
  const specifiedConfig = {
@@ -2138,14 +2148,14 @@
2138
2148
  const newConfig = {
2139
2149
  ...defaultConfig,
2140
2150
  ...specifiedConfig
2141
- }, projectBased = newConfig.useProjectHostname;
2151
+ }, projectBased = newConfig.useProjectHostname && !newConfig["~experimental_resource"];
2142
2152
  if (typeof Promise > "u") {
2143
2153
  const helpUrl = generateHelpUrl("js-client-promise-polyfill");
2144
2154
  throw new Error(`No native Promise-implementation found, polyfill needed - see ${helpUrl}`);
2145
2155
  }
2146
2156
  if (projectBased && !newConfig.projectId)
2147
2157
  throw new Error("Configuration must contain `projectId`");
2148
- if (typeof newConfig.perspective < "u" && validateApiPerspective(newConfig.perspective), "encodeSourceMap" in newConfig)
2158
+ if (newConfig["~experimental_resource"] && resourceConfig(newConfig), typeof newConfig.perspective < "u" && validateApiPerspective(newConfig.perspective), "encodeSourceMap" in newConfig)
2149
2159
  throw new Error(
2150
2160
  "It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMap' is not supported in '@sanity/client'. Did you mean 'stega.enabled'?"
2151
2161
  );
@@ -2162,10 +2172,9 @@
2162
2172
  `stega.studioUrl must be a string or a function, received ${newConfig.stega.studioUrl}`
2163
2173
  );
2164
2174
  const isBrowser = typeof window < "u" && window.location && window.location.hostname, isLocalhost = isBrowser && isLocal(window.location.hostname), hasToken = !!newConfig.token;
2165
- let withCredentials = !!newConfig.withCredentials;
2166
- withCredentials && hasToken && (printCredentialedTokenWarning(), withCredentials = false), isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== true ? printBrowserTokenWarning() : typeof newConfig.useCdn > "u" && printCdnWarning(), projectBased && projectId(newConfig.projectId), newConfig.dataset && dataset(newConfig.dataset), "requestTagPrefix" in newConfig && (newConfig.requestTagPrefix = newConfig.requestTagPrefix ? requestTag(newConfig.requestTagPrefix).replace(/\.+$/, "") : void 0), newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, ""), newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost, newConfig.useCdn === true && withCredentials && printCdnAndWithCredentialsWarning(), newConfig.useCdn = newConfig.useCdn !== false && !withCredentials, validateApiVersion(newConfig.apiVersion);
2175
+ newConfig.withCredentials && hasToken && (printCredentialedTokenWarning(), newConfig.withCredentials = false), isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== true ? printBrowserTokenWarning() : typeof newConfig.useCdn > "u" && printCdnWarning(), projectBased && projectId(newConfig.projectId), newConfig.dataset && dataset(newConfig.dataset), "requestTagPrefix" in newConfig && (newConfig.requestTagPrefix = newConfig.requestTagPrefix ? requestTag(newConfig.requestTagPrefix).replace(/\.+$/, "") : void 0), newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, ""), newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost, newConfig.useCdn === true && newConfig.withCredentials && printCdnAndWithCredentialsWarning(), newConfig.useCdn = newConfig.useCdn !== false && !newConfig.withCredentials, validateApiVersion(newConfig.apiVersion);
2167
2176
  const hostParts = newConfig.apiHost.split("://", 2), protocol = hostParts[0], host = hostParts[1], cdnHost = newConfig.isDefaultApi ? defaultCdnHost : host;
2168
- return newConfig.useProjectHostname ? (newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`, newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`) : (newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`, newConfig.cdnUrl = newConfig.url), newConfig;
2177
+ return projectBased ? (newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`, newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`) : (newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`, newConfig.cdnUrl = newConfig.url), newConfig;
2169
2178
  };
2170
2179
  class ConnectionFailedError extends Error {
2171
2180
  name = "ConnectionFailedError";
@@ -2733,7 +2742,7 @@ ${selectionOpts}`);
2733
2742
  );
2734
2743
  }
2735
2744
  function _dataRequest(client, httpRequest, endpoint, body, options = {}) {
2736
- const isMutation = endpoint === "mutate", isAction = endpoint === "actions", isQuery = endpoint === "query", strQuery = isMutation || isAction ? "" : encodeQueryString(body), useGet = !isMutation && !isAction && strQuery.length < getQuerySizeLimit, stringQuery = useGet ? strQuery : "", returnFirst = options.returnFirst, { timeout, token, tag, headers, returnQuery, lastLiveEventId, cacheMode } = options, uri = _getDataUrl(client, endpoint, stringQuery), reqOptions = {
2745
+ const isMutation = endpoint === "mutate", isAction = endpoint === "actions", isQuery2 = endpoint === "query", strQuery = isMutation || isAction ? "" : encodeQueryString(body), useGet = !isMutation && !isAction && strQuery.length < getQuerySizeLimit, stringQuery = useGet ? strQuery : "", returnFirst = options.returnFirst, { timeout, token, tag, headers, returnQuery, lastLiveEventId, cacheMode } = options, uri = _getDataUrl(client, endpoint, stringQuery), reqOptions = {
2737
2746
  method: useGet ? "GET" : "POST",
2738
2747
  uri,
2739
2748
  json: true,
@@ -2748,7 +2757,7 @@ ${selectionOpts}`);
2748
2757
  resultSourceMap: options.resultSourceMap,
2749
2758
  lastLiveEventId: Array.isArray(lastLiveEventId) ? lastLiveEventId[0] : lastLiveEventId,
2750
2759
  cacheMode,
2751
- canUseCdn: isQuery,
2760
+ canUseCdn: isQuery2,
2752
2761
  signal: options.signal,
2753
2762
  fetch: options.fetch,
2754
2763
  useAbortSignal: options.useAbortSignal,
@@ -2776,11 +2785,12 @@ ${selectionOpts}`);
2776
2785
  const mutation = { [op]: doc }, opts = Object.assign({ returnFirst: true, returnDocuments: true }, options);
2777
2786
  return _dataRequest(client, httpRequest, "mutate", { mutations: [mutation] }, opts);
2778
2787
  }
2788
+ const hasDataConfig = (client) => client.config().dataset !== void 0 && client.config().projectId !== void 0 || client.config()["~experimental_resource"] !== void 0, isQuery = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "query")), isMutate = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "mutate")), isDoc = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "doc", "")), isListener = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "listen")), isHistory = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "history", "")), isData = (client, uri) => uri.startsWith("/data/") || isQuery(client, uri) || isMutate(client, uri) || isDoc(client, uri) || isListener(client, uri) || isHistory(client, uri);
2779
2789
  function _requestObservable(client, httpRequest, options) {
2780
- const uri = options.url || options.uri, config = client.config(), canUseCdn = typeof options.canUseCdn > "u" ? ["GET", "HEAD"].indexOf(options.method || "GET") >= 0 && uri.indexOf("/data/") === 0 : options.canUseCdn;
2790
+ const uri = options.url || options.uri, config = client.config(), canUseCdn = typeof options.canUseCdn > "u" ? ["GET", "HEAD"].indexOf(options.method || "GET") >= 0 && isData(client, uri) : options.canUseCdn;
2781
2791
  let useCdn = (options.useCdn ?? config.useCdn) && canUseCdn;
2782
2792
  const tag = options.tag && config.requestTagPrefix ? [config.requestTagPrefix, options.tag].join(".") : options.tag || config.requestTagPrefix;
2783
- if (tag && options.tag !== null && (options.query = { tag: requestTag(tag), ...options.query }), ["GET", "HEAD", "POST"].indexOf(options.method || "GET") >= 0 && uri.indexOf("/data/query/") === 0) {
2793
+ if (tag && options.tag !== null && (options.query = { tag: requestTag(tag), ...options.query }), ["GET", "HEAD", "POST"].indexOf(options.method || "GET") >= 0 && isQuery(client, uri)) {
2784
2794
  const resultSourceMap = options.resultSourceMap ?? config.resultSourceMap;
2785
2795
  resultSourceMap !== void 0 && resultSourceMap !== false && (options.query = { resultSourceMap, ...options.query });
2786
2796
  const perspectiveOption = options.perspective || config.perspective;
@@ -2807,8 +2817,14 @@ ${selectionOpts}`);
2807
2817
  );
2808
2818
  }
2809
2819
  function _getDataUrl(client, operation, path) {
2810
- const config = client.config(), catalog = hasDataset(config), baseUri = `/${operation}/${catalog}`;
2811
- return `/data${path ? `${baseUri}/${path}` : baseUri}`.replace(/\/($|\?)/, "$1");
2820
+ const config = client.config();
2821
+ if (config["~experimental_resource"]) {
2822
+ resourceConfig(config);
2823
+ const resourceBase = resourceDataBase(config), uri2 = path !== void 0 ? `${operation}/${path}` : operation;
2824
+ return `${resourceBase}/${uri2}`.replace(/\/($|\?)/, "$1");
2825
+ }
2826
+ const catalog = hasDataset(config), baseUri = `/${operation}/${catalog}`;
2827
+ return `/data${path !== void 0 ? `${baseUri}/${path}` : baseUri}`.replace(/\/($|\?)/, "$1");
2812
2828
  }
2813
2829
  function _getUrl(client, uri, canUseCdn = false) {
2814
2830
  const { url, cdnUrl } = client.config();
@@ -2834,6 +2850,27 @@ ${selectionOpts}`);
2834
2850
  const error = new Error(signal?.reason ?? "The operation was aborted.");
2835
2851
  return error.name = "AbortError", error;
2836
2852
  }
2853
+ const resourceDataBase = (config) => {
2854
+ if (!config["~experimental_resource"])
2855
+ throw new Error("`resource` must be provided to perform resource queries");
2856
+ const { type, id } = config["~experimental_resource"];
2857
+ switch (type) {
2858
+ case "dataset": {
2859
+ const segments = id.split(".");
2860
+ if (segments.length !== 2)
2861
+ throw new Error('Dataset ID must be in the format "project.dataset"');
2862
+ return `/projects/${segments[0]}/datasets/${segments[1]}`;
2863
+ }
2864
+ case "canvas":
2865
+ return `/canvases/${id}`;
2866
+ case "media-library":
2867
+ return `/media-libraries/${id}`;
2868
+ case "dashboard":
2869
+ return `/dashboards/${id}`;
2870
+ default:
2871
+ throw new Error(`Unsupported resource type: ${type.toString()}`);
2872
+ }
2873
+ };
2837
2874
  class ObservableAssetsClient {
2838
2875
  #client;
2839
2876
  #httpRequest;
@@ -2866,7 +2903,7 @@ ${selectionOpts}`);
2866
2903
  validateAssetType(assetType);
2867
2904
  let meta = opts.extract || void 0;
2868
2905
  meta && !meta.length && (meta = ["none"]);
2869
- const dataset2 = hasDataset(client.config()), assetEndpoint = assetType === "image" ? "images" : "files", options = optionsFromFile(opts, body), { tag, label, title, description, creditLine, filename, source } = options, query = {
2906
+ const config = client.config(), options = optionsFromFile(opts, body), { tag, label, title, description, creditLine, filename, source } = options, query = {
2870
2907
  label,
2871
2908
  title,
2872
2909
  description,
@@ -2878,12 +2915,34 @@ ${selectionOpts}`);
2878
2915
  tag,
2879
2916
  method: "POST",
2880
2917
  timeout: options.timeout || 0,
2881
- uri: `/assets/${assetEndpoint}/${dataset2}`,
2918
+ uri: buildAssetUploadUrl(config, assetType),
2882
2919
  headers: options.contentType ? { "Content-Type": options.contentType } : {},
2883
2920
  query,
2884
2921
  body
2885
2922
  });
2886
2923
  }
2924
+ function buildAssetUploadUrl(config, assetType) {
2925
+ const assetTypeEndpoint = assetType === "image" ? "images" : "files";
2926
+ if (config["~experimental_resource"]) {
2927
+ const { type, id } = config["~experimental_resource"];
2928
+ switch (type) {
2929
+ case "dataset":
2930
+ throw new Error(
2931
+ "Assets are not supported for dataset resources, yet. Configure the client with `{projectId: <projectId>, dataset: <datasetId>}` instead."
2932
+ );
2933
+ case "canvas":
2934
+ return `/canvases/${id}/assets/${assetTypeEndpoint}`;
2935
+ case "media-library":
2936
+ return `/media-libraries/${id}/upload`;
2937
+ case "dashboard":
2938
+ return `/dashboards/${id}/assets/${assetTypeEndpoint}`;
2939
+ default:
2940
+ throw new Error(`Unsupported resource type: ${type.toString()}`);
2941
+ }
2942
+ }
2943
+ const dataset2 = hasDataset(config);
2944
+ return `assets/${assetTypeEndpoint}/${dataset2}`;
2945
+ }
2887
2946
  function optionsFromFile(opts, file) {
2888
2947
  return typeof File > "u" || !(file instanceof File) ? opts : Object.assign(
2889
2948
  {
@@ -2975,6 +3034,7 @@ ${selectionOpts}`);
2975
3034
  includeDrafts = false,
2976
3035
  tag: _tag
2977
3036
  } = {}) {
3037
+ resourceGuard("live", this.#client.config());
2978
3038
  const {
2979
3039
  projectId: projectId2,
2980
3040
  apiVersion: _apiVersion,
@@ -3104,7 +3164,7 @@ ${selectionOpts}`);
3104
3164
  * @param options - Options for the dataset
3105
3165
  */
3106
3166
  create(name, options) {
3107
- return lastValueFrom(
3167
+ return resourceGuard("dataset", this.#client.config()), lastValueFrom(
3108
3168
  _modify(this.#client, this.#httpRequest, "PUT", name, options)
3109
3169
  );
3110
3170
  }
@@ -3115,7 +3175,7 @@ ${selectionOpts}`);
3115
3175
  * @param options - New options for the dataset
3116
3176
  */
3117
3177
  edit(name, options) {
3118
- return lastValueFrom(
3178
+ return resourceGuard("dataset", this.#client.config()), lastValueFrom(
3119
3179
  _modify(this.#client, this.#httpRequest, "PATCH", name, options)
3120
3180
  );
3121
3181
  }
@@ -3125,19 +3185,19 @@ ${selectionOpts}`);
3125
3185
  * @param name - Name of the dataset to delete
3126
3186
  */
3127
3187
  delete(name) {
3128
- return lastValueFrom(_modify(this.#client, this.#httpRequest, "DELETE", name));
3188
+ return resourceGuard("dataset", this.#client.config()), lastValueFrom(_modify(this.#client, this.#httpRequest, "DELETE", name));
3129
3189
  }
3130
3190
  /**
3131
3191
  * Fetch a list of datasets for the configured project
3132
3192
  */
3133
3193
  list() {
3134
- return lastValueFrom(
3194
+ return resourceGuard("dataset", this.#client.config()), lastValueFrom(
3135
3195
  _request(this.#client, this.#httpRequest, { uri: "/datasets", tag: null })
3136
3196
  );
3137
3197
  }
3138
3198
  }
3139
3199
  function _modify(client, httpRequest, method, name, options) {
3140
- return dataset(name), _request(client, httpRequest, {
3200
+ return resourceGuard("dataset", client.config()), dataset(name), _request(client, httpRequest, {
3141
3201
  method,
3142
3202
  uri: `/datasets/${name}`,
3143
3203
  body: options,
@@ -3151,6 +3211,7 @@ ${selectionOpts}`);
3151
3211
  this.#client = client, this.#httpRequest = httpRequest;
3152
3212
  }
3153
3213
  list(options) {
3214
+ resourceGuard("projects", this.#client.config());
3154
3215
  const uri = options?.includeMembers === false ? "/projects?includeMembers=false" : "/projects";
3155
3216
  return _request(this.#client, this.#httpRequest, { uri });
3156
3217
  }
@@ -3160,7 +3221,7 @@ ${selectionOpts}`);
3160
3221
  * @param projectId - ID of the project to fetch
3161
3222
  */
3162
3223
  getById(projectId2) {
3163
- return _request(this.#client, this.#httpRequest, { uri: `/projects/${projectId2}` });
3224
+ return resourceGuard("projects", this.#client.config()), _request(this.#client, this.#httpRequest, { uri: `/projects/${projectId2}` });
3164
3225
  }
3165
3226
  }
3166
3227
  class ProjectsClient {
@@ -3170,6 +3231,7 @@ ${selectionOpts}`);
3170
3231
  this.#client = client, this.#httpRequest = httpRequest;
3171
3232
  }
3172
3233
  list(options) {
3234
+ resourceGuard("projects", this.#client.config());
3173
3235
  const uri = options?.includeMembers === false ? "/projects?includeMembers=false" : "/projects";
3174
3236
  return lastValueFrom(_request(this.#client, this.#httpRequest, { uri }));
3175
3237
  }
@@ -3179,7 +3241,7 @@ ${selectionOpts}`);
3179
3241
  * @param projectId - ID of the project to fetch
3180
3242
  */
3181
3243
  getById(projectId2) {
3182
- return lastValueFrom(
3244
+ return resourceGuard("projects", this.#client.config()), lastValueFrom(
3183
3245
  _request(this.#client, this.#httpRequest, { uri: `/projects/${projectId2}` })
3184
3246
  );
3185
3247
  }