@sanity/client 7.3.0 → 7.4.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.
Files changed (53) hide show
  1. package/README.md +122 -1
  2. package/dist/_chunks-cjs/isRecord.cjs +6 -0
  3. package/dist/_chunks-cjs/isRecord.cjs.map +1 -0
  4. package/dist/_chunks-cjs/resolveEditInfo.cjs +3 -5
  5. package/dist/_chunks-cjs/resolveEditInfo.cjs.map +1 -1
  6. package/dist/_chunks-cjs/stegaClean.cjs +4 -0
  7. package/dist/_chunks-cjs/stegaClean.cjs.map +1 -1
  8. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +2 -5
  9. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +1 -1
  10. package/dist/_chunks-es/isRecord.js +7 -0
  11. package/dist/_chunks-es/isRecord.js.map +1 -0
  12. package/dist/_chunks-es/resolveEditInfo.js +1 -3
  13. package/dist/_chunks-es/resolveEditInfo.js.map +1 -1
  14. package/dist/_chunks-es/stegaClean.js +4 -0
  15. package/dist/_chunks-es/stegaClean.js.map +1 -1
  16. package/dist/_chunks-es/stegaEncodeSourceMap.js +1 -4
  17. package/dist/_chunks-es/stegaEncodeSourceMap.js.map +1 -1
  18. package/dist/index.browser.cjs +155 -32
  19. package/dist/index.browser.cjs.map +1 -1
  20. package/dist/index.browser.d.cts +473 -68
  21. package/dist/index.browser.d.ts +473 -68
  22. package/dist/index.browser.js +156 -33
  23. package/dist/index.browser.js.map +1 -1
  24. package/dist/index.cjs +157 -34
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +473 -68
  27. package/dist/index.d.ts +473 -68
  28. package/dist/index.js +157 -33
  29. package/dist/index.js.map +1 -1
  30. package/dist/stega.browser.d.cts +473 -68
  31. package/dist/stega.browser.d.ts +473 -68
  32. package/dist/stega.d.cts +473 -68
  33. package/dist/stega.d.ts +473 -68
  34. package/package.json +1 -1
  35. package/src/agent/actions/AgentActionsClient.ts +29 -2
  36. package/src/agent/actions/commonTypes.ts +57 -17
  37. package/src/agent/actions/generate.ts +36 -2
  38. package/src/agent/actions/patch.ts +136 -0
  39. package/src/agent/actions/prompt.ts +145 -0
  40. package/src/agent/actions/transform.ts +27 -4
  41. package/src/agent/actions/translate.ts +5 -2
  42. package/src/csm/walkMap.ts +1 -1
  43. package/src/data/eventsource.ts +16 -7
  44. package/src/data/listen.ts +10 -4
  45. package/src/data/live.ts +13 -5
  46. package/src/defineCreateClient.ts +7 -1
  47. package/src/http/errors.ts +92 -27
  48. package/src/http/request.ts +3 -3
  49. package/src/types.ts +25 -10
  50. package/src/util/codeFrame.ts +174 -0
  51. package/src/{csm → util}/isRecord.ts +1 -1
  52. package/umd/sanityClient.js +158 -35
  53. package/umd/sanityClient.min.js +2 -2
@@ -2,17 +2,86 @@ import { getIt } from "get-it";
2
2
  import { adapter, environment } from "get-it";
3
3
  import { retry, jsonRequest, jsonResponse, progress, observable } from "get-it/middleware";
4
4
  import { Observable, defer, of, isObservable, mergeMap, from, lastValueFrom, shareReplay, catchError, concat, throwError, timer, tap, finalize, share, merge, EMPTY, map as map$1, firstValueFrom } from "rxjs";
5
- import { stegaClean } from "./_chunks-es/stegaClean.js";
5
+ import { isRecord, stegaClean } from "./_chunks-es/stegaClean.js";
6
6
  import { combineLatestWith, map, filter, finalize as finalize$1 } from "rxjs/operators";
7
7
  import { getVersionFromId, isDraftId, getVersionId, getDraftId, isVersionId, getPublishedId } from "@sanity/client/csm";
8
8
  import { customAlphabet } from "nanoid";
