@relyio/sdk 0.6.0 → 0.7.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 (37) hide show
  1. package/CHANGELOG.md +370 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-DY2XT7OF.cjs → chunk-72UK5U7T.cjs} +70 -60
  4. package/dist/{chunk-7ABNXVWL.js → chunk-GYHAVYND.js} +777 -399
  5. package/dist/{chunk-I3ESNANB.js → chunk-H6IBQSMM.js} +2 -2
  6. package/dist/{chunk-HT6NFRM2.cjs → chunk-TZL374LS.cjs} +2 -2
  7. package/dist/{chunk-GCMQUM6N.cjs → chunk-VH2DE7HZ.cjs} +776 -402
  8. package/dist/{chunk-XJVY2CLY.js → chunk-YEJUMW4X.js} +70 -60
  9. package/dist/client/index.cjs +4 -3
  10. package/dist/client/index.d.cts +4 -4
  11. package/dist/client/index.d.ts +4 -4
  12. package/dist/client/index.js +2 -1
  13. package/dist/{index-d1Kz1e19.d.cts → define-content-type-DiVpbwNs.d.cts} +1615 -684
  14. package/dist/{index-yPbhZc6q.d.ts → define-content-type-DiVpbwNs.d.ts} +1615 -684
  15. package/dist/{define-schema-1kr2HIzN.d.cts → define-schema-C-5an28C.d.ts} +189 -85
  16. package/dist/{define-schema-ChvAzY8H.d.ts → define-schema-D7MButVt.d.cts} +189 -85
  17. package/dist/{index-XqoGUaAY.d.ts → index-1G97sNA8.d.ts} +489 -267
  18. package/dist/index-BOQIHnsh.d.ts +818 -0
  19. package/dist/index-DbsTUw3Q.d.cts +818 -0
  20. package/dist/{index-Df1VsfJR.d.cts → index-M0X45k7J.d.cts} +489 -267
  21. package/dist/index.cjs +98 -114
  22. package/dist/index.d.cts +31 -31
  23. package/dist/index.d.ts +31 -31
  24. package/dist/index.js +8 -8
  25. package/dist/schema/index.cjs +35 -35
  26. package/dist/schema/index.d.cts +13 -11
  27. package/dist/schema/index.d.ts +13 -11
  28. package/dist/schema/index.js +1 -1
  29. package/dist/types/index.d.cts +2 -2
  30. package/dist/types/index.d.ts +2 -2
  31. package/dist/utils/index.cjs +19 -19
  32. package/dist/utils/index.d.cts +10 -1
  33. package/dist/utils/index.d.ts +10 -1
  34. package/dist/utils/index.js +1 -1
  35. package/package.json +4 -3
  36. package/dist/define-content-type-CDB3kyeA.d.cts +0 -1173
  37. package/dist/define-content-type-CDB3kyeA.d.ts +0 -1173
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkLSRPMNPT_cjs = require('./chunk-LSRPMNPT.cjs');
4
+ var chunkTZL374LS_cjs = require('./chunk-TZL374LS.cjs');
4
5
  var chunkMWMSFIWN_cjs = require('./chunk-MWMSFIWN.cjs');
5
6
 
6
7
  /* RelyIO SDK - Built with ❤️ by the RelyIO Team */
@@ -232,18 +233,6 @@ chunkMWMSFIWN_cjs.__name(_UnknownContractError, "UnknownContractError");
232
233
  var UnknownContractError = _UnknownContractError;
233
234
 
234
235
  // src/errors/auth-errors.ts