9
+ const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
10
+ function codeFrame(query, location2, message) {
11
+ const lines = query.split(NEWLINE), loc = {
12
+ start: columnToLine(location2.start, lines),
13
+ end: location2.end ? columnToLine(location2.end, lines) : void 0
14
+ }, { start, end, markerLines } = getMarkerLines(loc, lines), numberMaxWidth = `${end}`.length;
15
+ return query.split(NEWLINE, end).slice(start, end).map((line, index) => {
16
+ const number = start + 1 + index, gutter = ` ${` ${number}`.slice(-numberMaxWidth)} |`, hasMarker = markerLines[number], lastMarkerLine = !markerLines[number + 1];
17
+ if (!hasMarker)
18
+ return ` ${gutter}${line.length > 0 ? ` ${line}` : ""}`;
19
+ let markerLine = "";
20
+ if (Array.isArray(hasMarker)) {
21
+ const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " "), numberOfMarkers = hasMarker[1] || 1;
22
+ markerLine = [
23
+ `
24
+ `,
25
+ gutter.replace(/\d/g, " "),
26
+ " ",
27
+ markerSpacing,
28
+ "^".repeat(numberOfMarkers)
29
+ ].join(""), lastMarkerLine && message && (markerLine += " " + message);
30
+ }
31
+ return [">", gutter, line.length > 0 ? ` ${line}` : "", markerLine].join("");
32
+ }).join(`
33
+ `);
34
+ }
35
+ function getMarkerLines(loc, source) {
36
+ const startLoc = { ...loc.start }, endLoc = { ...startLoc, ...loc.end }, linesAbove = 2, linesBelow = 3, startLine = startLoc.line ?? -1, startColumn = startLoc.column ?? 0, endLine = endLoc.line, endColumn = endLoc.column;
37
+ let start = Math.max(startLine - (linesAbove + 1), 0), end = Math.min(source.length, endLine + linesBelow);
38
+ startLine === -1 && (start = 0), endLine === -1 && (end = source.length);
39
+ const lineDiff = endLine - startLine, markerLines = {};
40
+ if (lineDiff)
41
+ for (let i = 0; i <= lineDiff; i++) {
42
+ const lineNumber = i + startLine;
43
+ if (!startColumn)
44
+ markerLines[lineNumber] = !0;
45
+ else if (i === 0) {
46
+ const sourceLength = source[lineNumber - 1].length;
47
+ markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
48
+ } else if (i === lineDiff)
49
+ markerLines[lineNumber] = [0, endColumn];
50
+ else {
51
+ const sourceLength = source[lineNumber - i].length;
52
+ markerLines[lineNumber] = [0, sourceLength];
53
+ }
54
+ }
55
+ else
56
+ startColumn === endColumn ? startColumn ? markerLines[startLine] = [startColumn, 0] : markerLines[startLine] = !0 : markerLines[startLine] = [startColumn, endColumn - startColumn];
57
+ return { start, end, markerLines };
58
+ }
59
+ function columnToLine(column, lines) {
60
+ let offset = 0;
61
+ for (let i = 0; i < lines.length; i++) {
62
+ const lineLength = lines[i].length + 1;
63
+ if (offset + lineLength > column)
64
+ return {
65
+ line: i + 1,
66
+ // 1-based line
67
+ column: column - offset
68
+ // 0-based column
69
+ };
70
+ offset += lineLength;
71
+ }
72
+ return {
73
+ line: lines.length,
74
+ column: lines[lines.length - 1]?.length ?? 0
75
+ };
76
+ }
77
+ const MAX_ITEMS_IN_ERROR_MESSAGE = 5;
9
78
  class ClientError extends Error {
10
79
  response;
11
80
  statusCode = 400;
12
81
  responseBody;
13
82
  details;
14
- constructor(res) {
15
- const props = extractErrorProps(res);
83
+ constructor(res, context) {
84
+ const props = extractErrorProps(res, context);
16
85
  super(props.message), Object.assign(this, props);
17
86
  }
18
87
  }
@@ -26,7 +95,7 @@ class ServerError extends Error {
26
95
  super(props.message), Object.assign(this, props);
27
96
  }
28
97
  }
29
- function extractErrorProps(res) {
98
+ function extractErrorProps(res, context) {
30
99
  const body = res.body, props = {
31
100
  response: res,
32
101
  statusCode: res.statusCode,
@@ -34,34 +103,56 @@ function extractErrorProps(res) {
34
103
  message: "",
35
104
  details: void 0
36
105
  };
37
- if (body.error && body.message)
38
- return props.message = `${body.error} - ${body.message}`, props;
39
- if (isMutationError(body) || isActionError(body)) {
40
- const allItems = body.error.items || [], items = allItems.slice(0, 5).map((item) => item.error?.description).filter(Boolean);
106
+ if (!isRecord(body))
107
+ return props.message = httpErrorMessage(res, body), props;
108
+ const error = body.error;
109
+ if (typeof error == "string" && typeof body.message == "string")
110
+ return props.message = `${error} - ${body.message}`, props;
111
+ if (typeof error != "object" || error === null)
112
+ return typeof error == "string" ? props.message = error : typeof body.message == "string" ? props.message = body.message : props.message = httpErrorMessage(res, body), props;
113
+ if (isMutationError(error) || isActionError(error)) {
114
+ const allItems = error.items || [], items = allItems.slice(0, MAX_ITEMS_IN_ERROR_MESSAGE).map((item) => item.error?.description).filter(Boolean);
41
115
  let itemsStr = items.length ? `:
42
116
  - ${items.join(`
43
117
  - `)}` : "";
44
- return allItems.length > 5 && (itemsStr += `
45
- ...and ${allItems.length - 5} more`), props.message = `${body.error.description}${itemsStr}`, props.details = body.error, props;
118
+ return allItems.length > MAX_ITEMS_IN_ERROR_MESSAGE && (itemsStr += `
119
+ ...and ${allItems.length - MAX_ITEMS_IN_ERROR_MESSAGE} more`), props.message = `${error.description}${itemsStr}`, props.details = body.error, props;
120
+ }
121
+ if (isQueryParseError(error)) {
122
+ const tag = context?.options?.query?.tag;
123
+ return props.message = formatQueryParseError(error, tag), props.details = body.error, props;
46
124
  }
47
- return body.error && body.error.description ? (props.message = body.error.description, props.details = body.error, props) : (props.message = body.error || body.message || httpErrorMessage(res), props);
125
+ return "description" in error && typeof error.description == "string" ? (props.message = error.description, props.details = error, props) : (props.message = httpErrorMessage(res, body), props);
48
126
  }
49
- function isMutationError(body) {
50
- return isPlainObject(body) && isPlainObject(body.error) && body.error.type === "mutationError" && typeof body.error.description == "string";
127
+ function isMutationError(error) {
128
+ return "type" in error && error.type === "mutationError" && "description" in error && typeof error.description == "string";
51
129
  }
52
- function isActionError(body) {
53
- return isPlainObject(body) && isPlainObject(body.error) && body.error.type === "actionError" && typeof body.error.description == "string";
130
+ function isActionError(error) {
131
+ return "type" in error && error.type === "actionError" && "description" in error && typeof error.description == "string";
54
132
  }
55
- function isPlainObject(obj) {
56
- return typeof obj == "object" && obj !== null && !Array.isArray(obj);
133
+ function isQueryParseError(error) {
134
+ return isRecord(error) && error.type === "queryParseError" && typeof error.query == "string" && typeof error.start == "number" && typeof error.end == "number";
57
135
  }
58
- function httpErrorMessage(res) {
59
- const statusMessage = res.statusMessage ? ` ${res.statusMessage}` : "";
60
- return `${res.method}-request to ${res.url} resulted in HTTP ${res.statusCode}${statusMessage}`;
136
+ function formatQueryParseError(error, tag) {
137
+ const { query, start, end, description } = error;
138
+ if (!query || typeof start > "u")
139
+ return `GROQ query parse error: ${description}`;
140
+ const withTag = tag ? `
141
+
142
+ Tag: ${tag}` : "";
143
+ return `GROQ query parse error:
144
+ ${codeFrame(query, { start, end }, description)}${withTag}`;
145
+ }
146
+ function httpErrorMessage(res, body) {
147
+ const details = typeof body == "string" ? ` (${sliceWithEllipsis(body, 100)})` : "", statusMessage = res.statusMessage ? ` ${res.statusMessage}` : "";
148
+ return `${res.method}-request to ${res.url} resulted in HTTP ${res.statusCode}${statusMessage}${details}`;
61
149
  }
62
150
  function stringifyBody(body, res) {
63
151
  return (res.headers["content-type"] || "").toLowerCase().indexOf("application/json") !== -1 ? JSON.stringify(body, null, 2) : body;
64
152
  }
153
+ function sliceWithEllipsis(str, max) {
154
+ return str.length > max ? `${str.slice(0, max)}\u2026` : str;
155
+ }
65
156
  class CorsOriginError extends Error {
66
157
  projectId;
67
158
  addOriginUrl;
@@ -76,11 +167,11 @@ class CorsOriginError extends Error {
76
167
  }
77
168
  }
78
169
  const httpError = {
79
- onResponse: (res) => {
170
+ onResponse: (res, context) => {
80
171
  if (res.statusCode >= 500)
81
172
  throw new ServerError(res);
82
173
  if (res.statusCode >= 400)
83
- throw new ClientError(res);
174
+ throw new ClientError(res, context);
84
175
  return res;
85
176
  }
86
177
  };
@@ -341,7 +432,8 @@ function connectWithESInstance(es, events) {
341
432
  return;
342
433
  }
343
434
  if (message.type === "channelError") {
344
- observer.error(new ChannelError(extractErrorMessage(event?.data), event.data));
435
+ const tag = new URL(es.url).searchParams.get("tag");
436
+ observer.error(new ChannelError(extractErrorMessage(event?.data, tag), event.data));
345
437
  return;
346
438
  }
347
439
  if (message.type === "disconnect") {
@@ -380,8 +472,9 @@ function parseEvent(message) {
380
472
  return [err, null];
381
473
  }
382
474
  }
383
- function extractErrorMessage(err) {
384
- return err.error ? err.error.description ? err.error.description : typeof err.error == "string" ? err.error : JSON.stringify(err.error, null, 2) : err.message || "Unknown listener error";
475
+ function extractErrorMessage(err, tag) {
476
+ const error = err.error;
477
+ return error ? isQueryParseError(error) ? formatQueryParseError(error, tag) : error.description ? error.description : typeof error == "string" ? error : JSON.stringify(error, null, 2) : err.message || "Unknown listener error";
385
478
  }
386
479
  function isEmptyObject(data) {
387
480
  for (const _ in data)
@@ -1044,6 +1137,22 @@ function _generate(client, httpRequest, request) {
1044
1137
  body: request
1045
1138
  });
1046
1139
  }
1140
+ function _patch(client, httpRequest, request) {
1141
+ const dataset2 = hasDataset(client.config());
1142
+ return _request(client, httpRequest, {
1143
+ method: "POST",
1144
+ uri: `/agent/action/patch/${dataset2}`,
1145
+ body: request
1146
+ });
1147
+ }
1148
+ function _prompt(client, httpRequest, request) {
1149
+ const dataset2 = hasDataset(client.config());
1150
+ return _request(client, httpRequest, {
1151
+ method: "POST",
1152
+ uri: `/agent/action/prompt/${dataset2}`,
1153
+ body: request
1154
+ });
1155
+ }
1047
1156
  function _transform(client, httpRequest, request) {
1048
1157
  const dataset2 = hasDataset(client.config());
1049
1158
  return _request(client, httpRequest, {
@@ -1115,6 +1224,21 @@ class AgentActionsClient {
1115
1224
  translate(request) {
1116
1225
  return lastValueFrom(_translate(this.#client, this.#httpRequest, request));
1117
1226
  }
1227
+ /**
1228
+ * Run a raw instruction and return the result either as text or json
1229
+ * @param request - prompt request
1230
+ */
1231
+ prompt(request) {
1232
+ return lastValueFrom(_prompt(this.#client, this.#httpRequest, request));
1233
+ }
1234
+ /**
1235
+ * Patch a document using a schema aware API.
1236
+ * Does not use an LLM, but uses the schema to ensure paths and values matches the schema.
1237
+ * @param request - instruction request
1238
+ */
1239
+ patch(request) {
1240
+ return lastValueFrom(_patch(this.#client, this.#httpRequest, request));
1241
+ }
1118
1242
  }
1119
1243
  class ObservableAssetsClient {
1120
1244
  #client;
@@ -1221,13 +1345,11 @@ const MAX_URL_LENGTH = 14800, possibleOptions = [
1221
1345
  includeResult: !0
1222
1346
  };
1223
1347
  function _listen(query, params, opts = {}) {
1224
- const { url, token, withCredentials, requestTagPrefix } = this.config(), tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join(".") : opts.tag, options = { ...defaults(opts, defaultOptions), tag }, listenOpts = pick(options, possibleOptions), qs = encodeQueryString({ query, params, options: { tag, ...listenOpts } }), uri = `${url}${_getDataUrl(this, "listen", qs)}`;
1348
+ const { url, token, withCredentials, requestTagPrefix, headers: configHeaders } = this.config(), tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join(".") : opts.tag, options = { ...defaults(opts, defaultOptions), tag }, listenOpts = pick(options, possibleOptions), qs = encodeQueryString({ query, params, options: { tag, ...listenOpts } }), uri = `${url}${_getDataUrl(this, "listen", qs)}`;
1225
1349
  if (uri.length > MAX_URL_LENGTH)
1226
1350
  return throwError(() => new Error("Query too large for listener"));
1227
1351
  const listenFor = options.events ? options.events : ["mutation"], esOptions = {};
1228
- return withCredentials && (esOptions.withCredentials = !0), token && (esOptions.headers = {
1229
- Authorization: `Bearer ${token}`
1230
- }), connectEventSource(() => (
1352
+ return withCredentials && (esOptions.withCredentials = !0), (token || configHeaders) && (esOptions.headers = {}, token && (esOptions.headers.Authorization = `Bearer ${token}`), configHeaders && Object.assign(esOptions.headers, configHeaders)), connectEventSource(() => (
1231
1353
  // use polyfill if there is no global EventSource or if we need to set headers
1232
1354
  (typeof EventSource > "u" || esOptions.headers ? eventSourcePolyfill : of(EventSource)).pipe(map((EventSource2) => new EventSource2(uri, esOptions)))
1233
1355
  ), listenFor).pipe(
@@ -1285,7 +1407,8 @@ class LiveClient {
1285
1407
  apiVersion: _apiVersion,
1286
1408
  token,
1287
1409
  withCredentials,
1288
- requestTagPrefix
1410
+ requestTagPrefix,
1411
+ headers: configHeaders
1289
1412
  } = this.#client.config(), apiVersion = _apiVersion.replace(/^v/, "");
1290
1413
  if (apiVersion !== "X" && apiVersion < requiredApiVersion)
1291
1414
  throw new Error(
@@ -1298,9 +1421,7 @@ class LiveClient {
1298
1421
  const path = _getDataUrl(this.#client, "live/events"), url = new URL(this.#client.getUrl(path, !1)), tag = _tag && requestTagPrefix ? [requestTagPrefix, _tag].join(".") : _tag;
1299
1422
  tag && url.searchParams.set("tag", tag), includeDrafts && url.searchParams.set("includeDrafts", "true");
1300
1423
  const esOptions = {};
1301
- includeDrafts && token && (esOptions.headers = {
1302
- Authorization: `Bearer ${token}`
1303
- }), includeDrafts && withCredentials && (esOptions.withCredentials = !0);
1424
+ includeDrafts && withCredentials && (esOptions.withCredentials = !0), (includeDrafts && token || configHeaders) && (esOptions.headers = {}, includeDrafts && token && (esOptions.headers.Authorization = `Bearer ${token}`), configHeaders && Object.assign(esOptions.headers, configHeaders));
1304
1425
  const key = `${url.href}::${JSON.stringify(esOptions)}`, existing = eventsCache.get(key);
1305
1426
  if (existing)
1306
1427
  return existing;
@@ -2579,6 +2700,8 @@ export {
2579
2700
  connectEventSource,
2580
2701
  createClient,
2581
2702
  deprecatedCreateClient as default,
2703
+ formatQueryParseError,
2704
+ isQueryParseError,
2582
2705
  requester,
2583
2706
  adapter as unstable__adapter,
2584
2707
  environment as unstable__environment,