235
- var _AuthenticationError = class _AuthenticationError extends SDKError {
236
- constructor(message = "Authentication failed", statusCode = 401, cause, context) {
237
- super(message, statusCode, cause, context);
238
- chunkMWMSFIWN_cjs.__publicField(this, "code", "AUTHENTICATION_ERROR");
239
- chunkMWMSFIWN_cjs.__publicField(this, "retryable", false);
240
- }
241
- getUserMessage() {
242
- return "Authentication failed. Please check your API key and try again.";
243
- }
244
- };
245
- chunkMWMSFIWN_cjs.__name(_AuthenticationError, "AuthenticationError");
246
- var AuthenticationError = _AuthenticationError;
247
236
  var _AuthorizationError = class _AuthorizationError extends SDKError {
248
237
  constructor(message = "Authorization failed", statusCode = 403, cause, context) {
249
238
  super(message, statusCode, cause, context);
@@ -422,58 +411,6 @@ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationErro
422
411
  };
423
412
  chunkMWMSFIWN_cjs.__name(_InvalidPayloadError, "InvalidPayloadError");
424
413
  var InvalidPayloadError = _InvalidPayloadError;
425
- var _SchemaValidationError = class _SchemaValidationError extends BaseValidationError {
426
- constructor(message = "Schema validation failed", violations = [], cause) {
427
- super(message, violations, 400, cause);
428
- chunkMWMSFIWN_cjs.__publicField(this, "code", "SCHEMA_VALIDATION_ERROR");
429
- }
430
- getUserMessage() {
431
- return "The data does not match the expected schema. Please check your content structure.";
432
- }
433
- };
434
- chunkMWMSFIWN_cjs.__name(_SchemaValidationError, "SchemaValidationError");
435
- var SchemaValidationError = _SchemaValidationError;
436
- var _RequiredFieldError = class _RequiredFieldError extends BaseValidationError {
437
- constructor(fieldName, message, cause) {
438
- const violation = {
439
- field: fieldName,
440
- message: message ?? `Field "${fieldName}" is required`,
441
- code: "REQUIRED"
442
- };
443
- super(`Required field "${fieldName}" is missing`, [violation], 400, cause);
444
- chunkMWMSFIWN_cjs.__publicField(this, "code", "REQUIRED_FIELD_ERROR");
445
- }
446
- getUserMessage() {
447
- const violation = this.violations[0];
448
- const fieldName = violation?.field;
449
- return `The field "${fieldName}" is required and cannot be empty.`;
450
- }
451
- };
452
- chunkMWMSFIWN_cjs.__name(_RequiredFieldError, "RequiredFieldError");
453
- var RequiredFieldError = _RequiredFieldError;
454
- var _InvalidFieldTypeError = class _InvalidFieldTypeError extends BaseValidationError {
455
- constructor(fieldName, expectedType, actualType, value, cause) {
456
- const violation = {
457
- field: fieldName,
458
- message: `Expected ${expectedType}, got ${actualType}`,
459
- code: "INVALID_TYPE",
460
- value
461
- };
462
- super(
463
- `Invalid type for field "${fieldName}": expected ${expectedType}, got ${actualType}`,
464
- [violation],
465
- 400,
466
- cause
467
- );
468
- chunkMWMSFIWN_cjs.__publicField(this, "code", "INVALID_FIELD_TYPE");
469
- }
470
- getUserMessage() {
471
- const violation = this.violations[0];
472
- return `The field "${violation?.field}" has an invalid type. ${violation?.message}.`;
473
- }
474
- };
475
- chunkMWMSFIWN_cjs.__name(_InvalidFieldTypeError, "InvalidFieldTypeError");
476
- var InvalidFieldTypeError = _InvalidFieldTypeError;
477
414
 
478
415
  // ../../platform/api-contract/dist/index.js
479
416
  var HEADER_RETRY_AFTER = { name: "Retry-After" };
@@ -873,6 +810,20 @@ function isAborted(signal) {
873
810
  }
874
811
  chunkMWMSFIWN_cjs.__name(isAborted, "isAborted");
875
812
 
813
+ // src/http/request-timeout.ts
814
+ var MAX_TIMER_DELAY_MS = 2147483647;
815
+ function isTimerDelay(value) {
816
+ return typeof value === "number" && value >= 1 && value <= MAX_TIMER_DELAY_MS;
817
+ }
818
+ chunkMWMSFIWN_cjs.__name(isTimerDelay, "isTimerDelay");
819
+ function assertRequestTimeout(timeout) {
820
+ if (isTimerDelay(timeout)) return;
821
+ throw new Error(
822
+ `timeout must be a number of milliseconds from 1 to ${MAX_TIMER_DELAY_MS} \u2014 a timer given 0, NaN, Infinity or more fires at once and ends every request \u2014 and got ${String(timeout)}`
823
+ );
824
+ }
825
+ chunkMWMSFIWN_cjs.__name(assertRequestTimeout, "assertRequestTimeout");
826
+
876
827
  // src/errors/instructed-delay.ts
877
828
  function serviceInstructedDelayMs(error, nowMs) {
878
829
  if (error instanceof ServiceIndeterminateError) {
@@ -926,43 +877,31 @@ var DefaultRetryPolicy = _DefaultRetryPolicy;
926
877
  // src/http/http-client.ts
927
878
  var _HttpClient = class _HttpClient {
928
879
  constructor(config) {
929
- chunkMWMSFIWN_cjs.__publicField(this, "baseUrl");
930
- chunkMWMSFIWN_cjs.__publicField(this, "defaultHeaders");
931
- chunkMWMSFIWN_cjs.__publicField(this, "timeout");
932
- chunkMWMSFIWN_cjs.__publicField(this, "retryPolicy");
933
- chunkMWMSFIWN_cjs.__publicField(this, "debug");
934
- chunkMWMSFIWN_cjs.__publicField(this, "logger");
935
- chunkMWMSFIWN_cjs.__publicField(this, "config");
936
- this.config = config;
937
- this.baseUrl = config.baseUrl;
938
- this.timeout = config.timeout;
939
- this.debug = config.debug.enabled ?? false;
940
- this.logger = config.debug.logger;
941
- const apiKey = presentKey(config.apiKey);
942
- this.defaultHeaders = {
943
- "Content-Type": "application/json",
944
- ...apiKey === void 0 ? {} : { [API_KEY_HEADER]: apiKey },
945
- ...config.headers
946
- };
947
- if (config.dataset != null) {
948
- this.defaultHeaders["X-RelyIO-Dataset"] = config.dataset;
949
- }
950
- if (typeof window === "undefined") {
951
- const globalWithVersion = globalThis;
952
- this.defaultHeaders["User-Agent"] = `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`;
953
- }
954
- this.retryPolicy = new DefaultRetryPolicy({
955
- maxAttempts: config.retryAttempts,
956
- baseDelay: 1e3,
957
- maxDelay: 1e4,
958
- backoffFactor: 2,
959
- jitter: true
960
- });
880
+ /** What every request reads off the configuration, derived by {@link configure} and nowhere else. */
881
+ chunkMWMSFIWN_cjs.__publicField(this, "connection");
882
+ this.connection = connectionFor(config);
883
+ this.announce();
884
+ }
885
+ /**
886
+ * Run on `config` from now on: every later request — whoever holds this client — is sent to its
887
+ * `baseUrl`, with its headers, key and dataset, its timeout and retries, through its `fetch`, and
888
+ * logged by its `debug` options.
889
+ *
890
+ * The client's own `updateConfig()` calls this rather than building a second client, so a
891
+ * `content()` or other sub-client taken before the update sends through the update too. Anything
892
+ * set on this client since it was last configured — `setDefaultHeaders()`, `setBaseUrl()` — is
893
+ * replaced by what `config` says.
894
+ */
895
+ configure(config) {
896
+ this.connection = connectionFor(config);
897
+ this.announce();
898
+ }
899
+ announce() {
961
900
  this.log("debug", "HttpClient initialized", {
962
- baseUrl: this.baseUrl,
963
- timeout: this.timeout,
964
- retryAttempts: config.retryAttempts,
965
- environment: typeof window === "undefined" ? "node" : "browser"
901
+ baseUrl: this.connection.baseUrl,
902
+ timeout: this.connection.timeout,
903
+ retryAttempts: this.connection.config.retryAttempts,
904
+ environment: chunkTZL374LS_cjs.isBrowser() ? "browser" : "node"
966
905
  });
967
906
  }
968
907
  /**
@@ -999,19 +938,24 @@ var _HttpClient = class _HttpClient {
999
938
  *
1000
939
  * The loop always makes one attempt. The incumbent's `while (attempt <
1001
940
  * maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
1002
- * accepts — and then dereferenced an unassigned `lastError`.
941
+ * then accepted, and now refuses — and then dereferenced an unassigned
942
+ * `lastError`. `retryAttempts` is the most attempts, the first included; an
943
+ * `HttpClient` constructed directly is not validated, so the first attempt
944
+ * stays unconditional.
1003
945
  *
1004
946
  * A request that would carry no `X-API-Key` makes none: it rejects with
1005
947
  * `MissingApiKeyError` before `fetch` is called, is not retried, and names
1006
948
  * `apiKey`. This is where a client built without a key learns it — the
1007
949
  * constructor accepts one so that a module-scope client can be evaluated by a
1008
- * build that holds no key (REL-1120).
950
+ * build that holds no key (REL-1120) — and so does one whose `setApiKey` was
951
+ * given none.
1009
952
  */
1010
953
  async request(config) {
954
+ if (config.timeout !== void 0) assertRequestTimeout(config.timeout);
1011
955
  const mergedConfig = this.mergeRequestConfig(config);
1012
956
  if (presentKey(headerValue(mergedConfig.headers, API_KEY_HEADER)) === void 0) {
1013
957
  throw new MissingApiKeyError(
1014
- "`apiKey` is missing: this client was created without an API key, so the request was not sent. Pass `apiKey` to createClient \u2014 the documented setup reads it from RELYIO_API_KEY.",
958
+ "`apiKey` is missing: this client holds no API key, so the request was not sent. Pass `apiKey` to createClient \u2014 the documented setup reads it from RELYIO_API_KEY.",
1015
959
  { url: mergedConfig.url, method: mergedConfig.method, sent: false }
1016
960
  );
1017
961
  }
@@ -1021,7 +965,7 @@ var _HttpClient = class _HttpClient {
1021
965
  // Show the final URL with query params
1022
966
  });
1023
967
  if (config.method === "DELETE" && mergedConfig.headers) {
1024
- delete mergedConfig.headers["Content-Type"];
968
+ mergedConfig.headers = layerHeaders(mergedConfig.headers, { "Content-Type": null });
1025
969
  }
1026
970
  for (let attempt = 1; ; attempt++) {
1027
971
  try {
@@ -1040,8 +984,8 @@ var _HttpClient = class _HttpClient {
1040
984
  attempt,
1041
985
  url: mergedConfig.url
1042
986
  });
1043
- if (this.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
1044
- const delay = this.retryPolicy.delayFor(attempt, failure);
987
+ if (this.connection.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
988
+ const delay = this.connection.retryPolicy.delayFor(attempt, failure);
1045
989
  this.log("debug", "Retrying request", { attempt, delay });
1046
990
  await sleep(delay, config.signal);
1047
991
  continue;
@@ -1113,34 +1057,60 @@ var _HttpClient = class _HttpClient {
1113
1057
  });
1114
1058
  }
1115
1059
  /**
1116
- * Set default headers for all requests
1060
+ * Add headers to every later request, each replacing any header of the same name — the name
1061
+ * matched without regard to case — until the client is next configured.
1117
1062
  */
1118
1063
  setDefaultHeaders(headers) {
1119
- this.defaultHeaders = { ...this.defaultHeaders, ...headers };
1064
+ this.connection = {
1065
+ ...this.connection,
1066
+ defaultHeaders: layerHeaders(this.connection.defaultHeaders, headers)
1067
+ };
1120
1068
  }
1121
1069
  /**
1122
- * Set authentication token
1070
+ * Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
1071
+ * reports.
1072
+ *
1073
+ * The key is read the way construction reads it (`presentKey`): an absent, empty or blank key is
1074
+ * no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
1075
+ * before anything is sent. A key header of any other spelling — one given in `headers` — goes
1076
+ * too, from the headers sent and from the headers the configuration reports, so the old key is
1077
+ * never sent beside the new one.
1078
+ *
1079
+ * The configuration is the one the owning `TypedRelyIOClient` holds (it hands its own to the
1080
+ * constructor), so its `getConfig().apiKey` — what a surface reads to decide a key's kind — is the
1081
+ * key sent from here on.
1082
+ *
1083
+ * This replaced `setAuthToken`, which added `Authorization: Bearer` beside an `X-API-Key` it
1084
+ * never touched: the API reads `X-API-Key` first, so the old key was the one used (REL-1385).
1123
1085
  */
1124
- setAuthToken(token) {
1125
- this.defaultHeaders.Authorization = `Bearer ${token}`;
1086
+ setApiKey(apiKey) {
1087
+ const { config } = this.connection;
1088
+ config.apiKey = apiKey;
1089
+ config.headers = layerHeaders(config.headers, { [API_KEY_HEADER]: null });
1090
+ this.connection = {
1091
+ ...this.connection,
1092
+ defaultHeaders: layerHeaders(this.connection.defaultHeaders, {
1093
+ [API_KEY_HEADER]: presentKey(apiKey) ?? null
1094
+ })
1095
+ };
1126
1096
  }
1127
1097
  /**
1128
1098
  * Get current default headers
1129
1099
  */
1130
1100
  getDefaultHeaders() {
1131
- return { ...this.defaultHeaders };
1101
+ return { ...this.connection.defaultHeaders };
1132
1102
  }
1133
1103
  /**
1134
1104
  * Update base URL
1135
1105
  */
1136
1106
  setBaseUrl(baseUrl) {
1137
- this.baseUrl = baseUrl;
1107
+ this.connection = { ...this.connection, baseUrl };
1138
1108
  }
1139
1109
  /**
1140
1110
  * Get current base URL
1141
1111
  */
1142
1112
  getBaseUrl() {
1143
- return this.baseUrl;
1113
+ return this.connection.baseUrl;
1144
1114
  }
1145
1115
  /**
1146
1116
  * One attempt.
@@ -1162,7 +1132,7 @@ var _HttpClient = class _HttpClient {
1162
1132
  const timeoutId = setTimeout(() => {
1163
1133
  timedOut = true;
1164
1134
  controller.abort();
1165
- }, config.timeout ?? this.timeout);
1135
+ }, config.timeout ?? this.connection.timeout);
1166
1136
  const onCallerAbort = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => controller.abort(), "onCallerAbort");
1167
1137
  caller?.addEventListener("abort", onCallerAbort, { once: true });
1168
1138
  try {
@@ -1172,14 +1142,15 @@ var _HttpClient = class _HttpClient {
1172
1142
  headers: filteredHeaders,
1173
1143
  body: this.prepareRequestBody(config),
1174
1144
  signal: controller.signal,
1175
- // Only where `window` exists. A server or edge runtime has no cookie jar for the mode to
1176
- // govern, so the field is left off and the runtime's default stands. A Web Worker gets
1177
- // that default too: it has cookies but no `window`.
1178
- ...typeof window !== "undefined" && {
1179
- credentials: credentialsModeFor(this.config.browser.includeCredentials)
1145
+ // Only in a browser — a `window` with a `document` (`isBrowser()`). A server or edge
1146
+ // runtime has no cookie jar for the mode to govern, so the field is left off and the
1147
+ // runtime's default stands; that includes Deno 1.x, whose global is a `window` with no
1148
+ // `document`. A Web Worker gets that default too: it has cookies but no `window`.
1149
+ ...chunkTZL374LS_cjs.isBrowser() && {
1150
+ credentials: credentialsModeFor(this.connection.config.browser.includeCredentials)
1180
1151
  }
1181
1152
  };
1182
- const send = this.config.fetch ?? globalThis.fetch;
1153
+ const send = this.connection.config.fetch ?? globalThis.fetch;
1183
1154
  const response = await send(url, requestInit);
1184
1155
  clearTimeout(timeoutId);
1185
1156
  const responseBody = await this.parseResponse(response);
@@ -1212,10 +1183,8 @@ var _HttpClient = class _HttpClient {
1212
1183
  }
1213
1184
  if (error instanceof DOMException && error.name === "AbortError") {
1214
1185
  if (!timedOut && isAborted(caller)) throw error;
1215
- throw new TimeoutError(
1216
- `Request timed out after ${config.timeout ?? this.timeout}ms`,
1217
- config.timeout ?? this.timeout
1218
- );
1186
+ const timeout = config.timeout ?? this.connection.timeout;
1187
+ throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
1219
1188
  }
1220
1189
  if (error instanceof TypeError && error.message.includes("CORS")) {
1221
1190
  const corsError = new NetworkError(
@@ -1229,9 +1198,10 @@ var _HttpClient = class _HttpClient {
1229
1198
  suggestion: "Check if the API server allows requests from your domain and has proper CORS headers configured."
1230
1199
  }
1231
1200
  );
1232
- if (typeof window !== "undefined" && this.config.browser.onCorsError) {
1201
+ const { onCorsError } = this.connection.config.browser;
1202
+ if (chunkTZL374LS_cjs.isBrowser() && onCorsError) {
1233
1203
  try {
1234
- this.config.browser.onCorsError(corsError, {
1204
+ onCorsError(corsError, {
1235
1205
  url: config.url,
1236
1206
  method: config.method,
1237
1207
  originalError: error
@@ -1248,20 +1218,20 @@ var _HttpClient = class _HttpClient {
1248
1218
  }
1249
1219
  }
1250
1220
  /**
1251
- * Filter headers that browsers don't allow to be set manually
1221
+ * The headers without those a browser controls itself, when this is a browser; unchanged when it
1222
+ * is not.
1223
+ *
1224
+ * A name is matched without regard to case (RFC 9110 §5.1), because a browser refuses `Origin`
1225
+ * whatever case a page spells it in. This matched only the all-lowercase and all-uppercase
1226
+ * spellings, so `Origin` and `User-Agent` — how people write them — reached `fetch` (REL-1409).
1252
1227
  */
1253
1228
  filterHeadersForBrowser(headers) {
1254
- if (typeof window !== "undefined") {
1255
- const filteredHeaders = { ...headers };
1256
- const forbiddenHeaders = ["user-agent", "referer", "origin", "host", "connection", "upgrade"];
1257
- forbiddenHeaders.forEach((header) => {
1258
- delete filteredHeaders[header];
1259
- delete filteredHeaders[header.toLowerCase()];
1260
- delete filteredHeaders[header.toUpperCase()];
1261
- });
1262
- return filteredHeaders;
1263
- }
1264
- return headers;
1229
+ if (!chunkTZL374LS_cjs.isBrowser()) return headers;
1230
+ return Object.fromEntries(
1231
+ Object.entries(headers).filter(
1232
+ ([name]) => !BROWSER_CONTROLLED_HEADERS.has(name.toLowerCase())
1233
+ )
1234
+ );
1265
1235
  }
1266
1236
  /**
1267
1237
  * Prepare request body based on content type and environment
@@ -1297,7 +1267,7 @@ var _HttpClient = class _HttpClient {
1297
1267
  if (url.startsWith("http://") || url.startsWith("https://")) {
1298
1268
  return url;
1299
1269
  }
1300
- return `${this.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
1270
+ return `${this.connection.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
1301
1271
  }
1302
1272
  mergeRequestConfig(config) {
1303
1273
  const url = this.resolveUrl(config.url);
@@ -1306,11 +1276,11 @@ var _HttpClient = class _HttpClient {
1306
1276
  return {
1307
1277
  ...config,
1308
1278
  url: finalUrl,
1309
- headers: {
1310
- ...this.defaultHeaders,
1311
- ...config.headers
1312
- },
1313
- timeout: config.timeout ?? this.timeout
1279
+ // The request's own headers replace the client's of the same name, whatever the case: a
1280
+ // per-request `x-relyio-dataset` sent beside the client's `X-RelyIO-Dataset` is one header
1281
+ // `Headers` joins into `main, staging`.
1282
+ headers: layerHeaders(this.connection.defaultHeaders, config.headers),
1283
+ timeout: config.timeout ?? this.connection.timeout
1314
1284
  };
1315
1285
  }
1316
1286
  buildQueryString(params) {
@@ -1334,9 +1304,10 @@ var _HttpClient = class _HttpClient {
1334
1304
  return obj;
1335
1305
  }
1336
1306
  log(level, message, data) {
1337
- if (!this.debug) return;
1338
- if (this.logger != null) {
1339
- this.logger(level, message, data);
1307
+ const { debug } = this.connection.config;
1308
+ if (!debug.enabled) return;
1309
+ if (debug.logger != null) {
1310
+ debug.logger(level, message, data);
1340
1311
  } else {
1341
1312
  console.log(`[RelyIO SDK ${level.toUpperCase()}] ${message}`, data ?? "");
1342
1313
  }
@@ -1345,29 +1316,104 @@ var _HttpClient = class _HttpClient {
1345
1316
  chunkMWMSFIWN_cjs.__name(_HttpClient, "HttpClient");
1346
1317
  var HttpClient = _HttpClient;
1347
1318
  var API_KEY_HEADER = "X-API-Key";
1319
+ var DATASET_HEADER = "X-RelyIO-Dataset";
1320
+ var BROWSER_CONTROLLED_HEADERS = /* @__PURE__ */ new Set([
1321
+ "user-agent",
1322
+ "referer",
1323
+ "origin",
1324
+ "host",
1325
+ "connection",
1326
+ "upgrade"
1327
+ ]);
1328
+ function connectionFor(config) {
1329
+ const globalWithVersion = globalThis;
1330
+ const defaultHeaders = layerHeaders(
1331
+ layerHeaders({ "Content-Type": "application/json" }, config.headers),
1332
+ {
1333
+ [API_KEY_HEADER]: presentKey(config.apiKey),
1334
+ [DATASET_HEADER]: config.dataset,
1335
+ // Only outside a browser, which controls this header. "A browser" is the core's one
1336
+ // definition, `isBrowser()` — every environment question in this file asks it.
1337
+ "User-Agent": chunkTZL374LS_cjs.isBrowser() ? void 0 : `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`
1338
+ }
1339
+ );
1340
+ return {
1341
+ config,
1342
+ baseUrl: config.baseUrl,
1343
+ defaultHeaders,
1344
+ timeout: config.timeout,
1345
+ // The policy, not a predicate over `(error, attempt)`: whether a request may be sent again is a
1346
+ // property of the **route** as much as of the refusal, and a callback that never sees the
1347
+ // request cannot express that.
1348
+ retryPolicy: new DefaultRetryPolicy({
1349
+ maxAttempts: config.retryAttempts,
1350
+ baseDelay: 1e3,
1351
+ maxDelay: 1e4,
1352
+ backoffFactor: 2,
1353
+ jitter: true
1354
+ })
1355
+ };
1356
+ }
1357
+ chunkMWMSFIWN_cjs.__name(connectionFor, "connectionFor");
1358
+ function layerHeaders(base, over) {
1359
+ const layered = { ...base };
1360
+ for (const [name, value] of Object.entries(over ?? {})) {
1361
+ if (value === void 0) continue;
1362
+ const lower = name.toLowerCase();
1363
+ for (const existing of Object.keys(layered)) {
1364
+ if (existing.toLowerCase() === lower) delete layered[existing];
1365
+ }
1366
+ if (value !== null) layered[name] = value;
1367
+ }
1368
+ return layered;
1369
+ }
1370
+ chunkMWMSFIWN_cjs.__name(layerHeaders, "layerHeaders");
1348
1371
  function presentKey(value) {
1349
1372
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
1350
1373
  }
1351
1374
  chunkMWMSFIWN_cjs.__name(presentKey, "presentKey");
1352
1375
  function credentialsModeFor(includeCredentials) {
1353
- switch (includeCredentials) {
1354
- case false: {
1355
- return "same-origin";
1356
- }
1357
- case true:
1358
- case void 0: {
1359
- return "include";
1360
- }
1361
- }
1376
+ return includeCredentials ? "include" : "same-origin";
1362
1377
  }
1363
1378
  chunkMWMSFIWN_cjs.__name(credentialsModeFor, "credentialsModeFor");
1364
1379
 
1380
+ // src/content/client-locale.ts
1381
+ function callLocale(named, clientLocale) {
1382
+ if (named !== void 0) return named;
1383
+ return clientLocale === void 0 || clientLocale === "" ? void 0 : clientLocale;
1384
+ }
1385
+ chunkMWMSFIWN_cjs.__name(callLocale, "callLocale");
1386
+ function readClientLocale(locale) {
1387
+ return typeof locale === "function" ? locale : () => locale;
1388
+ }
1389
+ chunkMWMSFIWN_cjs.__name(readClientLocale, "readClientLocale");
1390
+
1365
1391
  // src/content/query-builder.ts
1392
+ function namesMetadata(key) {
1393
+ return key === "_metadata" || key.startsWith("_metadata.");
1394
+ }
1395
+ chunkMWMSFIWN_cjs.__name(namesMetadata, "namesMetadata");
1396
+ function refuseMetadataConditions(conditions) {
1397
+ const named = Object.keys(conditions).filter(namesMetadata);
1398
+ if (named.length === 0) return;
1399
+ throw new ValidationError(
1400
+ `A condition cannot name ${named.join(", ")}: the API filters on the fields the content type declares, and reports _metadata beside them. Filter on a field, and read _metadata from the result.`,
1401
+ named.map((field) => ({
1402
+ field,
1403
+ code: "METADATA_CONDITION",
1404
+ message: `${field} is not a field the API can filter on`
1405
+ }))
1406
+ );
1407
+ }
1408
+ chunkMWMSFIWN_cjs.__name(refuseMetadataConditions, "refuseMetadataConditions");
1366
1409
  var _ContentQueryBuilder = class _ContentQueryBuilder {
1367
- constructor(httpClient, contentType, defaultLocale) {
1410
+ /**
1411
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
1412
+ * query names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1413
+ */
1414
+ constructor(httpClient, contentType, locale) {
1368
1415
  this.httpClient = httpClient;
1369
1416
  this.contentType = contentType;
1370
- this.defaultLocale = defaultLocale;
1371
1417
  chunkMWMSFIWN_cjs.__publicField(this, "queryOptions", {});
1372
1418
  chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
1373
1419
  chunkMWMSFIWN_cjs.__publicField(this, "localesArray");
@@ -1377,6 +1423,9 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1377
1423
  chunkMWMSFIWN_cjs.__publicField(this, "pageNumber");
1378
1424
  chunkMWMSFIWN_cjs.__publicField(this, "pageSizeValue");
1379
1425
  chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
1426
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
1427
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
1428
+ this.clientLocale = readClientLocale(locale);
1380
1429
  }
1381
1430
  /**
1382
1431
  * Headers this query adds to the client's own, e.g. `X-RelyIO-Dataset` to list another dataset
@@ -1388,9 +1437,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1388
1437
  return this;
1389
1438
  }
1390
1439
  /**
1391
- * Add where conditions to the query
1440
+ * Add where conditions to the query: conditions on the fields the content type declares. A
1441
+ * condition on `_metadata` is refused here, before anything is sent (`refuseMetadataConditions`).
1392
1442
  */
1393
1443
  where(conditions) {
1444
+ refuseMetadataConditions(conditions);
1394
1445
  this.queryOptions.where = {
1395
1446
  ...this.queryOptions.where,
1396
1447
  ...conditions
@@ -1647,7 +1698,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1647
1698
  * Clone the query builder
1648
1699
  */
1649
1700
  clone() {
1650
- const cloned = new _ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1701
+ const cloned = new _ContentQueryBuilder(
1702
+ this.httpClient,
1703
+ this.contentType,
1704
+ this.clientLocale
1705
+ );
1651
1706
  cloned.queryOptions = JSON.parse(JSON.stringify(this.queryOptions));
1652
1707
  cloned.localeValue = this.localeValue;
1653
1708
  cloned.localesArray = this.localesArray ? [...this.localesArray] : void 0;
@@ -1722,14 +1777,15 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1722
1777
  if (this.queryOptions.cursor !== void 0) {
1723
1778
  params.cursor = this.queryOptions.cursor;
1724
1779
  }
1780
+ const clientLocale = this.clientLocale();
1725
1781
  if (this.localeValue != null && this.localeValue !== "") {
1726
1782
  params.locale = this.localeValue;
1727
1783
  } else if (this.fetchAllLocales) {
1728
1784
  params.locale = "*";
1729
1785
  } else if (this.localesArray && this.localesArray.length > 0) {
1730
1786
  params.locales = this.localesArray.join(",");
1731
- } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1732
- params.locale = this.defaultLocale;
1787
+ } else if (clientLocale != null && clientLocale !== "") {
1788
+ params.locale = clientLocale;
1733
1789
  }
1734
1790
  if (this.pageNumber !== void 0) {
1735
1791
  params.page = this.pageNumber;
@@ -1753,17 +1809,23 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1753
1809
  chunkMWMSFIWN_cjs.__name(_ContentQueryBuilder, "ContentQueryBuilder");
1754
1810
  var ContentQueryBuilder = _ContentQueryBuilder;
1755
1811
  var _ContentByIdBuilder = class _ContentByIdBuilder {
1756
- constructor(httpClient, contentType, id, defaultLocale) {
1812
+ /**
1813
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
1814
+ * read names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1815
+ */
1816
+ constructor(httpClient, contentType, id, locale) {
1757
1817
  this.httpClient = httpClient;
1758
1818
  this.contentType = contentType;
1759
1819
  this.id = id;
1760
- this.defaultLocale = defaultLocale;
1761
1820
  chunkMWMSFIWN_cjs.__publicField(this, "includeRelations");
1762
1821
  chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
1763
1822
  chunkMWMSFIWN_cjs.__publicField(this, "localesArray");
1764
1823
  chunkMWMSFIWN_cjs.__publicField(this, "fetchAllLocales", false);
1765
1824
  chunkMWMSFIWN_cjs.__publicField(this, "childrenOptions");
1766
1825
  chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
1826
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
1827
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
1828
+ this.clientLocale = readClientLocale(locale);
1767
1829
  }
1768
1830
  /**
1769
1831
  * Include related content in the response
@@ -1833,14 +1895,15 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
1833
1895
  if (this.includeRelations != null) {
1834
1896
  params.include = this.includeRelations.join(",");
1835
1897
  }
1898
+ const clientLocale = this.clientLocale();
1836
1899
  if (this.localeValue != null && this.localeValue !== "") {
1837
1900
  params.locale = this.localeValue;
1838
1901
  } else if (this.fetchAllLocales) {
1839
1902
  params.locale = "*";
1840
1903
  } else if (this.localesArray && this.localesArray.length > 0) {
1841
1904
  params.locales = this.localesArray.join(",");
1842
- } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1843
- params.locale = this.defaultLocale;
1905
+ } else if (clientLocale != null && clientLocale !== "") {
1906
+ params.locale = clientLocale;
1844
1907
  }
1845
1908
  if (this.childrenOptions != null) {
1846
1909
  if (this.childrenOptions.contentTypes) {
@@ -1905,22 +1968,28 @@ chunkMWMSFIWN_cjs.__name(entityTagOf, "entityTagOf");
1905
1968
 
1906
1969
  // src/content/content-client.ts
1907
1970
  var _ContentClient = class _ContentClient {
1908
- constructor(httpClient, contentType, defaultLocale) {
1971
+ /**
1972
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
1973
+ * every call, or a locale fixed for this client
1974
+ */
1975
+ constructor(httpClient, contentType, locale) {
1909
1976
  this.httpClient = httpClient;
1910
1977
  this.contentType = contentType;
1911
- this.defaultLocale = defaultLocale;
1978
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
1979
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
1980
+ this.clientLocale = readClientLocale(locale);
1912
1981
  }
1913
1982
  /**
1914
1983
  * Create a new query builder for this content type
1915
1984
  */
1916
1985
  query() {
1917
- return new ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1986
+ return new ContentQueryBuilder(this.httpClient, this.contentType, this.clientLocale);
1918
1987
  }
1919
1988
  /**
1920
1989
  * Find content by ID with fluent options
1921
1990
  */
1922
1991
  findById(id) {
1923
- return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.defaultLocale);
1992
+ return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.clientLocale);
1924
1993
  }
1925
1994
  /**
1926
1995
  * Fetch all content items
@@ -2004,7 +2073,7 @@ var _ContentClient = class _ContentClient {
2004
2073
  async fetchOneWithTag(id, options) {
2005
2074
  const query = {};
2006
2075
  if (options?.include != null) query.include = options.include.join(",");
2007
- const locale = options?.locale ?? this.defaultLocale;
2076
+ const locale = options?.locale ?? this.clientLocale();
2008
2077
  if (locale != null && locale !== "") query.locale = locale;
2009
2078
  const response = await this.httpClient.send(
2010
2079
  "/v1/{contentType}/{id}",
@@ -2034,16 +2103,17 @@ var _ContentClient = class _ContentClient {
2034
2103
  * @param options - Create options (slug, locale, parentId, sortOrder), and `headers` this one
2035
2104
  * request adds — e.g. `{ 'X-RelyIO-Dataset': 'staging' }` to write a dataset other than the
2036
2105
  * client's. They are sent, never put in the body; `idempotencyKey` still wins over an
2037
- * `Idempotency-Key` among them.
2106
+ * `Idempotency-Key` among them. `locale` defaults to the client's own (`withLocale()`).
2038
2107
  */
2039
2108
  async create(data, options) {
2040
- const { idempotencyKey, headers, ...body } = options ?? {};
2109
+ const { idempotencyKey, headers, locale, ...body } = options ?? {};
2110
+ const sent = callLocale(locale, this.clientLocale());
2041
2111
  return this.httpClient.fetchPayload(
2042
2112
  "/v1/{contentType}",
2043
2113
  "post",
2044
2114
  {
2045
2115
  path: { contentType: this.contentType },
2046
- body: { content: data, ...body },
2116
+ body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
2047
2117
  headers: requestHeaders(headers, writeHeaders({ idempotencyKey }))
2048
2118
  }
2049
2119
  );
@@ -2054,16 +2124,18 @@ var _ContentClient = class _ContentClient {
2054
2124
  * @param data - Fields to update
2055
2125
  * @param options - Update options (slug, locale, parentId, sortOrder), and `headers` this one
2056
2126
  * request adds, as for {@link create}. `ifMatch` and `idempotencyKey` win over the same
2057
- * header among them.
2127
+ * header among them. `locale` defaults to the client's own, the locale whose entity tag
2128
+ * {@link fetchOneWithTag} reads, so the tag it hands back is checked against the same locale.
2058
2129
  */
2059
2130
  async update(id, data, options) {
2060
- const { idempotencyKey, ifMatch, headers, ...body } = options ?? {};
2131
+ const { idempotencyKey, ifMatch, headers, locale, ...body } = options ?? {};
2132
+ const sent = callLocale(locale, this.clientLocale());
2061
2133
  return this.httpClient.fetchPayload(
2062
2134
  "/v1/{contentType}/{id}",
2063
2135
  "patch",
2064
2136
  {
2065
2137
  path: { contentType: this.contentType, id },
2066
- body: { content: data, ...body },
2138
+ body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
2067
2139
  headers: requestHeaders(headers, writeHeaders({ idempotencyKey, ifMatch }))
2068
2140
  }
2069
2141
  );
@@ -2095,32 +2167,35 @@ var _ContentClient = class _ContentClient {
2095
2167
  * Get version history for one locale of an entry.
2096
2168
  *
2097
2169
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2098
- * schema default, no fallback is applied, and a locale with no history returns an empty array
2099
- * rather than another locale's rows. Every row names the locale it belongs to.
2170
+ * client's own (`withLocale()`), else the schema default; no fallback is applied, and a locale
2171
+ * with no history returns an empty array rather than another locale's rows. Every row names the
2172
+ * locale it belongs to.
2100
2173
  */
2101
2174
  async versions(id, options) {
2175
+ const locale = callLocale(options?.locale, this.clientLocale());
2102
2176
  return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions", "get", {
2103
2177
  path: { contentType: this.contentType, id },
2104
2178
  query: {
2105
2179
  limit: options?.limit ?? 10,
2106
- ...options?.locale === void 0 ? {} : { locale: options.locale }
2180
+ ...locale === void 0 ? {} : { locale }
2107
2181
  }
2108
2182
  });
2109
2183
  }
2110
2184
  /**
2111
2185
  * Get a specific version of an entry.
2112
2186
  *
2113
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2114
- * different content in each one.
2187
+ * `locale` defaults to the client's own (`withLocale()`), else the schema default. Version
2188
+ * numbers are per locale, so version 2 is different content in each one.
2115
2189
  */
2116
2190
  async version(id, versionNumber, options) {
2191
+ const locale = callLocale(options?.locale, this.clientLocale());
2117
2192
  return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions/{versionNumber}", "get", {
2118
2193
  path: {
2119
2194
  contentType: this.contentType,
2120
2195
  id,
2121
2196
  versionNumber: String(versionNumber)
2122
2197
  },
2123
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
2198
+ query: locale === void 0 ? void 0 : { locale }
2124
2199
  });
2125
2200
  }
2126
2201
  /**
@@ -2159,7 +2234,7 @@ var _ContentClient = class _ContentClient {
2159
2234
  if (options?.include != null) {
2160
2235
  params.include = options.include.join(",");
2161
2236
  }
2162
- const locale = options?.locale ?? this.defaultLocale;
2237
+ const locale = options?.locale ?? this.clientLocale();
2163
2238
  if (locale != null && locale !== "") {
2164
2239
  params.locale = locale;
2165
2240
  }
@@ -2179,19 +2254,20 @@ var _ContentClient = class _ContentClient {
2179
2254
  * Create a new ContentClient for a different content type
2180
2255
  */
2181
2256
  ofType(contentType) {
2182
- return new _ContentClient(this.httpClient, contentType, this.defaultLocale);
2257
+ return new _ContentClient(this.httpClient, contentType, this.clientLocale);
2183
2258
  }
2184
2259
  /**
2185
- * Create a new ContentClient with a different default locale
2260
+ * Create a new ContentClient with a different default locale, fixed: an update of the client's
2261
+ * locale (`updateConfig({ locale })`) does not reach it
2186
2262
  */
2187
2263
  withLocale(locale) {
2188
2264
  return new _ContentClient(this.httpClient, this.contentType, locale);
2189
2265
  }
2190
2266
  /**
2191
- * Get the current default locale
2267
+ * Get the default locale as it is now: the client's, or the one `withLocale()` fixed
2192
2268
  */
2193
2269
  getDefaultLocale() {
2194
- return this.defaultLocale;
2270
+ return this.clientLocale();
2195
2271
  }
2196
2272
  };
2197
2273
  chunkMWMSFIWN_cjs.__name(_ContentClient, "ContentClient");
@@ -2200,7 +2276,7 @@ var ContentClient = _ContentClient;
2200
2276
  // src/errors/file-errors.ts
2201
2277
  var _FileUploadError = class _FileUploadError extends SDKError {
2202
2278
  constructor(code, message, options = {}) {
2203
- super(message, options.statusCode, options.cause, { fileErrorCode: code });
2279
+ super(message, options.statusCode, options.cause, { ...options.context, fileErrorCode: code });
2204
2280
  chunkMWMSFIWN_cjs.__publicField(this, "code");
2205
2281
  chunkMWMSFIWN_cjs.__publicField(this, "retryable");
2206
2282
  this.code = code;
@@ -2247,11 +2323,52 @@ function validateFile(file, constraints = {}) {
2247
2323
  }
2248
2324
  chunkMWMSFIWN_cjs.__name(validateFile, "validateFile");
2249
2325
 
2326
+ // src/errors/file-error-codes.ts
2327
+ var FILE_ERROR_CODES = [
2328
+ "UPLOAD_TOO_LARGE",
2329
+ "UNSUPPORTED_MIME",
2330
+ "DIMENSION_OUT_OF_RANGE",
2331
+ "ASPECT_RATIO",
2332
+ "CORRUPT_FILE",
2333
+ "UNSUPPORTED_CODEC",
2334
+ "IMAGES_LIMIT_EXCEEDED",
2335
+ "STREAM_ENCODE_FAILED",
2336
+ "SCAN_INFECTED",
2337
+ "INTERNAL"
2338
+ ];
2339
+
2250
2340
  // src/content/asset-client.ts
2341
+ function assertWaitOptions(options) {
2342
+ const { timeoutMs, pollIntervalMs } = options;
2343
+ if (timeoutMs !== void 0 && !(typeof timeoutMs === "number" && timeoutMs >= 0 && timeoutMs <= MAX_TIMER_DELAY_MS)) {
2344
+ throw new Error(
2345
+ `timeoutMs must be a number of milliseconds from 0 to ${MAX_TIMER_DELAY_MS}, and got ${String(timeoutMs)}`
2346
+ );
2347
+ }
2348
+ if (pollIntervalMs !== void 0 && !isTimerDelay(pollIntervalMs)) {
2349
+ throw new Error(
2350
+ `pollIntervalMs must be a number of milliseconds from 1 to ${MAX_TIMER_DELAY_MS} \u2014 a timer given 0, NaN, Infinity or more fires at once \u2014 and got ${String(pollIntervalMs)}`
2351
+ );
2352
+ }
2353
+ }
2354
+ chunkMWMSFIWN_cjs.__name(assertWaitOptions, "assertWaitOptions");
2251
2355
  function hasText(value) {
2252
2356
  return value != null && value !== "";
2253
2357
  }
2254
2358
  chunkMWMSFIWN_cjs.__name(hasText, "hasText");
2359
+ function processingFailure(subject, stored) {
2360
+ const storedCode = stored?.code;
2361
+ const code = FILE_ERROR_CODES.find((known) => known === storedCode) ?? "PROCESSING_FAILED";
2362
+ return new FileUploadError(
2363
+ code,
2364
+ `Asset ${subject}: ${stored?.message ?? "File processing failed"}`,
2365
+ {
2366
+ retriable: stored?.retriable === true,
2367
+ context: { processingError: stored }
2368
+ }
2369
+ );
2370
+ }
2371
+ chunkMWMSFIWN_cjs.__name(processingFailure, "processingFailure");
2255
2372
  async function computeSha256Hex(blob) {
2256
2373
  try {
2257
2374
  const subtle = globalThis.crypto?.subtle;
@@ -2267,11 +2384,17 @@ async function computeSha256Hex(blob) {
2267
2384
  }
2268
2385
  chunkMWMSFIWN_cjs.__name(computeSha256Hex, "computeSha256Hex");
2269
2386
  var _AssetFileBuilder = class _AssetFileBuilder {
2270
- constructor(httpClient, assetType, entryUid, defaultLocale) {
2387
+ /**
2388
+ * @param locale - The client's locale, sent when a call names none: the function
2389
+ * `TypedRelyIOClient` hands over, or a locale fixed for this builder
2390
+ */
2391
+ constructor(httpClient, assetType, entryUid, locale) {
2271
2392
  this.httpClient = httpClient;
2272
2393
  this.assetType = assetType;
2273
2394
  this.entryUid = entryUid;
2274
- this.defaultLocale = defaultLocale;
2395
+ /** The client's locale, asked on every call rather than copied when this builder was taken. */
2396
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
2397
+ this.clientLocale = readClientLocale(locale);
2275
2398
  }
2276
2399
  /**
2277
2400
  * The path parameters every `/file/*` route on this builder takes.
@@ -2284,7 +2407,16 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2284
2407
  return { contentType: this.assetType, id: this.entryUid };
2285
2408
  }
2286
2409
  withLocale(locale) {
2287
- return locale ?? this.defaultLocale;
2410
+ return locale ?? this.clientLocale();
2411
+ }
2412
+ /**
2413
+ * The `locale` body field of a multipart call: the session's, else the client's. The API finds
2414
+ * the binding by it, so a session a `withLocale()` client opened must name the same locale on
2415
+ * every later call or its `objectKey` is refused as another binding's.
2416
+ */
2417
+ localeField(locale) {
2418
+ const sent = this.withLocale(locale);
2419
+ return hasText(sent) ? { locale: sent } : {};
2288
2420
  }
2289
2421
  /**
2290
2422
  * Issue a single upload target — an R2 presigned PUT (image/file) or a
@@ -2343,7 +2475,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2343
2475
  uploadId: target.uploadId,
2344
2476
  objectKey: target.objectKey,
2345
2477
  partNumber: target.partNumber,
2346
- ...hasText(target.locale) ? { locale: target.locale } : {}
2478
+ ...this.localeField(target.locale)
2347
2479
  }
2348
2480
  });
2349
2481
  }
@@ -2354,7 +2486,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2354
2486
  body: {
2355
2487
  uploadId: target.uploadId,
2356
2488
  objectKey: target.objectKey,
2357
- ...hasText(target.locale) ? { locale: target.locale } : {}
2489
+ ...this.localeField(target.locale)
2358
2490
  }
2359
2491
  });
2360
2492
  return payload.parts;
@@ -2367,7 +2499,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2367
2499
  uploadId: target.uploadId,
2368
2500
  objectKey: target.objectKey,
2369
2501
  parts: target.parts.map((p) => ({ partNumber: p.partNumber, etag: p.etag })),
2370
- ...hasText(target.locale) ? { locale: target.locale } : {}
2502
+ ...this.localeField(target.locale)
2371
2503
  }
2372
2504
  });
2373
2505
  }
@@ -2378,7 +2510,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2378
2510
  body: {
2379
2511
  uploadId: target.uploadId,
2380
2512
  objectKey: target.objectKey,
2381
- ...hasText(target.locale) ? { locale: target.locale } : {}
2513
+ ...this.localeField(target.locale)
2382
2514
  }
2383
2515
  });
2384
2516
  }
@@ -2398,6 +2530,25 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2398
2530
  { path: this.target, query: params }
2399
2531
  );
2400
2532
  }
2533
+ /**
2534
+ * Read where this file's upload got to — `status`, and the processing stage, progress and error
2535
+ * the pipeline recorded — whatever the asset entry is published in.
2536
+ *
2537
+ * An asset is a draft until its file is ready, and stays one when its file fails, so a key that
2538
+ * reads published content finds no entry for an upload in flight or one that failed. This read
2539
+ * answers for the binding itself. It takes the capability the upload calls take, so a read-only
2540
+ * key is refused with `ReadOnlyKeyError`, and it never returns the entry's fields.
2541
+ */
2542
+ async status(options = {}) {
2543
+ const params = {};
2544
+ const locale = this.withLocale(options.locale);
2545
+ if (hasText(locale)) params.locale = locale;
2546
+ return this.httpClient.fetchPayload(
2547
+ "/v1/{contentType}/{id}/file",
2548
+ "get",
2549
+ { path: this.target, query: params }
2550
+ );
2551
+ }
2401
2552
  /**
2402
2553
  * Update the binding's delivery visibility (token-based; no byte relocation —
2403
2554
  * a downgrade purges the gateway cache). Returns the refreshed asset entry.
@@ -2436,14 +2587,31 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2436
2587
  });
2437
2588
  }
2438
2589
  /**
2439
- * Poll the asset entry until its file binding reaches `ready` (resolves with
2440
- * the ready entry) or `failed` (throws). Times out after `timeoutMs`.
2590
+ * Poll the asset entry until its file binding reaches `ready`, and resolve with the ready entry.
2591
+ *
2592
+ * Each poll reads the entry through the key's lens. When that finds nothing — a key that reads
2593
+ * published content, and an asset that is a draft until its file is ready and stays one when it
2594
+ * fails — the poll reads the binding itself ({@link status}), so a failed upload rejects as one
2595
+ * rather than running out the limit (REL-1481).
2596
+ *
2597
+ * @throws {FileUploadError} When processing failed. `code` is the processing code the service
2598
+ * stored — `UNSUPPORTED_CODEC`, `CORRUPT_FILE` and so on — or `PROCESSING_FAILED` where it
2599
+ * stored none this SDK knows; `context.processingError` holds what it stored, and `retryable`
2600
+ * is its `retriable` hint.
2601
+ * @throws {TimeoutError} When `timeoutMs` passes first. The file may still become ready; the
2602
+ * error's `context.timeout` is the limit and `context.fileStatus` the status last seen. A file
2603
+ * that is `ready` in an asset the key's lens never shows — created with `publish: false`, or
2604
+ * awaiting a workflow — ends here too, and the message says so.
2605
+ * @throws {ReadOnlyKeyError} When the key's lens does not show the asset and the key may not read
2606
+ * its binding either: nothing it can read would ever report the file.
2441
2607
  */
2442
2608
  async waitUntilReady(options = {}) {
2609
+ assertWaitOptions(options);
2443
2610
  const timeoutMs = options.timeoutMs ?? 6e4;
2444
2611
  const pollIntervalMs = options.pollIntervalMs ?? 1500;
2445
2612
  const locale = this.withLocale(options.locale);
2446
2613
  const deadline = Date.now() + timeoutMs;
2614
+ const subject = `${this.assetType}/${this.entryUid}`;
2447
2615
  for (; ; ) {
2448
2616
  const builder = new ContentByIdBuilder(
2449
2617
  this.httpClient,
@@ -2453,15 +2621,24 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2453
2621
  );
2454
2622
  if (hasText(locale)) builder.locale(locale);
2455
2623
  const entry = await builder.execute();
2456
- const status = entry?.file?.status;
2457
- if (entry && status === "ready") return entry;
2458
- if (status === "failed") {
2459
- const message = entry?.file?.processing?.error?.message ?? "File processing failed";
2460
- throw new Error(`Asset ${this.assetType}/${this.entryUid}: ${message}`);
2624
+ let status;
2625
+ if (entry === null) {
2626
+ const binding = await this.status({ ...hasText(locale) ? { locale } : {} });
2627
+ status = binding.status;
2628
+ if (status === "failed") throw processingFailure(subject, binding.processing?.error);
2629
+ } else {
2630
+ status = entry.file?.status;
2631
+ if (status === "ready") return entry;
2632
+ if (status === "failed") throw processingFailure(subject, entry.file?.processing?.error);
2461
2633
  }
2462
2634
  if (Date.now() >= deadline) {
2463
- throw new Error(
2464
- `Timed out after ${timeoutMs}ms waiting for ${this.assetType}/${this.entryUid} (status: ${status ?? "unknown"})`
2635
+ const unseen = entry === null && status === "ready" ? "; the file is ready and this key's lens does not show the asset \u2014 it is not published" : "";
2636
+ throw new TimeoutError(
2637
+ `Timed out after ${timeoutMs}ms waiting for ${subject} (status: ${status ?? "unknown"})${unseen}`,
2638
+ timeoutMs,
2639
+ void 0,
2640
+ void 0,
2641
+ { fileStatus: status }
2465
2642
  );
2466
2643
  }
2467
2644
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
@@ -2471,11 +2648,14 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2471
2648
  chunkMWMSFIWN_cjs.__name(_AssetFileBuilder, "AssetFileBuilder");
2472
2649
  var AssetFileBuilder = _AssetFileBuilder;
2473
2650
  var _AssetUploadBuilder = class _AssetUploadBuilder {
2474
- constructor(httpClient, assetType, file, defaultLocale) {
2651
+ /**
2652
+ * @param locale - The client's locale, the upload's when `.locale()` names none: the function
2653
+ * `TypedRelyIOClient` hands over, or a locale fixed for this upload
2654
+ */
2655
+ constructor(httpClient, assetType, file, locale) {
2475
2656
  this.httpClient = httpClient;
2476
2657
  this.assetType = assetType;
2477
2658
  this.file = file;
2478
- this.defaultLocale = defaultLocale;
2479
2659
  chunkMWMSFIWN_cjs.__publicField(this, "_fileName");
2480
2660
  chunkMWMSFIWN_cjs.__publicField(this, "_visibility");
2481
2661
  chunkMWMSFIWN_cjs.__publicField(this, "_locale");
@@ -2487,6 +2667,9 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2487
2667
  chunkMWMSFIWN_cjs.__publicField(this, "_onProgress");
2488
2668
  chunkMWMSFIWN_cjs.__publicField(this, "_validate");
2489
2669
  chunkMWMSFIWN_cjs.__publicField(this, "_maxPartRetries", 3);
2670
+ /** The client's locale, read once when the upload starts. */
2671
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
2672
+ this.clientLocale = readClientLocale(locale);
2490
2673
  }
2491
2674
  /** Subscribe to client → storage upload progress (single PUT + multipart). */
2492
2675
  onProgress(callback) {
@@ -2536,8 +2719,14 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2536
2719
  this._slug = slug;
2537
2720
  return this;
2538
2721
  }
2539
- /** Wait until the file binding becomes `ready` before resolving. */
2722
+ /**
2723
+ * Wait until the file binding becomes `ready` before resolving.
2724
+ *
2725
+ * @throws {Error} When `timeoutMs` or `pollIntervalMs` is one the wait cannot honour — refused
2726
+ * here, before anything is uploaded, rather than after the bytes are in.
2727
+ */
2540
2728
  waitForReady(options = true) {
2729
+ if (typeof options === "object") assertWaitOptions(options);
2541
2730
  if (options === false) {
2542
2731
  this._waitForReady = false;
2543
2732
  } else {
@@ -2552,7 +2741,8 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2552
2741
  if (!fileName) {
2553
2742
  throw new Error('A file name is required: pass a File, or call .filename("name.ext")');
2554
2743
  }
2555
- const locale = this._locale ?? this.defaultLocale;
2744
+ const clientLocale = this.clientLocale();
2745
+ const locale = this._locale ?? clientLocale;
2556
2746
  if (this._validate) {
2557
2747
  const violations = validateFile(this.file, this._validate);
2558
2748
  if (violations.length > 0) {
@@ -2563,7 +2753,7 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2563
2753
  }
2564
2754
  }
2565
2755
  const hash = await computeSha256Hex(this.file);
2566
- const client = new AssetClient(this.httpClient, this.assetType, this.defaultLocale);
2756
+ const client = new AssetClient(this.httpClient, this.assetType, clientLocale);
2567
2757
  const created = await client.create(this._content, {
2568
2758
  ...hasText(this._slug) ? { slug: this._slug } : {},
2569
2759
  ...hasText(locale) ? { locale } : {},
@@ -2714,17 +2904,26 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2714
2904
  chunkMWMSFIWN_cjs.__name(_AssetUploadBuilder, "AssetUploadBuilder");
2715
2905
  var AssetUploadBuilder = _AssetUploadBuilder;
2716
2906
  var _AssetClient = class _AssetClient {
2717
- constructor(httpClient, assetType, defaultLocale) {
2907
+ /**
2908
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
2909
+ * every call, or a locale fixed for this client
2910
+ */
2911
+ constructor(httpClient, assetType, locale) {
2718
2912
  this.httpClient = httpClient;
2719
2913
  this.assetType = assetType;
2720
- this.defaultLocale = defaultLocale;
2914
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
2915
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
2916
+ this.clientLocale = readClientLocale(locale);
2721
2917
  }
2722
- /** Create a query builder for this asset type. */
2918
+ /**
2919
+ * Create a query builder for this asset type. It resolves asset reads; its conditions name the
2920
+ * asset type's fields, which the `file` and `urls` blocks are not.
2921
+ */
2723
2922
  query() {
2724
2923
  return new ContentQueryBuilder(
2725
2924
  this.httpClient,
2726
2925
  this.assetType,
2727
- this.defaultLocale
2926
+ this.clientLocale
2728
2927
  );
2729
2928
  }
2730
2929
  /** Find an asset entry by id (or slug) with fluent options. */
@@ -2733,7 +2932,7 @@ var _AssetClient = class _AssetClient {
2733
2932
  this.httpClient,
2734
2933
  this.assetType,
2735
2934
  id,
2736
- this.defaultLocale
2935
+ this.clientLocale
2737
2936
  );
2738
2937
  }
2739
2938
  /** Fetch a single asset entry by id (or slug), or `null` if not found. */
@@ -2754,28 +2953,34 @@ var _AssetClient = class _AssetClient {
2754
2953
  * Create a new asset entry as a draft. The binary is uploaded separately via
2755
2954
  * `file(uid)` (or use the high-level `upload()` helper), and the entry
2756
2955
  * auto-publishes when its file becomes ready (unless `publish: false`).
2956
+ * `locale` defaults to the client's own (`withLocale()`).
2757
2957
  */
2758
2958
  async create(data, options) {
2759
- const { idempotencyKey, ...rest } = options ?? {};
2959
+ const { idempotencyKey, locale, ...rest } = options ?? {};
2960
+ const sent = callLocale(locale, this.clientLocale());
2760
2961
  return this.httpClient.fetchPayload(
2761
2962
  "/v1/{contentType}",
2762
2963
  "post",
2763
2964
  {
2764
2965
  path: { contentType: this.assetType },
2765
- body: { content: data, ...rest },
2966
+ body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
2766
2967
  headers: writeHeaders({ idempotencyKey })
2767
2968
  }
2768
2969
  );
2769
2970
  }
2770
- /** Update an asset entry's metadata fields (and/or slug). */
2971
+ /**
2972
+ * Update an asset entry's metadata fields (and/or slug). `locale` defaults to the client's own
2973
+ * (`withLocale()`).
2974
+ */
2771
2975
  async update(id, data, options) {
2772
- const { idempotencyKey, ifMatch, ...rest } = options ?? {};
2976
+ const { idempotencyKey, ifMatch, locale, ...rest } = options ?? {};
2977
+ const sent = callLocale(locale, this.clientLocale());
2773
2978
  return this.httpClient.fetchPayload(
2774
2979
  "/v1/{contentType}/{id}",
2775
2980
  "patch",
2776
2981
  {
2777
2982
  path: { contentType: this.assetType, id },
2778
- body: { content: data, ...rest },
2983
+ body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
2779
2984
  headers: writeHeaders({ idempotencyKey, ifMatch })
2780
2985
  }
2781
2986
  );
@@ -2789,21 +2994,24 @@ var _AssetClient = class _AssetClient {
2789
2994
  }
2790
2995
  /** Get the file sub-resource builder for a specific asset entry. */
2791
2996
  file(entryUid) {
2792
- return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.defaultLocale);
2997
+ return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.clientLocale);
2793
2998
  }
2794
2999
  /** Start a high-level upload (create → presign → PUT → confirm). */
2795
3000
  upload(file) {
2796
- return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.defaultLocale);
3001
+ return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.clientLocale);
2797
3002
  }
2798
3003
  /** Get the asset type id. */
2799
3004
  getAssetType() {
2800
3005
  return this.assetType;
2801
3006
  }
2802
- /** Get the current default locale. */
3007
+ /** Get the default locale as it is now: the client's, or the one `withLocale()` fixed. */
2803
3008
  getDefaultLocale() {
2804
- return this.defaultLocale;
3009
+ return this.clientLocale();
2805
3010
  }
2806
- /** Create a new AssetClient for this type with a different default locale. */
3011
+ /**
3012
+ * Create a new AssetClient for this type with a different default locale, fixed: an update of the
3013
+ * client's locale (`updateConfig({ locale })`) does not reach it.
3014
+ */
2807
3015
  withLocale(locale) {
2808
3016
  return new _AssetClient(this.httpClient, this.assetType, locale);
2809
3017
  }
@@ -2819,12 +3027,18 @@ chunkMWMSFIWN_cjs.__name(isAssetEntry, "isAssetEntry");
2819
3027
 
2820
3028
  // src/content/singleton-client.ts
2821
3029
  var _SingletonClient = class _SingletonClient {
2822
- constructor(httpClient, singletonKey, defaultLocale) {
3030
+ /**
3031
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
3032
+ * every call, or a locale fixed for this client
3033
+ */
3034
+ constructor(httpClient, singletonKey, locale) {
2823
3035
  this.httpClient = httpClient;
2824
3036
  this.singletonKey = singletonKey;
2825
- this.defaultLocale = defaultLocale;
2826
3037
  chunkMWMSFIWN_cjs.__publicField(this, "includeFields");
2827
3038
  chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
3039
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
3040
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3041
+ this.clientLocale = readClientLocale(locale);
2828
3042
  }
2829
3043
  /**
2830
3044
  * Include reference fields in the response
@@ -2864,7 +3078,7 @@ var _SingletonClient = class _SingletonClient {
2864
3078
  async fetchWithTag(options) {
2865
3079
  const query = {};
2866
3080
  const includeValue = options?.include ?? this.includeFields;
2867
- const localeValueFinal = options?.locale ?? this.localeValue ?? this.defaultLocale;
3081
+ const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
2868
3082
  if (includeValue) query.include = includeValue.join(",");
2869
3083
  if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
2870
3084
  const response = await this.httpClient.send(
@@ -2878,11 +3092,12 @@ var _SingletonClient = class _SingletonClient {
2878
3092
  * Update singleton content. The API auto-publishes on PATCH — there is no
2879
3093
  * separate publish route; calling `update()` writes and publishes.
2880
3094
  * @param data - The content fields to update
2881
- * @param locale - Optional locale for localized content (overrides fluent locale)
3095
+ * @param locale - Optional locale for localized content (overrides the fluent locale, which
3096
+ * overrides the client's own)
2882
3097
  * @param options - `If-Match` / `Idempotency-Key`, both declared on this route
2883
3098
  */
2884
3099
  async update(data, locale, options) {
2885
- const finalLocale = locale ?? this.localeValue;
3100
+ const finalLocale = this.localeOf(locale);
2886
3101
  return this.httpClient.fetchPayload(
2887
3102
  "/v1/singletons/{key}",
2888
3103
  "patch",
@@ -2911,15 +3126,17 @@ var _SingletonClient = class _SingletonClient {
2911
3126
  * Get version history for one locale of the singleton.
2912
3127
  *
2913
3128
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2914
- * schema default, no fallback is applied, and a locale with no history returns an empty array
2915
- * rather than another locale's rows. Every row names the locale it belongs to.
3129
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
3130
+ * fallback is applied, and a locale with no history returns an empty array rather than another
3131
+ * locale's rows. Every row names the locale it belongs to.
2916
3132
  */
2917
3133
  async versions(options) {
3134
+ const locale = this.localeOf(options?.locale);
2918
3135
  const payload = await this.httpClient.fetchPayload("/v1/singletons/{key}/versions", "get", {
2919
3136
  path: { key: this.singletonKey },
2920
3137
  query: {
2921
3138
  limit: options?.limit ?? 10,
2922
- ...options?.locale === void 0 ? {} : { locale: options.locale }
3139
+ ...locale === void 0 ? {} : { locale }
2923
3140
  }
2924
3141
  });
2925
3142
  return payload.versions;
@@ -2927,20 +3144,25 @@ var _SingletonClient = class _SingletonClient {
2927
3144
  /**
2928
3145
  * Get a specific version of the singleton.
2929
3146
  *
2930
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2931
- * different content in each one.
3147
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
3148
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
2932
3149
  */
2933
3150
  async version(versionNumber, options) {
3151
+ const locale = this.localeOf(options?.locale);
2934
3152
  try {
2935
3153
  return await this.httpClient.fetchPayload("/v1/singletons/{key}/versions/{versionNumber}", "get", {
2936
3154
  path: { key: this.singletonKey, versionNumber: String(versionNumber) },
2937
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
3155
+ query: locale === void 0 ? void 0 : { locale }
2938
3156
  });
2939
3157
  } catch (error) {
2940
3158
  if (isResourceNotFound(error)) return null;
2941
3159
  throw error;
2942
3160
  }
2943
3161
  }
3162
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
3163
+ localeOf(named) {
3164
+ return callLocale(named ?? this.localeValue, this.clientLocale());
3165
+ }
2944
3166
  /**
2945
3167
  * Get the singleton key
2946
3168
  */
@@ -2961,12 +3183,18 @@ var SingletonClient = _SingletonClient;
2961
3183
 
2962
3184
  // src/content/settings-client.ts
2963
3185
  var _SettingsClient = class _SettingsClient {
2964
- constructor(httpClient, groupId, defaultLocale) {
3186
+ /**
3187
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
3188
+ * every call, or a locale fixed for this client
3189
+ */
3190
+ constructor(httpClient, groupId, locale) {
2965
3191
  this.httpClient = httpClient;
2966
3192
  this.groupId = groupId;
2967
- this.defaultLocale = defaultLocale;
2968
3193
  chunkMWMSFIWN_cjs.__publicField(this, "includeFields");
2969
3194
  chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
3195
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
3196
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3197
+ this.clientLocale = readClientLocale(locale);
2970
3198
  }
2971
3199
  /**
2972
3200
  * Include reference fields in the response
@@ -2998,12 +3226,20 @@ var _SettingsClient = class _SettingsClient {
2998
3226
  }
2999
3227
  /**
3000
3228
  * Update settings group
3229
+ *
3230
+ * The fields travel as `content` beside an optional `locale`, the body the route validates
3231
+ * (`UpdateSettingsDto`); any other top-level key is refused `REQUEST_INVALID`.
3232
+ *
3001
3233
  * @param settings - The settings fields to update
3002
- * @param locale - Optional locale for localized settings (overrides fluent locale)
3234
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
3235
+ * overrides the client's own)
3003
3236
  */
3004
3237
  async update(settings, locale, options) {
3005
- const finalLocale = locale ?? this.localeValue;
3006
- const body = finalLocale != null && finalLocale !== "" ? { ...settings, locale: finalLocale } : settings;
3238
+ const finalLocale = this.localeOf(locale);
3239
+ const body = {
3240
+ content: settings,
3241
+ ...finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : {}
3242
+ };
3007
3243
  return this.httpClient.fetchPayload(
3008
3244
  "/v1/settings/{groupId}",
3009
3245
  "patch",
@@ -3018,7 +3254,7 @@ var _SettingsClient = class _SettingsClient {
3018
3254
  async fetchWithTag(options) {
3019
3255
  const query = {};
3020
3256
  const includeValue = options?.include ?? this.includeFields;
3021
- const localeValueFinal = options?.locale ?? this.localeValue ?? this.defaultLocale;
3257
+ const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
3022
3258
  if (includeValue) query.include = includeValue.join(",");
3023
3259
  if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
3024
3260
  const response = await this.httpClient.send(
@@ -3030,16 +3266,20 @@ var _SettingsClient = class _SettingsClient {
3030
3266
  }
3031
3267
  /**
3032
3268
  * Reset settings to default values
3033
- * @param locale - Optional locale for localized settings
3269
+ *
3270
+ * The route reads its locale from `?locale=` and takes no body, so that is where it is sent.
3271
+ *
3272
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
3273
+ * overrides the client's own)
3034
3274
  */
3035
3275
  async reset(locale, options) {
3036
- const finalLocale = locale ?? this.localeValue;
3276
+ const finalLocale = this.localeOf(locale);
3037
3277
  return this.httpClient.fetchPayload(
3038
3278
  "/v1/settings/{groupId}/reset",
3039
3279
  "post",
3040
3280
  {
3041
3281
  path: { groupId: this.groupId },
3042
- body: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
3282
+ query: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
3043
3283
  headers: writeHeaders(options)
3044
3284
  }
3045
3285
  );
@@ -3070,15 +3310,17 @@ var _SettingsClient = class _SettingsClient {
3070
3310
  * Get version history for one locale of the settings group.
3071
3311
  *
3072
3312
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
3073
- * schema default, no fallback is applied, and a locale with no history returns an empty array
3074
- * rather than another locale's rows. Every row names the locale it belongs to.
3313
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
3314
+ * fallback is applied, and a locale with no history returns an empty array rather than another
3315
+ * locale's rows. Every row names the locale it belongs to.
3075
3316
  */
3076
3317
  async versions(options) {
3318
+ const locale = this.localeOf(options?.locale);
3077
3319
  const payload = await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions", "get", {
3078
3320
  path: { groupId: this.groupId },
3079
3321
  query: {
3080
3322
  limit: options?.limit ?? 10,
3081
- ...options?.locale === void 0 ? {} : { locale: options.locale }
3323
+ ...locale === void 0 ? {} : { locale }
3082
3324
  }
3083
3325
  });
3084
3326
  return payload.versions;
@@ -3086,20 +3328,25 @@ var _SettingsClient = class _SettingsClient {
3086
3328
  /**
3087
3329
  * Get a specific version of the settings.
3088
3330
  *
3089
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
3090
- * different content in each one.
3331
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
3332
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
3091
3333
  */
3092
3334
  async version(versionNumber, options) {
3335
+ const locale = this.localeOf(options?.locale);
3093
3336
  try {
3094
3337
  return await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions/{versionNumber}", "get", {
3095
3338
  path: { groupId: this.groupId, versionNumber: String(versionNumber) },
3096
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
3339
+ query: locale === void 0 ? void 0 : { locale }
3097
3340
  });
3098
3341
  } catch (error) {
3099
3342
  if (isResourceNotFound(error)) return null;
3100
3343
  throw error;
3101
3344
  }
3102
3345
  }
3346
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
3347
+ localeOf(named) {
3348
+ return callLocale(named ?? this.localeValue, this.clientLocale());
3349
+ }
3103
3350
  /**
3104
3351
  * Get the settings group ID
3105
3352
  */
@@ -3121,15 +3368,18 @@ var SettingsClient = _SettingsClient;
3121
3368
  // src/search/search-client.ts
3122
3369
  var _SearchBuilder = class _SearchBuilder {
3123
3370
  /**
3124
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
3371
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3372
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3125
3373
  */
3126
- constructor(httpClient, query, defaultLocale) {
3374
+ constructor(httpClient, query, locale) {
3127
3375
  this.httpClient = httpClient;
3128
- this.defaultLocale = defaultLocale;
3129
3376
  chunkMWMSFIWN_cjs.__publicField(this, "query");
3130
3377
  chunkMWMSFIWN_cjs.__publicField(this, "searchOptions", {});
3131
3378
  chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
3379
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
3380
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3132
3381
  this.query = query;
3382
+ this.clientLocale = readClientLocale(locale);
3133
3383
  }
3134
3384
  /**
3135
3385
  * Headers this search adds to the client's own, e.g. `X-RelyIO-Dataset` to search another
@@ -3160,10 +3410,12 @@ var _SearchBuilder = class _SearchBuilder {
3160
3410
  return this;
3161
3411
  }
3162
3412
  /**
3163
- * Add filter conditions
3413
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
3414
+ * refused here, before anything is sent.
3164
3415
  * @param conditions - Filter conditions
3165
3416
  */
3166
3417
  where(conditions) {
3418
+ refuseMetadataConditions(conditions);
3167
3419
  this.searchOptions.where = {
3168
3420
  ...this.searchOptions.where,
3169
3421
  ...conditions
@@ -3271,7 +3523,7 @@ var _SearchBuilder = class _SearchBuilder {
3271
3523
  if (this.searchOptions.explain === true) {
3272
3524
  body.explain = true;
3273
3525
  }
3274
- const locale = this.searchOptions.locale ?? this.defaultLocale;
3526
+ const locale = this.searchOptions.locale ?? this.clientLocale();
3275
3527
  if (locale != null && locale !== "") {
3276
3528
  body.locale = locale;
3277
3529
  }
@@ -3299,14 +3551,17 @@ chunkMWMSFIWN_cjs.__name(_SearchBuilder, "SearchBuilder");
3299
3551
  var SearchBuilder = _SearchBuilder;
3300
3552
  var _AutocompleteBuilder = class _AutocompleteBuilder {
3301
3553
  /**
3302
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
3554
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3555
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3303
3556
  */
3304
- constructor(httpClient, query, defaultLocale) {
3557
+ constructor(httpClient, query, locale) {
3305
3558
  this.httpClient = httpClient;
3306
- this.defaultLocale = defaultLocale;
3307
3559
  chunkMWMSFIWN_cjs.__publicField(this, "query");
3308
3560
  chunkMWMSFIWN_cjs.__publicField(this, "autocompleteOptions", {});
3561
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
3562
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3309
3563
  this.query = query;
3564
+ this.clientLocale = readClientLocale(locale);
3310
3565
  }
3311
3566
  /**
3312
3567
  * Autocomplete within a content type
@@ -3332,10 +3587,12 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
3332
3587
  return this;
3333
3588
  }
3334
3589
  /**
3335
- * Add filter conditions
3590
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
3591
+ * refused here, before anything is sent.
3336
3592
  * @param conditions - Filter conditions
3337
3593
  */
3338
3594
  where(conditions) {
3595
+ refuseMetadataConditions(conditions);
3339
3596
  this.autocompleteOptions.where = {
3340
3597
  ...this.autocompleteOptions.where,
3341
3598
  ...conditions
@@ -3382,7 +3639,7 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
3382
3639
  if (this.autocompleteOptions.limit !== void 0) {
3383
3640
  body.limit = this.autocompleteOptions.limit;
3384
3641
  }
3385
- const locale = this.autocompleteOptions.locale ?? this.defaultLocale;
3642
+ const locale = this.autocompleteOptions.locale ?? this.clientLocale();
3386
3643
  if (locale != null && locale !== "") {
3387
3644
  body.locale = locale;
3388
3645
  }
@@ -3400,15 +3657,18 @@ chunkMWMSFIWN_cjs.__name(_AutocompleteBuilder, "AutocompleteBuilder");
3400
3657
  var AutocompleteBuilder = _AutocompleteBuilder;
3401
3658
  var _SimilarBuilder = class _SimilarBuilder {
3402
3659
  /**
3403
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
3660
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3661
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3404
3662
  */
3405
- constructor(httpClient, sourceId, defaultLocale) {
3663
+ constructor(httpClient, sourceId, locale) {
3406
3664
  this.httpClient = httpClient;
3407
- this.defaultLocale = defaultLocale;
3408
3665
  chunkMWMSFIWN_cjs.__publicField(this, "sourceId");
3409
3666
  chunkMWMSFIWN_cjs.__publicField(this, "similarOptions", {});
3410
3667
  chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
3668
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
3669
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3411
3670
  this.sourceId = sourceId;
3671
+ this.clientLocale = readClientLocale(locale);
3412
3672
  }
3413
3673
  /**
3414
3674
  * Headers this read adds to the client's own, e.g. `X-RelyIO-Dataset` to read another dataset
@@ -3436,17 +3696,12 @@ var _SimilarBuilder = class _SimilarBuilder {
3436
3696
  this.similarOptions.contentType = void 0;
3437
3697
  return this;
3438
3698
  }
3439
- /**
3440
- * Add filter conditions
3441
- * @param conditions - Filter conditions
3699
+ /*
3700
+ * No `where()` (REL-1452). Similar ranks from the source entry's stored vector, and the vector
3701
+ * index can pre-filter by content type and locale only — never by an entry field. The API used to
3702
+ * accept `where` here and apply nothing; it now refuses the property, so the builder does not
3703
+ * offer a filter that cannot be honoured. Narrow with `.in()`, `.across()` and `.locale()`.
3442
3704
  */
3443
- where(conditions) {
3444
- this.similarOptions.where = {
3445
- ...this.similarOptions.where,
3446
- ...conditions
3447
- };
3448
- return this;
3449
- }
3450
3705
  /**
3451
3706
  * Limit number of results
3452
3707
  * @param count - Maximum results
@@ -3480,13 +3735,10 @@ var _SimilarBuilder = class _SimilarBuilder {
3480
3735
  if (contentTypes != null) {
3481
3736
  body.contentTypes = contentTypes;
3482
3737
  }
3483
- if (this.similarOptions.where && Object.keys(this.similarOptions.where).length > 0) {
3484
- body.where = this.similarOptions.where;
3485
- }
3486
3738
  if (this.similarOptions.limit !== void 0) {
3487
3739
  body.limit = this.similarOptions.limit;
3488
3740
  }
3489
- const locale = this.similarOptions.locale ?? this.defaultLocale;
3741
+ const locale = this.similarOptions.locale ?? this.clientLocale();
3490
3742
  if (locale != null && locale !== "") {
3491
3743
  body.locale = locale;
3492
3744
  }
@@ -3514,41 +3766,36 @@ chunkMWMSFIWN_cjs.__name(_SimilarBuilder, "SimilarBuilder");
3514
3766
  var SimilarBuilder = _SimilarBuilder;
3515
3767
  var _SearchClient = class _SearchClient {
3516
3768
  /**
3517
- * @param defaultLocale - The client's locale (`withLocale()`): every builder here sends it when
3518
- * the query names none, as `content()`'s reads do
3769
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`): every builder
3770
+ * here sends it when the query names none, as `content()`'s reads do — the function
3771
+ * `TypedRelyIOClient` hands over, or a locale fixed for this client
3519
3772
  */
3520
- constructor(httpClient, defaultLocale) {
3773
+ constructor(httpClient, locale) {
3521
3774
  this.httpClient = httpClient;
3522
- this.defaultLocale = defaultLocale;
3775
+ /** The client's locale, handed to every builder here to ask when it sends. */
3776
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3777
+ this.clientLocale = readClientLocale(locale);
3523
3778
  }
3524
3779
  /**
3525
3780
  * Start a search query
3526
3781
  * @param query - Search query string
3527
3782
  */
3528
3783
  search(query) {
3529
- return new SearchBuilder(this.httpClient, query, this.defaultLocale);
3784
+ return new SearchBuilder(this.httpClient, query, this.clientLocale);
3530
3785
  }
3531
3786
  /**
3532
3787
  * Start an autocomplete query
3533
3788
  * @param query - Partial query to autocomplete
3534
3789
  */
3535
3790
  autocomplete(query) {
3536
- return new AutocompleteBuilder(this.httpClient, query, this.defaultLocale);
3791
+ return new AutocompleteBuilder(this.httpClient, query, this.clientLocale);
3537
3792
  }
3538
3793
  /**
3539
3794
  * Find content similar to a given entry
3540
3795
  * @param sourceId - Entry ID to find similar content for
3541
3796
  */
3542
3797
  similar(sourceId) {
3543
- return new SimilarBuilder(this.httpClient, sourceId, this.defaultLocale);
3544
- }
3545
- /**
3546
- * Quick search helper - searches all content types
3547
- * @param query - Search query
3548
- * @param limit - Max results (default 20)
3549
- */
3550
- async global(query, limit = 20) {
3551
- return this.search(query).across("*").limit(limit).execute();
3798
+ return new SimilarBuilder(this.httpClient, sourceId, this.clientLocale);
3552
3799
  }
3553
3800
  };
3554
3801
  chunkMWMSFIWN_cjs.__name(_SearchClient, "SearchClient");
@@ -3556,7 +3803,12 @@ var SearchClient = _SearchClient;
3556
3803
 
3557
3804
  // src/batch/batch-client.ts
3558
3805
  var _BatchBuilder = class _BatchBuilder {
3559
- constructor(httpClient) {
3806
+ /**
3807
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), each
3808
+ * operation's when it names none: the function `TypedRelyIOClient` hands over, or a locale fixed
3809
+ * for this batch
3810
+ */
3811
+ constructor(httpClient, locale) {
3560
3812
  this.httpClient = httpClient;
3561
3813
  chunkMWMSFIWN_cjs.__publicField(this, "operations", []);
3562
3814
  chunkMWMSFIWN_cjs.__publicField(this, "defaultOptions", {
@@ -3566,6 +3818,17 @@ var _BatchBuilder = class _BatchBuilder {
3566
3818
  continueOnError: true
3567
3819
  });
3568
3820
  chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
3821
+ /** The client's locale, asked as each operation is added rather than copied when this was built. */
3822
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
3823
+ this.clientLocale = readClientLocale(locale);
3824
+ }
3825
+ /**
3826
+ * An operation's body with its locale: the one it names, else the client's as it is when the
3827
+ * operation is added.
3828
+ */
3829
+ localized(data) {
3830
+ const locale = callLocale(data.locale, this.clientLocale());
3831
+ return locale === void 0 ? data : { ...data, locale };
3569
3832
  }
3570
3833
  // ==========================================================================
3571
3834
  // ENTRY OPERATIONS
@@ -3581,7 +3844,7 @@ var _BatchBuilder = class _BatchBuilder {
3581
3844
  id,
3582
3845
  method: "POST",
3583
3846
  path: `/${contentType}`,
3584
- body: data
3847
+ body: this.localized(data)
3585
3848
  });
3586
3849
  return this;
3587
3850
  }
@@ -3601,7 +3864,7 @@ var _BatchBuilder = class _BatchBuilder {
3601
3864
  id,
3602
3865
  method: "PATCH",
3603
3866
  path: `/${contentType}/${entryId}`,
3604
- body: data
3867
+ body: this.localized(data)
3605
3868
  });
3606
3869
  return this;
3607
3870
  }
@@ -3621,7 +3884,7 @@ var _BatchBuilder = class _BatchBuilder {
3621
3884
  id,
3622
3885
  method: "PUT",
3623
3886
  path: `/${contentType}/${entryId}`,
3624
- body: data
3887
+ body: this.localized(data)
3625
3888
  });
3626
3889
  return this;
3627
3890
  }
@@ -3653,7 +3916,7 @@ var _BatchBuilder = class _BatchBuilder {
3653
3916
  id,
3654
3917
  method: "PATCH",
3655
3918
  path: `/_singletons/${singletonKey}`,
3656
- body: data
3919
+ body: this.localized(data)
3657
3920
  });
3658
3921
  return this;
3659
3922
  }
@@ -3668,7 +3931,7 @@ var _BatchBuilder = class _BatchBuilder {
3668
3931
  id,
3669
3932
  method: "POST",
3670
3933
  path: `/_singletons/${singletonKey}`,
3671
- body: data
3934
+ body: this.localized(data)
3672
3935
  });
3673
3936
  return this;
3674
3937
  }
@@ -3676,7 +3939,8 @@ var _BatchBuilder = class _BatchBuilder {
3676
3939
  // RAW OPERATIONS
3677
3940
  // ==========================================================================
3678
3941
  /**
3679
- * Add a raw operation (for advanced use cases)
3942
+ * Add a raw operation (for advanced use cases). It is sent exactly as written: the client's
3943
+ * locale is not added to it.
3680
3944
  * @param operation - The operation to add
3681
3945
  */
3682
3946
  raw(operation) {
@@ -3802,7 +4066,7 @@ var _BatchBuilder = class _BatchBuilder {
3802
4066
  * Clone the builder
3803
4067
  */
3804
4068
  clone() {
3805
- const cloned = new _BatchBuilder(this.httpClient);
4069
+ const cloned = new _BatchBuilder(this.httpClient, this.clientLocale);
3806
4070
  cloned.operations = [...this.operations];
3807
4071
  cloned.defaultOptions = { ...this.defaultOptions };
3808
4072
  cloned.requestHeaders = this.requestHeaders === void 0 ? void 0 : { ...this.requestHeaders };
@@ -3855,14 +4119,21 @@ var _BatchBuilder = class _BatchBuilder {
3855
4119
  chunkMWMSFIWN_cjs.__name(_BatchBuilder, "BatchBuilder");
3856
4120
  var BatchBuilder = _BatchBuilder;
3857
4121
  var _BatchClient = class _BatchClient {
3858
- constructor(httpClient) {
4122
+ /**
4123
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, or a locale
4124
+ * fixed for this client
4125
+ */
4126
+ constructor(httpClient, locale) {
3859
4127
  this.httpClient = httpClient;
4128
+ /** The client's locale, handed to every batch this builds to ask as operations are added. */
4129
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
4130
+ this.clientLocale = readClientLocale(locale);
3860
4131
  }
3861
4132
  /**
3862
- * Create a new batch builder
4133
+ * Create a new batch builder, whose operations default to this client's locale
3863
4134
  */
3864
4135
  create() {
3865
- return new BatchBuilder(this.httpClient);
4136
+ return new BatchBuilder(this.httpClient, this.clientLocale);
3866
4137
  }
3867
4138
  /**
3868
4139
  * Quick bulk create entries
@@ -3913,15 +4184,18 @@ function withClientLocale(parameters, clientLocale) {
3913
4184
  chunkMWMSFIWN_cjs.__name(withClientLocale, "withClientLocale");
3914
4185
  var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3915
4186
  /**
3916
- * @param defaultLocale - The client's locale (`withLocale()`), sent as the `locale` parameter
3917
- * when `.param('locale', …)` binds none
4187
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
4188
+ * `locale` parameter when `.param('locale', …)` binds none: the function `TypedRelyIOClient`
4189
+ * hands over, or a locale fixed for this builder
3918
4190
  */
3919
- constructor(httpClient, defaultLocale) {
4191
+ constructor(httpClient, locale) {
3920
4192
  this.httpClient = httpClient;
3921
- this.defaultLocale = defaultLocale;
3922
4193
  chunkMWMSFIWN_cjs.__publicField(this, "queryDef", {});
3923
4194
  chunkMWMSFIWN_cjs.__publicField(this, "parameters", {});
3924
4195
  chunkMWMSFIWN_cjs.__publicField(this, "options", {});
4196
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
4197
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
4198
+ this.clientLocale = readClientLocale(locale);
3925
4199
  }
3926
4200
  // ==========================================================================
3927
4201
  // QUERY BLOCKS
@@ -3966,14 +4240,6 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3966
4240
  this.queryDef.search = config;
3967
4241
  return this;
3968
4242
  }
3969
- /**
3970
- * Add similar block
3971
- * @param config - Similar configuration
3972
- */
3973
- similar(config) {
3974
- this.queryDef.similar = config;
3975
- return this;
3976
- }
3977
4243
  // ==========================================================================
3978
4244
  // FETCH MODIFIERS
3979
4245
  // ==========================================================================
@@ -4150,15 +4416,15 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
4150
4416
  * Execute the query
4151
4417
  */
4152
4418
  async execute() {
4153
- if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search && !this.queryDef.similar) {
4419
+ if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search) {
4154
4420
  throw new Error(
4155
- "Query must have at least one of: fetch, aggregate, search, or similar. Use .from(), .aggregate(), .search(), or .similar()"
4421
+ "Query must have at least one of: fetch, aggregate or search. Use .from(), .aggregate() or .search()"
4156
4422
  );
4157
4423
  }
4158
4424
  const body = {
4159
4425
  query: this.queryDef
4160
4426
  };
4161
- const parameters = withClientLocale(this.parameters, this.defaultLocale);
4427
+ const parameters = withClientLocale(this.parameters, this.clientLocale());
4162
4428
  if (parameters !== void 0 && Object.keys(parameters).length > 0) {
4163
4429
  body.parameters = parameters;
4164
4430
  }
@@ -4191,7 +4457,7 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
4191
4457
  * Clone the builder
4192
4458
  */
4193
4459
  clone() {
4194
- const cloned = new _AdhocQueryBuilder(this.httpClient, this.defaultLocale);
4460
+ const cloned = new _AdhocQueryBuilder(this.httpClient, this.clientLocale);
4195
4461
  cloned.queryDef = JSON.parse(JSON.stringify(this.queryDef));
4196
4462
  cloned.parameters = { ...this.parameters };
4197
4463
  cloned.options = { ...this.options };
@@ -4202,18 +4468,21 @@ chunkMWMSFIWN_cjs.__name(_AdhocQueryBuilder, "AdhocQueryBuilder");
4202
4468
  var AdhocQueryBuilder = _AdhocQueryBuilder;
4203
4469
  var _AdhocQueryClient = class _AdhocQueryClient {
4204
4470
  /**
4205
- * @param defaultLocale - The client's locale (`withLocale()`), sent as the `locale` parameter of
4206
- * every query that binds none
4471
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
4472
+ * `locale` parameter of every query that binds none: the function `TypedRelyIOClient` hands
4473
+ * over, or a locale fixed for this client
4207
4474
  */
4208
- constructor(httpClient, defaultLocale) {
4475
+ constructor(httpClient, locale) {
4209
4476
  this.httpClient = httpClient;
4210
- this.defaultLocale = defaultLocale;
4477
+ /** The client's locale, asked on every query rather than copied when this client was taken. */
4478
+ chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
4479
+ this.clientLocale = readClientLocale(locale);
4211
4480
  }
4212
4481
  /**
4213
4482
  * Create a new query builder
4214
4483
  */
4215
4484
  build() {
4216
- return new AdhocQueryBuilder(this.httpClient, this.defaultLocale);
4485
+ return new AdhocQueryBuilder(this.httpClient, this.clientLocale);
4217
4486
  }
4218
4487
  /**
4219
4488
  * Execute a query definition directly
@@ -4228,7 +4497,7 @@ var _AdhocQueryClient = class _AdhocQueryClient {
4228
4497
  const body = {
4229
4498
  query: definition
4230
4499
  };
4231
- const sent = withClientLocale(parameters, this.defaultLocale);
4500
+ const sent = withClientLocale(parameters, this.clientLocale());
4232
4501
  if (sent !== void 0 && Object.keys(sent).length > 0) {
4233
4502
  body.parameters = sent;
4234
4503
  }
@@ -4477,7 +4746,7 @@ var DEFAULT_CONFIG = {
4477
4746
  environment: "production",
4478
4747
  headers: {},
4479
4748
  browser: {
4480
- includeCredentials: true,
4749
+ includeCredentials: false,
4481
4750
  useRelativeUrls: false
4482
4751
  },
4483
4752
  cache: {
@@ -4509,45 +4778,42 @@ function validateConfig(config) {
4509
4778
  if (config.baseUrl != null && typeof config.baseUrl !== "string") {
4510
4779
  throw new Error("Base URL must be a string");
4511
4780
  }
4512
- if (config.timeout != null && (typeof config.timeout !== "number" || config.timeout < 0)) {
4513
- throw new Error("Timeout must be a positive number");
4514
- }
4515
- if (config.retryAttempts != null && (typeof config.retryAttempts !== "number" || config.retryAttempts < 0)) {
4516
- throw new Error("Retry attempts must be a positive number");
4781
+ if (config.timeout != null) assertRequestTimeout(config.timeout);
4782
+ if (config.retryAttempts != null && !(Number.isInteger(config.retryAttempts) && config.retryAttempts >= 1)) {
4783
+ throw new Error(
4784
+ `retryAttempts must be a whole number of at least 1 \u2014 the most attempts one request makes, the first included, so 1 turns retrying off \u2014 and got ${String(config.retryAttempts)}`
4785
+ );
4517
4786
  }
4518
4787
  }
4519
4788
  chunkMWMSFIWN_cjs.__name(validateConfig, "validateConfig");
4520
4789
  var devOverrideNotified = false;
4521
4790
  function resolveConfig(userConfig) {
4522
4791
  validateConfig(userConfig);
4523
- const merged = {
4524
- ...DEFAULT_CONFIG,
4525
- ...userConfig,
4526
- headers: {
4527
- ...DEFAULT_CONFIG.headers,
4528
- ...userConfig.headers
4529
- },
4530
- browser: {
4531
- ...DEFAULT_CONFIG.browser,
4532
- ...userConfig.browser
4533
- },
4534
- cache: {
4535
- ...DEFAULT_CONFIG.cache,
4536
- ...userConfig.cache
4537
- },
4538
- realtime: {
4539
- ...DEFAULT_CONFIG.realtime,
4540
- ...userConfig.realtime
4541
- },
4542
- debug: {
4543
- ...DEFAULT_CONFIG.debug,
4544
- ...userConfig.debug
4545
- }
4546
- };
4547
- const dev = resolveDevOverride(userConfig.dev);
4792
+ return withHandshake(withDefaults(DEFAULT_CONFIG, userConfig, DEFAULT_CONFIG));
4793
+ }
4794
+ chunkMWMSFIWN_cjs.__name(resolveConfig, "resolveConfig");
4795
+ function resolveConfigUpdate(configured, update) {
4796
+ validateConfig(update);
4797
+ const base = update.apiKey === void 0 ? configured : withoutKeyHeader(configured);
4798
+ return withHandshake(withDefaults(base, update, DEFAULT_CONFIG));
4799
+ }
4800
+ chunkMWMSFIWN_cjs.__name(resolveConfigUpdate, "resolveConfigUpdate");
4801
+ function withConfiguredKey(configured, apiKey) {
4802
+ return { ...withoutKeyHeader(configured), apiKey };
4803
+ }
4804
+ chunkMWMSFIWN_cjs.__name(withConfiguredKey, "withConfiguredKey");
4805
+ function withoutKeyHeader(configured) {
4806
+ return { ...configured, headers: layerHeaders(configured.headers, { [API_KEY_HEADER]: null }) };
4807
+ }
4808
+ chunkMWMSFIWN_cjs.__name(withoutKeyHeader, "withoutKeyHeader");
4809
+ function withHandshake(configured) {
4810
+ const dev = resolveDevOverride(configured.dev);
4811
+ const merged = withDefaults(
4812
+ configured,
4813
+ dev.state === "active" ? { apiKey: dev.apiKey, dataset: dev.sandbox.datasetId } : {},
4814
+ DEFAULT_CONFIG
4815
+ );
4548
4816
  if (dev.state === "active") {
4549
- merged.apiKey = dev.apiKey;
4550
- merged.dataset = dev.sandbox.datasetId;
4551
4817
  if (!devOverrideNotified) {
4552
4818
  devOverrideNotified = true;
4553
4819
  console.info(
@@ -4565,30 +4831,67 @@ function resolveConfig(userConfig) {
4565
4831
  `[RelyIO] Your .relyio/dev.json could not be read (${dev.reason}) \u2014 ignoring it and using the configured dataset "${merged.dataset}". Run \`relyio dev\` to rewrite it.`
4566
4832
  );
4567
4833
  }
4568
- return { config: merged, sandbox: sandboxStateOf(dev) };
4834
+ return { config: merged, sandbox: sandboxStateOf(dev), configured };
4569
4835
  }
4570
- chunkMWMSFIWN_cjs.__name(resolveConfig, "resolveConfig");
4836
+ chunkMWMSFIWN_cjs.__name(withHandshake, "withHandshake");
4837
+ function withDefaults(base, given, defaults) {
4838
+ const merged = new Map(Object.entries(base));
4839
+ const givenValues = new Map(Object.entries(given ?? {}));
4840
+ const defaultValues = new Map(Object.entries(defaults));
4841
+ for (const key of /* @__PURE__ */ new Set([...merged.keys(), ...givenValues.keys()])) {
4842
+ const fallback = merged.get(key);
4843
+ const value = givenValues.get(key);
4844
+ const givenBag = isOptionBag(value) ? value : void 0;
4845
+ if (isOptionBag(fallback) && key === "headers") {
4846
+ merged.set(key, layerHeaders(fallback, givenBag));
4847
+ } else if (isOptionBag(fallback)) {
4848
+ const defaultBag = defaultValues.get(key);
4849
+ merged.set(key, withDefaults(fallback, givenBag, isOptionBag(defaultBag) ? defaultBag : {}));
4850
+ } else if (value === null) {
4851
+ if (defaultValues.has(key)) merged.set(key, defaultValues.get(key));
4852
+ else merged.delete(key);
4853
+ } else if (value !== void 0) {
4854
+ merged.set(key, value);
4855
+ }
4856
+ }
4857
+ return Object.fromEntries(merged);
4858
+ }
4859
+ chunkMWMSFIWN_cjs.__name(withDefaults, "withDefaults");
4860
+ function isOptionBag(value) {
4861
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4862
+ }
4863
+ chunkMWMSFIWN_cjs.__name(isOptionBag, "isOptionBag");
4571
4864
 
4572
4865
  // src/client/create-client.ts
4573
4866
  var API_VERSION_SEGMENT = "v1";
4574
4867
  var _TypedRelyIOClient = class _TypedRelyIOClient {
4575
4868
  constructor(config) {
4869
+ /**
4870
+ * The one HTTP client every sub-client sends through. `updateConfig()` and `setApiKey()` change it
4871
+ * in place rather than replacing it, so a sub-client taken before either sends through the change.
4872
+ */
4576
4873
  chunkMWMSFIWN_cjs.__publicField(this, "httpClient");
4577
4874
  chunkMWMSFIWN_cjs.__publicField(this, "config");
4875
+ /**
4876
+ * The configuration as `createClient()`, `setApiKey()` and `updateConfig()` gave it, before the
4877
+ * `relyio dev` handshake: what the next update is laid over, and what `withLocale()` starts from.
4878
+ */
4879
+ chunkMWMSFIWN_cjs.__publicField(this, "configured");
4578
4880
  chunkMWMSFIWN_cjs.__publicField(this, "_sandbox");
4579
- chunkMWMSFIWN_cjs.__publicField(this, "_search");
4580
- chunkMWMSFIWN_cjs.__publicField(this, "_batch");
4581
- chunkMWMSFIWN_cjs.__publicField(this, "_adhocQuery");
4582
4881
  chunkMWMSFIWN_cjs.__publicField(this, "_schema");
4882
+ /**
4883
+ * The client's locale as it is when a call is made. Every sub-client and builder is handed this
4884
+ * rather than a copy of the locale, so one taken before `updateConfig({ locale })` sends the new
4885
+ * locale, or none after `locale: null` (REL-1453).
4886
+ */
4887
+ chunkMWMSFIWN_cjs.__publicField(this, "currentLocale", /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => this.config.locale, "currentLocale"));
4583
4888
  const { schema, ...clientConfig } = config;
4584
4889
  this._schema = schema;
4585
4890
  const resolved = resolveConfig(clientConfig);
4586
4891
  this.config = resolved.config;
4892
+ this.configured = resolved.configured;
4587
4893
  this._sandbox = resolved.sandbox;
4588
4894
  this.httpClient = new HttpClient(this.config);
4589
- this._search = new SearchClient(this.httpClient, this.config.locale);
4590
- this._batch = new BatchClient(this.httpClient);
4591
- this._adhocQuery = new AdhocQueryClient(this.httpClient, this.config.locale);
4592
4895
  }
4593
4896
  // ============================================================================
4594
4897
  // CORE CLIENTS
@@ -4617,10 +4920,10 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4617
4920
  return this._sandbox;
4618
4921
  }
4619
4922
  /**
4620
- * Get the ad-hoc query client
4923
+ * Get the ad-hoc query client. Every query it sends is in the client's locale as it is then.
4621
4924
  */
4622
4925
  get query() {
4623
- return this._adhocQuery;
4926
+ return new AdhocQueryClient(this.httpClient, this.currentLocale);
4624
4927
  }
4625
4928
  // ============================================================================
4626
4929
  // CONTENT OPERATIONS
@@ -4640,7 +4943,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4640
4943
  * ```
4641
4944
  */
4642
4945
  content(contentType) {
4643
- return new ContentClient(this.httpClient, contentType, this.config.locale);
4946
+ return new ContentClient(this.httpClient, contentType, this.currentLocale);
4644
4947
  }
4645
4948
  /**
4646
4949
  * Get an asset client for a specific asset type.
@@ -4661,7 +4964,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4661
4964
  * ```
4662
4965
  */
4663
4966
  asset(assetType) {
4664
- return new AssetClient(this.httpClient, assetType, this.config.locale);
4967
+ return new AssetClient(this.httpClient, assetType, this.currentLocale);
4665
4968
  }
4666
4969
  /**
4667
4970
  * Get a singleton client for a specific singleton key
@@ -4676,7 +4979,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4676
4979
  * ```
4677
4980
  */
4678
4981
  singleton(key) {
4679
- return new SingletonClient(this.httpClient, key, this.config.locale);
4982
+ return new SingletonClient(this.httpClient, key, this.currentLocale);
4680
4983
  }
4681
4984
  /**
4682
4985
  * Get a settings client for a specific settings group
@@ -4690,7 +4993,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4690
4993
  * ```
4691
4994
  */
4692
4995
  settings(groupId) {
4693
- return new SettingsClient(this.httpClient, groupId, this.config.locale);
4996
+ return new SettingsClient(this.httpClient, groupId, this.currentLocale);
4694
4997
  }
4695
4998
  // ============================================================================
4696
4999
  // SEARCH OPERATIONS
@@ -4712,7 +5015,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4712
5015
  * ```
4713
5016
  */
4714
5017
  search(query) {
4715
- return this._search.search(query);
5018
+ return this.searchClient().search(query);
4716
5019
  }
4717
5020
  /**
4718
5021
  * Start an autocomplete query for search suggestions
@@ -4728,7 +5031,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4728
5031
  * ```
4729
5032
  */
4730
5033
  autocomplete(query) {
4731
- return this._search.autocomplete(query);
5034
+ return this.searchClient().autocomplete(query);
4732
5035
  }
4733
5036
  /**
4734
5037
  * Find content similar to a given entry using vector search
@@ -4743,13 +5046,17 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4743
5046
  * ```
4744
5047
  */
4745
5048
  similar(sourceId) {
4746
- return this._search.similar(sourceId);
5049
+ return this.searchClient().similar(sourceId);
4747
5050
  }
4748
5051
  // ============================================================================
4749
5052
  // BATCH OPERATIONS
4750
5053
  // ============================================================================
4751
5054
  /**
4752
- * Start a batch operation for bulk create/update/delete
5055
+ * Start a batch operation for bulk create/update/delete.
5056
+ *
5057
+ * By default each operation lands or fails on its own. `atomic: true` makes the batch one
5058
+ * transaction, which the API accepts only when every operation is the same kind of write and none
5059
+ * writes a singleton that does not exist yet.
4753
5060
  *
4754
5061
  * @example
4755
5062
  * ```typescript
@@ -4758,13 +5065,23 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4758
5065
  * .update('product', 'entry_abc', { content: { price: 899 } })
4759
5066
  * .delete('product', 'entry_xyz')
4760
5067
  * .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
4761
- * .execute({ atomic: true })
5068
+ * .execute()
4762
5069
  *
4763
5070
  * console.log(result.summary.succeeded)
5071
+ *
5072
+ * // All or nothing: one kind of write
5073
+ * await relyio.batch()
5074
+ * .update('product', 'entry_abc', { content: { price: 899 } })
5075
+ * .update('product', 'entry_def', { content: { price: 799 } })
5076
+ * .execute({ atomic: true })
4764
5077
  * ```
4765
5078
  */
4766
5079
  batch() {
4767
- return this._batch.create();
5080
+ return new BatchClient(this.httpClient, this.currentLocale).create();
5081
+ }
5082
+ /** The search client, whose builders send the client's locale as it is when each one is sent. */
5083
+ searchClient() {
5084
+ return new SearchClient(this.httpClient, this.currentLocale);
4768
5085
  }
4769
5086
  // ============================================================================
4770
5087
  // CHANGES FEED
@@ -4838,7 +5155,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4838
5155
  * ```
4839
5156
  */
4840
5157
  adhoc() {
4841
- return this._adhocQuery.build();
5158
+ return this.query.build();
4842
5159
  }
4843
5160
  /**
4844
5161
  * Execute a predefined query by name (from schema)
@@ -4923,16 +5240,53 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4923
5240
  }
4924
5241
  }
4925
5242
  /**
4926
- * Update the configuration and reinitialize all clients
5243
+ * Change some of the client's options and keep the rest.
5244
+ *
5245
+ * What you pass is laid over the configuration the client holds, field by field:
5246
+ *
5247
+ * - an option you name replaces the value the client holds;
5248
+ * - an option left out, or given as `undefined`, keeps the value the client holds;
5249
+ * - an option with no default given as `null` is cleared — `locale`, `dataset`, `apiKey`, `dev`,
5250
+ * `fetch`, `browser.onCorsError`, `realtime.wsUrl`, `debug.logger` — so the client runs as though
5251
+ * it had never been given one. An option with a default takes no `null`;
5252
+ * - a bag of options you name — `browser`, `cache`, `realtime`, `debug` — keeps every field of it
5253
+ * you do not name, so `updateConfig({ browser: { includeCredentials: true } })` keeps a
5254
+ * configured `onCorsError`;
5255
+ * - `headers` is laid over the headers the client sends, a name matched without regard to case: a
5256
+ * header you name is added or replaces every spelling of it, every other one is still sent, and a
5257
+ * header given as `null` is no longer sent;
5258
+ * - naming `apiKey` — a key, or `null` — replaces every key the client holds, one given in
5259
+ * `headers` included.
5260
+ *
5261
+ * The configuration it is laid over is what `createClient()`, `setApiKey()` and earlier updates
5262
+ * gave the client. The `relyio dev` handshake is read again, as `createClient()` reads it: while a
5263
+ * sandbox is active its key and dataset are sent over the configured ones, and once it has gone
5264
+ * the configured ones are.
5265
+ *
5266
+ * The client's one HTTP client is changed in place, so every request from now on is sent as the
5267
+ * update says — including one from a `content()`, `asset()`, `singleton()` or `settings()`
5268
+ * sub-client, a `query` client, or a builder such as `search()` or `batch()`, taken before the
5269
+ * call. The locale reaches them too: each reads the client's locale when it sends, so a new
5270
+ * `locale` is the default of its next request and `locale: null` leaves that request with none. A
5271
+ * locale the call names, and a sub-client's own `withLocale()`, still win over it. A client made
5272
+ * by `withLocale()` is a client of its own: an update of this one does not reach it.
5273
+ *
5274
+ * @example
5275
+ * ```typescript
5276
+ * const relyio = createClient({ apiKey, headers: { 'X-Tenant': 'acme' }, browser: { onCorsError } })
5277
+ *
5278
+ * relyio.updateConfig({ headers: { 'X-Trace': traceId } }) // X-Tenant is still sent
5279
+ * relyio.updateConfig({ browser: { includeCredentials: true } }) // onCorsError is kept
5280
+ * relyio.updateConfig({ headers: { 'X-Tenant': null } }) // X-Tenant is no longer sent
5281
+ * relyio.updateConfig({ locale: null }) // reads name no locale of the client's
5282
+ * ```
4927
5283
  */
4928
- updateConfig(newConfig) {
4929
- const resolved = resolveConfig({ ...this.config, ...newConfig });
5284
+ updateConfig(update) {
5285
+ const resolved = resolveConfigUpdate(this.configured, update);
4930
5286
  this.config = resolved.config;
5287
+ this.configured = resolved.configured;
4931
5288
  this._sandbox = resolved.sandbox;
4932
- this.httpClient = new HttpClient(this.config);
4933
- this._search = new SearchClient(this.httpClient, this.config.locale);
4934
- this._batch = new BatchClient(this.httpClient);
4935
- this._adhocQuery = new AdhocQueryClient(this.httpClient, this.config.locale);
5289
+ this.httpClient.configure(this.config);
4936
5290
  }
4937
5291
  /**
4938
5292
  * Get the current configuration
@@ -4941,11 +5295,31 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4941
5295
  return { ...this.config };
4942
5296
  }
4943
5297
  /**
4944
- * Set the API key
5298
+ * Replace the API key every later request sends as `X-API-Key`.
5299
+ *
5300
+ * It reaches every request this client makes from now on, including those of a `content()`,
5301
+ * `asset()` or other sub-client taken before the call, and `getConfig().apiKey` reports it. A key
5302
+ * given in `headers`, under any spelling, is replaced with it and does not come back on a later
5303
+ * `updateConfig()`. A client already derived with `withLocale()` is a client of its own and keeps
5304
+ * its key.
5305
+ *
5306
+ * An empty or blank key is no key, as it is when passed to `createClient`: the next request
5307
+ * rejects with `MissingApiKeyError` and nothing is sent.
5308
+ *
5309
+ * Under an active `relyio dev` sandbox the sandbox's scoped key stands, as it does over the key
5310
+ * passed to `createClient` — replacing the configured key does not retarget the client at the
5311
+ * sandbox's dataset with a key the sandbox did not issue.
5312
+ *
5313
+ * @example
5314
+ * ```typescript
5315
+ * const relyio = createClient({ apiKey: process.env.RELYIO_API_KEY! })
5316
+ * relyio.setApiKey(rotatedKey) // the next read sends `X-API-Key: <rotatedKey>`
5317
+ * ```
4945
5318
  */
4946
5319
  setApiKey(apiKey) {
4947
- this.config.apiKey = apiKey;
4948
- this.httpClient.setAuthToken(apiKey);
5320
+ this.configured = withConfiguredKey(this.configured, apiKey);
5321
+ if (this._sandbox.state === "active") return;
5322
+ this.httpClient.setApiKey(apiKey);
4949
5323
  }
4950
5324
  /**
4951
5325
  * Get the HTTP client instance (for advanced usage)
@@ -4959,9 +5333,12 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4959
5333
  /**
4960
5334
  * Create a locale-scoped client
4961
5335
  *
4962
- * Every read the returned client builds — `content()`, `asset()`, `singleton()`, `settings()`,
4963
- * `search()`, `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — is in this
4964
- * locale unless the call names one of its own, which wins.
5336
+ * Every call the returned client builds is in this locale unless the call names one of its own,
5337
+ * which wins: every read — `content()`, `asset()`, `singleton()`, `settings()`, `search()`,
5338
+ * `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — and every write and
5339
+ * version-history read — `create()` and `update()`, the singleton and settings writes, the asset
5340
+ * file writes, `versions()` and `version()`, and each operation `batch()` builds. `restore()`
5341
+ * always names its locale; a delete, and a `batch().raw()` operation, carry none of the client's.
4965
5342
  *
4966
5343
  * Type-safe when schema is provided: autocompletes valid locale codes!
4967
5344
  *
@@ -4969,10 +5346,11 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4969
5346
  * ```typescript
4970
5347
  * const spanish = relyio.withLocale('es-ES') // ← Autocompletes with schema!
4971
5348
  *
4972
- * // Reads use Spanish
5349
+ * // Reads and writes use Spanish
4973
5350
  * const products = await spanish.content('product').query().execute()
4974
5351
  * const homepage = await spanish.singleton('homepage').fetch()
4975
5352
  * const results = await spanish.search('zapatos').execute()
5353
+ * await spanish.content('product').update(id, { title: 'Zapatos' })
4976
5354
  *
4977
5355
  * // Original client unchanged
4978
5356
  * const englishProducts = await relyio.content('product').query().execute()
@@ -4980,7 +5358,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4980
5358
  */
4981
5359
  withLocale(locale) {
4982
5360
  const newConfig = {
4983
- ...this.getConfig(),
5361
+ ...this.configured,
4984
5362
  locale,
4985
5363
  schema: this._schema
4986
5364
  };
@@ -5034,7 +5412,6 @@ exports.AdhocQueryClient = AdhocQueryClient;
5034
5412
  exports.AssetClient = AssetClient;
5035
5413
  exports.AssetFileBuilder = AssetFileBuilder;
5036
5414
  exports.AssetUploadBuilder = AssetUploadBuilder;
5037
- exports.AuthenticationError = AuthenticationError;
5038
5415
  exports.AuthorizationError = AuthorizationError;
5039
5416
  exports.AutocompleteBuilder = AutocompleteBuilder;
5040
5417
  exports.BaseValidationError = BaseValidationError;
@@ -5050,7 +5427,6 @@ exports.FileUploadError = FileUploadError;
5050
5427
  exports.FileValidationError = FileValidationError;
5051
5428
  exports.HttpClient = HttpClient;
5052
5429
  exports.InvalidApiKeyError = InvalidApiKeyError;
5053
- exports.InvalidFieldTypeError = InvalidFieldTypeError;
5054
5430
  exports.InvalidPayloadError = InvalidPayloadError;
5055
5431
  exports.MethodNotAllowedError = MethodNotAllowedError;
5056
5432
  exports.MissingApiKeyError = MissingApiKeyError;
@@ -5059,12 +5435,10 @@ exports.PayloadTooLargeError = PayloadTooLargeError;
5059
5435
  exports.PlanFeatureUnavailableError = PlanFeatureUnavailableError;
5060
5436
  exports.RateLimitError = RateLimitError;
5061
5437
  exports.ReadOnlyKeyError = ReadOnlyKeyError;
5062
- exports.RequiredFieldError = RequiredFieldError;
5063
5438
  exports.ResourceConflictError = ResourceConflictError;
5064
5439
  exports.ResourceExpiredError = ResourceExpiredError;
5065
5440
  exports.ResourceNotFoundError = ResourceNotFoundError;
5066
5441
  exports.SDKError = SDKError;
5067
- exports.SchemaValidationError = SchemaValidationError;
5068
5442
  exports.SearchBuilder = SearchBuilder;
5069
5443
  exports.SearchClient = SearchClient;
5070
5444
  exports.ServerError = ServerError;
@@ -5087,5 +5461,5 @@ exports.matchRoute = matchRoute;
5087
5461
  exports.serviceInstructedDelayMs = serviceInstructedDelayMs;
5088
5462
  exports.sleep = sleep;
5089
5463
  exports.validateFile = validateFile;
5090
- //# sourceMappingURL=chunk-GCMQUM6N.cjs.map
5091
- //# sourceMappingURL=chunk-GCMQUM6N.cjs.map
5464
+ //# sourceMappingURL=chunk-VH2DE7HZ.cjs.map
5465
+ //# sourceMappingURL=chunk-VH2DE7HZ.cjs.map