@relyio/sdk 0.5.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 +540 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-HAQELDZN.cjs → chunk-72UK5U7T.cjs} +70 -60
  4. package/dist/{chunk-5AZUUV5B.js → chunk-GYHAVYND.js} +1086 -494
  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-CIRT6TVT.cjs → chunk-VH2DE7HZ.cjs} +1088 -497
  8. package/dist/{chunk-XY5KFEFY.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-C5mRBb6t.d.cts → define-content-type-DiVpbwNs.d.cts} +1629 -665
  14. package/dist/{index-mXUx2H99.d.ts → define-content-type-DiVpbwNs.d.ts} +1629 -665
  15. package/dist/{define-schema-DzYXk4HL.d.ts → define-schema-C-5an28C.d.ts} +211 -429
  16. package/dist/{define-schema-2xbHgtK-.d.cts → define-schema-D7MButVt.d.cts} +211 -429
  17. package/dist/{index-Dzo-upNS.d.ts → index-1G97sNA8.d.ts} +677 -296
  18. package/dist/index-BOQIHnsh.d.ts +818 -0
  19. package/dist/index-DbsTUw3Q.d.cts +818 -0
  20. package/dist/{index-BozPz4n1.d.cts → index-M0X45k7J.d.cts} +677 -296
  21. package/dist/index.cjs +180 -103
  22. package/dist/index.d.cts +307 -32
  23. package/dist/index.d.ts +307 -32
  24. package/dist/index.js +95 -8
  25. package/dist/schema/index.cjs +35 -35
  26. package/dist/schema/index.d.cts +21 -15
  27. package/dist/schema/index.d.ts +21 -15
  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-CBfnTWSS.d.cts +0 -716
  37. package/dist/define-content-type-CBfnTWSS.d.ts +0 -716
@@ -1,4 +1,5 @@
1
1
  import { parseDevEnv, DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME, parseDevContextFile } from './chunk-BBUB7C2Z.js';
2
+ import { isBrowser } from './chunk-H6IBQSMM.js';
2
3
  import { __name, __publicField } from './chunk-XQ4QHWZE.js';
3
4
 
4
5
  /* RelyIO SDK - Built with ❤️ by the RelyIO Team */
@@ -69,44 +70,6 @@ var _SDKError = class _SDKError extends Error {
69
70
  __name(_SDKError, "SDKError");
70
71
  var SDKError = _SDKError;
71
72
 
72
- // src/errors/auth-errors.ts
73
- var _AuthenticationError = class _AuthenticationError extends SDKError {
74
- constructor(message = "Authentication failed", statusCode = 401, cause, context) {
75
- super(message, statusCode, cause, context);
76
- __publicField(this, "code", "AUTHENTICATION_ERROR");
77
- __publicField(this, "retryable", false);
78
- }
79
- getUserMessage() {
80
- return "Authentication failed. Please check your API key and try again.";
81
- }
82
- };
83
- __name(_AuthenticationError, "AuthenticationError");
84
- var AuthenticationError = _AuthenticationError;
85
- var _AuthorizationError = class _AuthorizationError extends SDKError {
86
- constructor(message = "Authorization failed", statusCode = 403, cause, context) {
87
- super(message, statusCode, cause, context);
88
- __publicField(this, "code", "AUTHORIZATION_ERROR");
89
- __publicField(this, "retryable", false);
90
- }
91
- getUserMessage() {
92
- return "You do not have permission to access this resource.";
93
- }
94
- };
95
- __name(_AuthorizationError, "AuthorizationError");
96
- var AuthorizationError = _AuthorizationError;
97
- var _InvalidApiKeyError = class _InvalidApiKeyError extends SDKError {
98
- constructor(message = "Invalid API key", cause, context) {
99
- super(message, 401, cause, context);
100
- __publicField(this, "code", "INVALID_API_KEY");
101
- __publicField(this, "retryable", false);
102
- }
103
- getUserMessage() {
104
- return "Invalid API key. Please check your API key and try again.";
105
- }
106
- };
107
- __name(_InvalidApiKeyError, "InvalidApiKeyError");
108
- var InvalidApiKeyError = _InvalidApiKeyError;
109
-
110
73
  // src/errors/contract-errors.ts
111
74
  var _MissingApiKeyError = class _MissingApiKeyError extends SDKError {
112
75
  constructor(message = "No API key was sent", context) {
@@ -267,6 +230,32 @@ var _UnknownContractError = class _UnknownContractError extends SDKError {
267
230
  __name(_UnknownContractError, "UnknownContractError");
268
231
  var UnknownContractError = _UnknownContractError;
269
232
 
233
+ // src/errors/auth-errors.ts
234
+ var _AuthorizationError = class _AuthorizationError extends SDKError {
235
+ constructor(message = "Authorization failed", statusCode = 403, cause, context) {
236
+ super(message, statusCode, cause, context);
237
+ __publicField(this, "code", "AUTHORIZATION_ERROR");
238
+ __publicField(this, "retryable", false);
239
+ }
240
+ getUserMessage() {
241
+ return "You do not have permission to access this resource.";
242
+ }
243
+ };
244
+ __name(_AuthorizationError, "AuthorizationError");
245
+ var AuthorizationError = _AuthorizationError;
246
+ var _InvalidApiKeyError = class _InvalidApiKeyError extends SDKError {
247
+ constructor(message = "Invalid API key", cause, context) {
248
+ super(message, 401, cause, context);
249
+ __publicField(this, "code", "INVALID_API_KEY");
250
+ __publicField(this, "retryable", false);
251
+ }
252
+ getUserMessage() {
253
+ return "Invalid API key. Please check your API key and try again.";
254
+ }
255
+ };
256
+ __name(_InvalidApiKeyError, "InvalidApiKeyError");
257
+ var InvalidApiKeyError = _InvalidApiKeyError;
258
+
270
259
  // src/errors/content-errors.ts
271
260
  var _ResourceNotFoundError = class _ResourceNotFoundError extends SDKError {
272
261
  constructor(message = "Resource not found", statusCode = 404, cause, context) {
@@ -328,8 +317,12 @@ var _NetworkError = class _NetworkError extends SDKError {
328
317
  __name(_NetworkError, "NetworkError");
329
318
  var NetworkError = _NetworkError;
330
319
  var _TimeoutError = class _TimeoutError extends SDKError {
331
- constructor(message = "Request timed out", timeout, statusCode, cause) {
332
- super(message, statusCode, cause, { timeout });
320
+ /**
321
+ * @param context - Carried beside `timeout`. The mapper passes a `REQUEST_TIMEOUT` refusal's body
322
+ * as `context.response`, as it does for every other contract code.
323
+ */
324
+ constructor(message = "Request timed out", timeout, statusCode, cause, context) {
325
+ super(message, statusCode, cause, { ...context, timeout });
333
326
  __publicField(this, "code", "TIMEOUT_ERROR");
334
327
  __publicField(this, "retryable", true);
335
328
  }
@@ -355,8 +348,13 @@ var ConnectionError = _ConnectionError;
355
348
 
356
349
  // src/errors/validation-errors.ts
357
350
  var _BaseValidationError = class _BaseValidationError extends SDKError {
358
- constructor(message = "Validation failed", violations = [], statusCode = 400, cause) {
359
- super(message, statusCode, cause, { violations });
351
+ /**
352
+ * @param context - Carried beside `violations`. The mapper passes the refusal body as
353
+ * `context.response`, as it does for every other contract code, so a consumer that hands the
354
+ * service's own words on can read them here too.
355
+ */
356
+ constructor(message = "Validation failed", violations = [], statusCode = 400, cause, context) {
357
+ super(message, statusCode, cause, { ...context, violations });
360
358
  __publicField(this, "retryable", false);
361
359
  __publicField(this, "violations");
362
360
  this.violations = violations;
@@ -401,8 +399,8 @@ var _ValidationError = class _ValidationError extends BaseValidationError {
401
399
  __name(_ValidationError, "ValidationError");
402
400
  var ValidationError = _ValidationError;
403
401
  var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationError {
404
- constructor(message = "Invalid payload", violations = [], cause) {
405
- super(message, violations, 400, cause);
402
+ constructor(message = "Invalid payload", violations = [], cause, context) {
403
+ super(message, violations, 400, cause, context);
406
404
  __publicField(this, "code", "INVALID_PAYLOAD");
407
405
  }
408
406
  getUserMessage() {
@@ -411,58 +409,6 @@ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationErro
411
409
  };
412
410
  __name(_InvalidPayloadError, "InvalidPayloadError");
413
411
  var InvalidPayloadError = _InvalidPayloadError;
414
- var _SchemaValidationError = class _SchemaValidationError extends BaseValidationError {
415
- constructor(message = "Schema validation failed", violations = [], cause) {
416
- super(message, violations, 400, cause);
417
- __publicField(this, "code", "SCHEMA_VALIDATION_ERROR");
418
- }
419
- getUserMessage() {
420
- return "The data does not match the expected schema. Please check your content structure.";
421
- }
422
- };
423
- __name(_SchemaValidationError, "SchemaValidationError");
424
- var SchemaValidationError = _SchemaValidationError;
425
- var _RequiredFieldError = class _RequiredFieldError extends BaseValidationError {
426
- constructor(fieldName, message, cause) {
427
- const violation = {
428
- field: fieldName,
429
- message: message ?? `Field "${fieldName}" is required`,
430
- code: "REQUIRED"
431
- };
432
- super(`Required field "${fieldName}" is missing`, [violation], 400, cause);
433
- __publicField(this, "code", "REQUIRED_FIELD_ERROR");
434
- }
435
- getUserMessage() {
436
- const violation = this.violations[0];
437
- const fieldName = violation?.field;
438
- return `The field "${fieldName}" is required and cannot be empty.`;
439
- }
440
- };
441
- __name(_RequiredFieldError, "RequiredFieldError");
442
- var RequiredFieldError = _RequiredFieldError;
443
- var _InvalidFieldTypeError = class _InvalidFieldTypeError extends BaseValidationError {
444
- constructor(fieldName, expectedType, actualType, value, cause) {
445
- const violation = {
446
- field: fieldName,
447
- message: `Expected ${expectedType}, got ${actualType}`,
448
- code: "INVALID_TYPE",
449
- value
450
- };
451
- super(
452
- `Invalid type for field "${fieldName}": expected ${expectedType}, got ${actualType}`,
453
- [violation],
454
- 400,
455
- cause
456
- );
457
- __publicField(this, "code", "INVALID_FIELD_TYPE");
458
- }
459
- getUserMessage() {
460
- const violation = this.violations[0];
461
- return `The field "${violation?.field}" has an invalid type. ${violation?.message}.`;
462
- }
463
- };
464
- __name(_InvalidFieldTypeError, "InvalidFieldTypeError");
465
- var InvalidFieldTypeError = _InvalidFieldTypeError;
466
412
 
467
413
  // ../../platform/api-contract/dist/index.js
468
414
  var HEADER_RETRY_AFTER = { name: "Retry-After" };
@@ -591,10 +537,10 @@ var _ErrorMapper = class _ErrorMapper {
591
537
  );
592
538
  }
593
539
  case "REQUEST_INVALID": {
594
- return new InvalidPayloadError(message, violationsOf(refusal));
540
+ return new InvalidPayloadError(message, violationsOf(refusal), void 0, context);
595
541
  }
596
542
  case "CONTENT_INVALID": {
597
- return new ValidationError(message, violationsOf(refusal), 400);
543
+ return new ValidationError(message, violationsOf(refusal), 400, void 0, context);
598
544
  }
599
545
  case "METHOD_NOT_ALLOWED": {
600
546
  return new MethodNotAllowedError(message, context);
@@ -617,7 +563,7 @@ var _ErrorMapper = class _ErrorMapper {
617
563
  return new ResourceExpiredError(message, 410, void 0, context);
618
564
  }
619
565
  case "REQUEST_TIMEOUT": {
620
- return new TimeoutError(message, void 0, void 0, void 0);
566
+ return new TimeoutError(message, void 0, status, void 0, context);
621
567
  }
622
568
  case "PAYLOAD_TOO_LARGE": {
623
569
  return new PayloadTooLargeError(message, detailNumber(refusal, "limitBytes"), context);
@@ -840,20 +786,43 @@ function readQuery(searchParams) {
840
786
  }
841
787
  __name(readQuery, "readQuery");
842
788
 
843
- // src/http/retry-policy.ts
844
- var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
845
- "GET",
846
- "HEAD",
847
- "OPTIONS",
848
- "PUT",
849
- "DELETE",
850
- "TRACE"
851
- ]);
852
- function isReplaySafe(request) {
853
- if (IDEMPOTENT_METHODS.has(request.method.toUpperCase())) return true;
854
- return headerValue(request.headers, HEADER_IDEMPOTENCY_KEY.name) !== void 0;
789
+ // src/http/abortable-sleep.ts
790
+ function sleep(ms, signal) {
791
+ return new Promise((resolve) => {
792
+ if (isAborted(signal)) {
793
+ resolve();
794
+ return;
795
+ }
796
+ const done = /* @__PURE__ */ __name(() => {
797
+ clearTimeout(timer);
798
+ signal?.removeEventListener("abort", done);
799
+ resolve();
800
+ }, "done");
801
+ const timer = setTimeout(done, ms);
802
+ signal?.addEventListener("abort", done, { once: true });
803
+ });
855
804
  }
856
- __name(isReplaySafe, "isReplaySafe");
805
+ __name(sleep, "sleep");
806
+ function isAborted(signal) {
807
+ return signal?.aborted === true;
808
+ }
809
+ __name(isAborted, "isAborted");
810
+
811
+ // src/http/request-timeout.ts
812
+ var MAX_TIMER_DELAY_MS = 2147483647;
813
+ function isTimerDelay(value) {
814
+ return typeof value === "number" && value >= 1 && value <= MAX_TIMER_DELAY_MS;
815
+ }
816
+ __name(isTimerDelay, "isTimerDelay");
817
+ function assertRequestTimeout(timeout) {
818
+ if (isTimerDelay(timeout)) return;
819
+ throw new Error(
820
+ `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)}`
821
+ );
822
+ }
823
+ __name(assertRequestTimeout, "assertRequestTimeout");
824
+
825
+ // src/errors/instructed-delay.ts
857
826
  function serviceInstructedDelayMs(error, nowMs) {
858
827
  if (error instanceof ServiceIndeterminateError) {
859
828
  return error.retryAfterMs;
@@ -867,6 +836,21 @@ function serviceInstructedDelayMs(error, nowMs) {
867
836
  return wait > 0 ? wait : void 0;
868
837
  }
869
838
  __name(serviceInstructedDelayMs, "serviceInstructedDelayMs");
839
+
840
+ // src/http/retry-policy.ts
841
+ var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
842
+ "GET",
843
+ "HEAD",
844
+ "OPTIONS",
845
+ "PUT",
846
+ "DELETE",
847
+ "TRACE"
848
+ ]);
849
+ function isReplaySafe(request) {
850
+ if (IDEMPOTENT_METHODS.has(request.method.toUpperCase())) return true;
851
+ return headerValue(request.headers, HEADER_IDEMPOTENCY_KEY.name) !== void 0;
852
+ }
853
+ __name(isReplaySafe, "isReplaySafe");
870
854
  var _DefaultRetryPolicy = class _DefaultRetryPolicy {
871
855
  constructor(config) {
872
856
  __publicField(this, "config");
@@ -891,42 +875,31 @@ var DefaultRetryPolicy = _DefaultRetryPolicy;
891
875
  // src/http/http-client.ts
892
876
  var _HttpClient = class _HttpClient {
893
877
  constructor(config) {
894
- __publicField(this, "baseUrl");
895
- __publicField(this, "defaultHeaders");
896
- __publicField(this, "timeout");
897
- __publicField(this, "retryPolicy");
898
- __publicField(this, "debug");
899
- __publicField(this, "logger");
900
- __publicField(this, "config");
901
- this.config = config;
902
- this.baseUrl = config.baseUrl;
903
- this.timeout = config.timeout;
904
- this.debug = config.debug.enabled ?? false;
905
- this.logger = config.debug.logger;
906
- this.defaultHeaders = {
907
- "Content-Type": "application/json",
908
- "X-API-Key": config.apiKey,
909
- ...config.headers
910
- };
911
- if (config.dataset != null) {
912
- this.defaultHeaders["X-RelyIO-Dataset"] = config.dataset;
913
- }
914
- if (typeof window === "undefined") {
915
- const globalWithVersion = globalThis;
916
- this.defaultHeaders["User-Agent"] = `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`;
917
- }
918
- this.retryPolicy = new DefaultRetryPolicy({
919
- maxAttempts: config.retryAttempts,
920
- baseDelay: 1e3,
921
- maxDelay: 1e4,
922
- backoffFactor: 2,
923
- jitter: true
924
- });
878
+ /** What every request reads off the configuration, derived by {@link configure} and nowhere else. */
879
+ __publicField(this, "connection");
880
+ this.connection = connectionFor(config);
881
+ this.announce();
882
+ }
883
+ /**
884
+ * Run on `config` from now on: every later request — whoever holds this client — is sent to its
885
+ * `baseUrl`, with its headers, key and dataset, its timeout and retries, through its `fetch`, and
886
+ * logged by its `debug` options.
887
+ *
888
+ * The client's own `updateConfig()` calls this rather than building a second client, so a
889
+ * `content()` or other sub-client taken before the update sends through the update too. Anything
890
+ * set on this client since it was last configured — `setDefaultHeaders()`, `setBaseUrl()` — is
891
+ * replaced by what `config` says.
892
+ */
893
+ configure(config) {
894
+ this.connection = connectionFor(config);
895
+ this.announce();
896
+ }
897
+ announce() {
925
898
  this.log("debug", "HttpClient initialized", {
926
- baseUrl: this.baseUrl,
927
- timeout: this.timeout,
928
- retryAttempts: config.retryAttempts,
929
- environment: typeof window === "undefined" ? "node" : "browser"
899
+ baseUrl: this.connection.baseUrl,
900
+ timeout: this.connection.timeout,
901
+ retryAttempts: this.connection.config.retryAttempts,
902
+ environment: isBrowser() ? "browser" : "node"
930
903
  });
931
904
  }
932
905
  /**
@@ -963,17 +936,34 @@ var _HttpClient = class _HttpClient {
963
936
  *
964
937
  * The loop always makes one attempt. The incumbent's `while (attempt <
965
938
  * maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
966
- * accepts — and then dereferenced an unassigned `lastError`.
939
+ * then accepted, and now refuses — and then dereferenced an unassigned
940
+ * `lastError`. `retryAttempts` is the most attempts, the first included; an
941
+ * `HttpClient` constructed directly is not validated, so the first attempt
942
+ * stays unconditional.
943
+ *
944
+ * A request that would carry no `X-API-Key` makes none: it rejects with
945
+ * `MissingApiKeyError` before `fetch` is called, is not retried, and names
946
+ * `apiKey`. This is where a client built without a key learns it — the
947
+ * constructor accepts one so that a module-scope client can be evaluated by a
948
+ * build that holds no key (REL-1120) — and so does one whose `setApiKey` was
949
+ * given none.
967
950
  */
968
951
  async request(config) {
952
+ if (config.timeout !== void 0) assertRequestTimeout(config.timeout);
969
953
  const mergedConfig = this.mergeRequestConfig(config);
954
+ if (presentKey(headerValue(mergedConfig.headers, API_KEY_HEADER)) === void 0) {
955
+ throw new MissingApiKeyError(
956
+ "`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.",
957
+ { url: mergedConfig.url, method: mergedConfig.method, sent: false }
958
+ );
959
+ }
970
960
  this.log("debug", "Making request", {
971
961
  method: mergedConfig.method,
972
962
  url: mergedConfig.url
973
963
  // Show the final URL with query params
974
964
  });
975
965
  if (config.method === "DELETE" && mergedConfig.headers) {
976
- delete mergedConfig.headers["Content-Type"];
966
+ mergedConfig.headers = layerHeaders(mergedConfig.headers, { "Content-Type": null });
977
967
  }
978
968
  for (let attempt = 1; ; attempt++) {
979
969
  try {
@@ -992,10 +982,10 @@ var _HttpClient = class _HttpClient {
992
982
  attempt,
993
983
  url: mergedConfig.url
994
984
  });
995
- if (this.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
996
- const delay = this.retryPolicy.delayFor(attempt, failure);
985
+ if (this.connection.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
986
+ const delay = this.connection.retryPolicy.delayFor(attempt, failure);
997
987
  this.log("debug", "Retrying request", { attempt, delay });
998
- await this.sleep(delay, config.signal);
988
+ await sleep(delay, config.signal);
999
989
  continue;
1000
990
  }
1001
991
  const sdkError = ErrorMapper.mapGenericError(failure, {
@@ -1065,34 +1055,60 @@ var _HttpClient = class _HttpClient {
1065
1055
  });
1066
1056
  }
1067
1057
  /**
1068
- * Set default headers for all requests
1058
+ * Add headers to every later request, each replacing any header of the same name — the name
1059
+ * matched without regard to case — until the client is next configured.
1069
1060
  */
1070
1061
  setDefaultHeaders(headers) {
1071
- this.defaultHeaders = { ...this.defaultHeaders, ...headers };
1062
+ this.connection = {
1063
+ ...this.connection,
1064
+ defaultHeaders: layerHeaders(this.connection.defaultHeaders, headers)
1065
+ };
1072
1066
  }
1073
1067
  /**
1074
- * Set authentication token
1068
+ * Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
1069
+ * reports.
1070
+ *
1071
+ * The key is read the way construction reads it (`presentKey`): an absent, empty or blank key is
1072
+ * no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
1073
+ * before anything is sent. A key header of any other spelling — one given in `headers` — goes
1074
+ * too, from the headers sent and from the headers the configuration reports, so the old key is
1075
+ * never sent beside the new one.
1076
+ *
1077
+ * The configuration is the one the owning `TypedRelyIOClient` holds (it hands its own to the
1078
+ * constructor), so its `getConfig().apiKey` — what a surface reads to decide a key's kind — is the
1079
+ * key sent from here on.
1080
+ *
1081
+ * This replaced `setAuthToken`, which added `Authorization: Bearer` beside an `X-API-Key` it
1082
+ * never touched: the API reads `X-API-Key` first, so the old key was the one used (REL-1385).
1075
1083
  */
1076
- setAuthToken(token) {
1077
- this.defaultHeaders.Authorization = `Bearer ${token}`;
1084
+ setApiKey(apiKey) {
1085
+ const { config } = this.connection;
1086
+ config.apiKey = apiKey;
1087
+ config.headers = layerHeaders(config.headers, { [API_KEY_HEADER]: null });
1088
+ this.connection = {
1089
+ ...this.connection,
1090
+ defaultHeaders: layerHeaders(this.connection.defaultHeaders, {
1091
+ [API_KEY_HEADER]: presentKey(apiKey) ?? null
1092
+ })
1093
+ };
1078
1094
  }
1079
1095
  /**
1080
1096
  * Get current default headers
1081
1097
  */
1082
1098
  getDefaultHeaders() {
1083
- return { ...this.defaultHeaders };
1099
+ return { ...this.connection.defaultHeaders };
1084
1100
  }
1085
1101
  /**
1086
1102
  * Update base URL
1087
1103
  */
1088
1104
  setBaseUrl(baseUrl) {
1089
- this.baseUrl = baseUrl;
1105
+ this.connection = { ...this.connection, baseUrl };
1090
1106
  }
1091
1107
  /**
1092
1108
  * Get current base URL
1093
1109
  */
1094
1110
  getBaseUrl() {
1095
- return this.baseUrl;
1111
+ return this.connection.baseUrl;
1096
1112
  }
1097
1113
  /**
1098
1114
  * One attempt.
@@ -1114,7 +1130,7 @@ var _HttpClient = class _HttpClient {
1114
1130
  const timeoutId = setTimeout(() => {
1115
1131
  timedOut = true;
1116
1132
  controller.abort();
1117
- }, config.timeout ?? this.timeout);
1133
+ }, config.timeout ?? this.connection.timeout);
1118
1134
  const onCallerAbort = /* @__PURE__ */ __name(() => controller.abort(), "onCallerAbort");
1119
1135
  caller?.addEventListener("abort", onCallerAbort, { once: true });
1120
1136
  try {
@@ -1124,10 +1140,15 @@ var _HttpClient = class _HttpClient {
1124
1140
  headers: filteredHeaders,
1125
1141
  body: this.prepareRequestBody(config),
1126
1142
  signal: controller.signal,
1127
- // Include credentials for CORS requests if in browser and configured
1128
- ...typeof window !== "undefined" && this.config.browser.includeCredentials != null && { credentials: "include" }
1143
+ // Only in a browser — a `window` with a `document` (`isBrowser()`). A server or edge
1144
+ // runtime has no cookie jar for the mode to govern, so the field is left off and the
1145
+ // runtime's default stands; that includes Deno 1.x, whose global is a `window` with no
1146
+ // `document`. A Web Worker gets that default too: it has cookies but no `window`.
1147
+ ...isBrowser() && {
1148
+ credentials: credentialsModeFor(this.connection.config.browser.includeCredentials)
1149
+ }
1129
1150
  };
1130
- const send = this.config.fetch ?? globalThis.fetch;
1151
+ const send = this.connection.config.fetch ?? globalThis.fetch;
1131
1152
  const response = await send(url, requestInit);
1132
1153
  clearTimeout(timeoutId);
1133
1154
  const responseBody = await this.parseResponse(response);
@@ -1160,10 +1181,8 @@ var _HttpClient = class _HttpClient {
1160
1181
  }
1161
1182
  if (error instanceof DOMException && error.name === "AbortError") {
1162
1183
  if (!timedOut && isAborted(caller)) throw error;
1163
- throw new TimeoutError(
1164
- `Request timed out after ${config.timeout ?? this.timeout}ms`,
1165
- config.timeout ?? this.timeout
1166
- );
1184
+ const timeout = config.timeout ?? this.connection.timeout;
1185
+ throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
1167
1186
  }
1168
1187
  if (error instanceof TypeError && error.message.includes("CORS")) {
1169
1188
  const corsError = new NetworkError(
@@ -1177,9 +1196,10 @@ var _HttpClient = class _HttpClient {
1177
1196
  suggestion: "Check if the API server allows requests from your domain and has proper CORS headers configured."
1178
1197
  }
1179
1198
  );
1180
- if (typeof window !== "undefined" && this.config.browser.onCorsError) {
1199
+ const { onCorsError } = this.connection.config.browser;
1200
+ if (isBrowser() && onCorsError) {
1181
1201
  try {
1182
- this.config.browser.onCorsError(corsError, {
1202
+ onCorsError(corsError, {
1183
1203
  url: config.url,
1184
1204
  method: config.method,
1185
1205
  originalError: error
@@ -1196,20 +1216,20 @@ var _HttpClient = class _HttpClient {
1196
1216
  }
1197
1217
  }
1198
1218
  /**
1199
- * Filter headers that browsers don't allow to be set manually
1219
+ * The headers without those a browser controls itself, when this is a browser; unchanged when it
1220
+ * is not.
1221
+ *
1222
+ * A name is matched without regard to case (RFC 9110 §5.1), because a browser refuses `Origin`
1223
+ * whatever case a page spells it in. This matched only the all-lowercase and all-uppercase
1224
+ * spellings, so `Origin` and `User-Agent` — how people write them — reached `fetch` (REL-1409).
1200
1225
  */
1201
1226
  filterHeadersForBrowser(headers) {
1202
- if (typeof window !== "undefined") {
1203
- const filteredHeaders = { ...headers };
1204
- const forbiddenHeaders = ["user-agent", "referer", "origin", "host", "connection", "upgrade"];
1205
- forbiddenHeaders.forEach((header) => {
1206
- delete filteredHeaders[header];
1207
- delete filteredHeaders[header.toLowerCase()];
1208
- delete filteredHeaders[header.toUpperCase()];
1209
- });
1210
- return filteredHeaders;
1211
- }
1212
- return headers;
1227
+ if (!isBrowser()) return headers;
1228
+ return Object.fromEntries(
1229
+ Object.entries(headers).filter(
1230
+ ([name]) => !BROWSER_CONTROLLED_HEADERS.has(name.toLowerCase())
1231
+ )
1232
+ );
1213
1233
  }
1214
1234
  /**
1215
1235
  * Prepare request body based on content type and environment
@@ -1245,7 +1265,7 @@ var _HttpClient = class _HttpClient {
1245
1265
  if (url.startsWith("http://") || url.startsWith("https://")) {
1246
1266
  return url;
1247
1267
  }
1248
- return `${this.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
1268
+ return `${this.connection.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
1249
1269
  }
1250
1270
  mergeRequestConfig(config) {
1251
1271
  const url = this.resolveUrl(config.url);
@@ -1254,11 +1274,11 @@ var _HttpClient = class _HttpClient {
1254
1274
  return {
1255
1275
  ...config,
1256
1276
  url: finalUrl,
1257
- headers: {
1258
- ...this.defaultHeaders,
1259
- ...config.headers
1260
- },
1261
- timeout: config.timeout ?? this.timeout
1277
+ // The request's own headers replace the client's of the same name, whatever the case: a
1278
+ // per-request `x-relyio-dataset` sent beside the client's `X-RelyIO-Dataset` is one header
1279
+ // `Headers` joins into `main, staging`.
1280
+ headers: layerHeaders(this.connection.defaultHeaders, config.headers),
1281
+ timeout: config.timeout ?? this.connection.timeout
1262
1282
  };
1263
1283
  }
1264
1284
  buildQueryString(params) {
@@ -1281,26 +1301,11 @@ var _HttpClient = class _HttpClient {
1281
1301
  });
1282
1302
  return obj;
1283
1303
  }
1284
- /** A backoff the caller's abort cuts short; the next attempt then refuses to send. */
1285
- sleep(ms, signal) {
1286
- return new Promise((resolve) => {
1287
- if (isAborted(signal)) {
1288
- resolve();
1289
- return;
1290
- }
1291
- const done = /* @__PURE__ */ __name(() => {
1292
- clearTimeout(timer);
1293
- signal?.removeEventListener("abort", done);
1294
- resolve();
1295
- }, "done");
1296
- const timer = setTimeout(done, ms);
1297
- signal?.addEventListener("abort", done, { once: true });
1298
- });
1299
- }
1300
1304
  log(level, message, data) {
1301
- if (!this.debug) return;
1302
- if (this.logger != null) {
1303
- this.logger(level, message, data);
1305
+ const { debug } = this.connection.config;
1306
+ if (!debug.enabled) return;
1307
+ if (debug.logger != null) {
1308
+ debug.logger(level, message, data);
1304
1309
  } else {
1305
1310
  console.log(`[RelyIO SDK ${level.toUpperCase()}] ${message}`, data ?? "");
1306
1311
  }
@@ -1308,17 +1313,105 @@ var _HttpClient = class _HttpClient {
1308
1313
  };
1309
1314
  __name(_HttpClient, "HttpClient");
1310
1315
  var HttpClient = _HttpClient;
1311
- function isAborted(signal) {
1312
- return signal?.aborted === true;
1316
+ var API_KEY_HEADER = "X-API-Key";
1317
+ var DATASET_HEADER = "X-RelyIO-Dataset";
1318
+ var BROWSER_CONTROLLED_HEADERS = /* @__PURE__ */ new Set([
1319
+ "user-agent",
1320
+ "referer",
1321
+ "origin",
1322
+ "host",
1323
+ "connection",
1324
+ "upgrade"
1325
+ ]);
1326
+ function connectionFor(config) {
1327
+ const globalWithVersion = globalThis;
1328
+ const defaultHeaders = layerHeaders(
1329
+ layerHeaders({ "Content-Type": "application/json" }, config.headers),
1330
+ {
1331
+ [API_KEY_HEADER]: presentKey(config.apiKey),
1332
+ [DATASET_HEADER]: config.dataset,
1333
+ // Only outside a browser, which controls this header. "A browser" is the core's one
1334
+ // definition, `isBrowser()` — every environment question in this file asks it.
1335
+ "User-Agent": isBrowser() ? void 0 : `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`
1336
+ }
1337
+ );
1338
+ return {
1339
+ config,
1340
+ baseUrl: config.baseUrl,
1341
+ defaultHeaders,
1342
+ timeout: config.timeout,
1343
+ // The policy, not a predicate over `(error, attempt)`: whether a request may be sent again is a
1344
+ // property of the **route** as much as of the refusal, and a callback that never sees the
1345
+ // request cannot express that.
1346
+ retryPolicy: new DefaultRetryPolicy({
1347
+ maxAttempts: config.retryAttempts,
1348
+ baseDelay: 1e3,
1349
+ maxDelay: 1e4,
1350
+ backoffFactor: 2,
1351
+ jitter: true
1352
+ })
1353
+ };
1313
1354
  }
1314
- __name(isAborted, "isAborted");
1355
+ __name(connectionFor, "connectionFor");
1356
+ function layerHeaders(base, over) {
1357
+ const layered = { ...base };
1358
+ for (const [name, value] of Object.entries(over ?? {})) {
1359
+ if (value === void 0) continue;
1360
+ const lower = name.toLowerCase();
1361
+ for (const existing of Object.keys(layered)) {
1362
+ if (existing.toLowerCase() === lower) delete layered[existing];
1363
+ }
1364
+ if (value !== null) layered[name] = value;
1365
+ }
1366
+ return layered;
1367
+ }
1368
+ __name(layerHeaders, "layerHeaders");
1369
+ function presentKey(value) {
1370
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
1371
+ }
1372
+ __name(presentKey, "presentKey");
1373
+ function credentialsModeFor(includeCredentials) {
1374
+ return includeCredentials ? "include" : "same-origin";
1375
+ }
1376
+ __name(credentialsModeFor, "credentialsModeFor");
1377
+
1378
+ // src/content/client-locale.ts
1379
+ function callLocale(named, clientLocale) {
1380
+ if (named !== void 0) return named;
1381
+ return clientLocale === void 0 || clientLocale === "" ? void 0 : clientLocale;
1382
+ }
1383
+ __name(callLocale, "callLocale");
1384
+ function readClientLocale(locale) {
1385
+ return typeof locale === "function" ? locale : () => locale;
1386
+ }
1387
+ __name(readClientLocale, "readClientLocale");
1315
1388
 
1316
1389
  // src/content/query-builder.ts
1390
+ function namesMetadata(key) {
1391
+ return key === "_metadata" || key.startsWith("_metadata.");
1392
+ }
1393
+ __name(namesMetadata, "namesMetadata");
1394
+ function refuseMetadataConditions(conditions) {
1395
+ const named = Object.keys(conditions).filter(namesMetadata);
1396
+ if (named.length === 0) return;
1397
+ throw new ValidationError(
1398
+ `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.`,
1399
+ named.map((field) => ({
1400
+ field,
1401
+ code: "METADATA_CONDITION",
1402
+ message: `${field} is not a field the API can filter on`
1403
+ }))
1404
+ );
1405
+ }
1406
+ __name(refuseMetadataConditions, "refuseMetadataConditions");
1317
1407
  var _ContentQueryBuilder = class _ContentQueryBuilder {
1318
- constructor(httpClient, contentType, defaultLocale) {
1408
+ /**
1409
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
1410
+ * query names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1411
+ */
1412
+ constructor(httpClient, contentType, locale) {
1319
1413
  this.httpClient = httpClient;
1320
1414
  this.contentType = contentType;
1321
- this.defaultLocale = defaultLocale;
1322
1415
  __publicField(this, "queryOptions", {});
1323
1416
  __publicField(this, "localeValue");
1324
1417
  __publicField(this, "localesArray");
@@ -1327,11 +1420,26 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1327
1420
  __publicField(this, "childrenOptions");
1328
1421
  __publicField(this, "pageNumber");
1329
1422
  __publicField(this, "pageSizeValue");
1423
+ __publicField(this, "requestHeaders");
1424
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
1425
+ __publicField(this, "clientLocale");
1426
+ this.clientLocale = readClientLocale(locale);
1427
+ }
1428
+ /**
1429
+ * Headers this query adds to the client's own, e.g. `X-RelyIO-Dataset` to list another dataset
1430
+ * the key can see. A name the client already sends is replaced for this query only; the client
1431
+ * is not changed.
1432
+ */
1433
+ headers(headers) {
1434
+ this.requestHeaders = headers;
1435
+ return this;
1330
1436
  }
1331
1437
  /**
1332
- * Add where conditions to the query
1438
+ * Add where conditions to the query: conditions on the fields the content type declares. A
1439
+ * condition on `_metadata` is refused here, before anything is sent (`refuseMetadataConditions`).
1333
1440
  */
1334
1441
  where(conditions) {
1442
+ refuseMetadataConditions(conditions);
1335
1443
  this.queryOptions.where = {
1336
1444
  ...this.queryOptions.where,
1337
1445
  ...conditions
@@ -1524,7 +1632,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1524
1632
  const response = await this.httpClient.send(
1525
1633
  "/v1/{contentType}",
1526
1634
  "get",
1527
- { path: { contentType: this.contentType }, query: this.buildQueryParams() }
1635
+ {
1636
+ path: { contentType: this.contentType },
1637
+ query: this.buildQueryParams(),
1638
+ headers: this.requestHeaders
1639
+ }
1528
1640
  );
1529
1641
  return response.body;
1530
1642
  }
@@ -1584,7 +1696,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1584
1696
  * Clone the query builder
1585
1697
  */
1586
1698
  clone() {
1587
- const cloned = new _ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1699
+ const cloned = new _ContentQueryBuilder(
1700
+ this.httpClient,
1701
+ this.contentType,
1702
+ this.clientLocale
1703
+ );
1588
1704
  cloned.queryOptions = JSON.parse(JSON.stringify(this.queryOptions));
1589
1705
  cloned.localeValue = this.localeValue;
1590
1706
  cloned.localesArray = this.localesArray ? [...this.localesArray] : void 0;
@@ -1592,6 +1708,7 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1592
1708
  cloned.fieldsProjection = this.fieldsProjection ? [...this.fieldsProjection] : void 0;
1593
1709
  cloned.pageNumber = this.pageNumber;
1594
1710
  cloned.pageSizeValue = this.pageSizeValue;
1711
+ cloned.requestHeaders = this.requestHeaders ? { ...this.requestHeaders } : void 0;
1595
1712
  return cloned;
1596
1713
  }
1597
1714
  /**
@@ -1658,14 +1775,15 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1658
1775
  if (this.queryOptions.cursor !== void 0) {
1659
1776
  params.cursor = this.queryOptions.cursor;
1660
1777
  }
1778
+ const clientLocale = this.clientLocale();
1661
1779
  if (this.localeValue != null && this.localeValue !== "") {
1662
1780
  params.locale = this.localeValue;
1663
1781
  } else if (this.fetchAllLocales) {
1664
1782
  params.locale = "*";
1665
1783
  } else if (this.localesArray && this.localesArray.length > 0) {
1666
1784
  params.locales = this.localesArray.join(",");
1667
- } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1668
- params.locale = this.defaultLocale;
1785
+ } else if (clientLocale != null && clientLocale !== "") {
1786
+ params.locale = clientLocale;
1669
1787
  }
1670
1788
  if (this.pageNumber !== void 0) {
1671
1789
  params.page = this.pageNumber;
@@ -1689,16 +1807,23 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
1689
1807
  __name(_ContentQueryBuilder, "ContentQueryBuilder");
1690
1808
  var ContentQueryBuilder = _ContentQueryBuilder;
1691
1809
  var _ContentByIdBuilder = class _ContentByIdBuilder {
1692
- constructor(httpClient, contentType, id, defaultLocale) {
1810
+ /**
1811
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
1812
+ * read names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1813
+ */
1814
+ constructor(httpClient, contentType, id, locale) {
1693
1815
  this.httpClient = httpClient;
1694
1816
  this.contentType = contentType;
1695
1817
  this.id = id;
1696
- this.defaultLocale = defaultLocale;
1697
1818
  __publicField(this, "includeRelations");
1698
1819
  __publicField(this, "localeValue");
1699
1820
  __publicField(this, "localesArray");
1700
1821
  __publicField(this, "fetchAllLocales", false);
1701
1822
  __publicField(this, "childrenOptions");
1823
+ __publicField(this, "requestHeaders");
1824
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
1825
+ __publicField(this, "clientLocale");
1826
+ this.clientLocale = readClientLocale(locale);
1702
1827
  }
1703
1828
  /**
1704
1829
  * Include related content in the response
@@ -1729,6 +1854,15 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
1729
1854
  this.fetchAllLocales = false;
1730
1855
  return this;
1731
1856
  }
1857
+ /**
1858
+ * Headers this one read adds to the client's own, e.g. `X-RelyIO-Dataset` to read another dataset
1859
+ * the key can see. A name the client already sends is replaced for this request only; the client
1860
+ * is not changed.
1861
+ */
1862
+ headers(headers) {
1863
+ this.requestHeaders = headers;
1864
+ return this;
1865
+ }
1732
1866
  /**
1733
1867
  * Fetch content in all available locales
1734
1868
  * Returns default locale at top level, others in _metadata.localizations
@@ -1759,14 +1893,15 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
1759
1893
  if (this.includeRelations != null) {
1760
1894
  params.include = this.includeRelations.join(",");
1761
1895
  }
1896
+ const clientLocale = this.clientLocale();
1762
1897
  if (this.localeValue != null && this.localeValue !== "") {
1763
1898
  params.locale = this.localeValue;
1764
1899
  } else if (this.fetchAllLocales) {
1765
1900
  params.locale = "*";
1766
1901
  } else if (this.localesArray && this.localesArray.length > 0) {
1767
1902
  params.locales = this.localesArray.join(",");
1768
- } else if (this.defaultLocale != null && this.defaultLocale !== "") {
1769
- params.locale = this.defaultLocale;
1903
+ } else if (clientLocale != null && clientLocale !== "") {
1904
+ params.locale = clientLocale;
1770
1905
  }
1771
1906
  if (this.childrenOptions != null) {
1772
1907
  if (this.childrenOptions.contentTypes) {
@@ -1782,7 +1917,11 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
1782
1917
  return await this.httpClient.fetchPayload(
1783
1918
  "/v1/{contentType}/{id}",
1784
1919
  "get",
1785
- { path: { contentType: this.contentType, id: this.id }, query: params }
1920
+ {
1921
+ path: { contentType: this.contentType, id: this.id },
1922
+ query: params,
1923
+ headers: this.requestHeaders
1924
+ }
1786
1925
  );
1787
1926
  } catch (error) {
1788
1927
  if (isResourceNotFound(error)) return null;
@@ -1812,6 +1951,14 @@ function writeHeaders(options) {
1812
1951
  return Object.keys(headers).length > 0 ? headers : void 0;
1813
1952
  }
1814
1953
  __name(writeHeaders, "writeHeaders");
1954
+ function requestHeaders(headers, typed) {
1955
+ if (headers === void 0) return typed;
1956
+ if (typed === void 0) return headers;
1957
+ const typedNames = new Set(Object.keys(typed).map((name) => name.toLowerCase()));
1958
+ const own = Object.entries(headers).filter(([name]) => !typedNames.has(name.toLowerCase()));
1959
+ return { ...Object.fromEntries(own), ...typed };
1960
+ }
1961
+ __name(requestHeaders, "requestHeaders");
1815
1962
  function entityTagOf(response) {
1816
1963
  return headerValue(response.headers, HEADER_ENTITY_TAG.name);
1817
1964
  }
@@ -1819,22 +1966,28 @@ __name(entityTagOf, "entityTagOf");
1819
1966
 
1820
1967
  // src/content/content-client.ts
1821
1968
  var _ContentClient = class _ContentClient {
1822
- constructor(httpClient, contentType, defaultLocale) {
1969
+ /**
1970
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
1971
+ * every call, or a locale fixed for this client
1972
+ */
1973
+ constructor(httpClient, contentType, locale) {
1823
1974
  this.httpClient = httpClient;
1824
1975
  this.contentType = contentType;
1825
- this.defaultLocale = defaultLocale;
1976
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
1977
+ __publicField(this, "clientLocale");
1978
+ this.clientLocale = readClientLocale(locale);
1826
1979
  }
1827
1980
  /**
1828
1981
  * Create a new query builder for this content type
1829
1982
  */
1830
1983
  query() {
1831
- return new ContentQueryBuilder(this.httpClient, this.contentType, this.defaultLocale);
1984
+ return new ContentQueryBuilder(this.httpClient, this.contentType, this.clientLocale);
1832
1985
  }
1833
1986
  /**
1834
1987
  * Find content by ID with fluent options
1835
1988
  */
1836
1989
  findById(id) {
1837
- return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.defaultLocale);
1990
+ return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.clientLocale);
1838
1991
  }
1839
1992
  /**
1840
1993
  * Fetch all content items
@@ -1881,7 +2034,8 @@ var _ContentClient = class _ContentClient {
1881
2034
  /**
1882
2035
  * Fetch a single content item by ID
1883
2036
  * @param id - Entry ID or slug
1884
- * @param options - Fetch options (include, locale)
2037
+ * @param options - Fetch options (include, locale, and `headers` this one request adds — e.g.
2038
+ * `{ 'X-RelyIO-Dataset': 'staging' }` to read a dataset other than the client's)
1885
2039
  */
1886
2040
  async fetchOne(id, options) {
1887
2041
  const builder = this.findById(id);
@@ -1891,6 +2045,9 @@ var _ContentClient = class _ContentClient {
1891
2045
  if (options?.locale != null && options.locale !== "") {
1892
2046
  builder.locale(options.locale);
1893
2047
  }
2048
+ if (options?.headers != null) {
2049
+ builder.headers(options.headers);
2050
+ }
1894
2051
  return builder.execute();
1895
2052
  }
1896
2053
  /**
@@ -1905,16 +2062,21 @@ var _ContentClient = class _ContentClient {
1905
2062
  * `entityTag` is `undefined` when the response came from the cache: a cached
1906
2063
  * body cannot know the current version, and an absent tag beats a stale one
1907
2064
  * that would refuse the next write.
2065
+ *
2066
+ * Unlike {@link fetchOne}, a missing entry is not `null`: the service's
2067
+ * `RESOURCE_NOT_FOUND` is thrown as it arrived, with the `kind` that says
2068
+ * whether the entry, the content type or the schema was missing. `headers`
2069
+ * are the ones this read adds, as for `fetchOne`.
1908
2070
  */
1909
2071
  async fetchOneWithTag(id, options) {
1910
2072
  const query = {};
1911
2073
  if (options?.include != null) query.include = options.include.join(",");
1912
- const locale = options?.locale ?? this.defaultLocale;
2074
+ const locale = options?.locale ?? this.clientLocale();
1913
2075
  if (locale != null && locale !== "") query.locale = locale;
1914
2076
  const response = await this.httpClient.send(
1915
2077
  "/v1/{contentType}/{id}",
1916
2078
  "get",
1917
- { path: { contentType: this.contentType, id }, query }
2079
+ { path: { contentType: this.contentType, id }, query, headers: options?.headers }
1918
2080
  );
1919
2081
  return { entry: readPayload(response.body), entityTag: entityTagOf(response) };
1920
2082
  }
@@ -1936,17 +2098,21 @@ var _ContentClient = class _ContentClient {
1936
2098
  /**
1937
2099
  * Create a new content item
1938
2100
  * @param data - Content data
1939
- * @param options - Create options (slug, locale, parentId, sortOrder)
2101
+ * @param options - Create options (slug, locale, parentId, sortOrder), and `headers` this one
2102
+ * request adds — e.g. `{ 'X-RelyIO-Dataset': 'staging' }` to write a dataset other than the
2103
+ * client's. They are sent, never put in the body; `idempotencyKey` still wins over an
2104
+ * `Idempotency-Key` among them. `locale` defaults to the client's own (`withLocale()`).
1940
2105
  */
1941
2106
  async create(data, options) {
1942
- const { idempotencyKey, ...body } = options ?? {};
2107
+ const { idempotencyKey, headers, locale, ...body } = options ?? {};
2108
+ const sent = callLocale(locale, this.clientLocale());
1943
2109
  return this.httpClient.fetchPayload(
1944
2110
  "/v1/{contentType}",
1945
2111
  "post",
1946
2112
  {
1947
2113
  path: { contentType: this.contentType },
1948
- body: { content: data, ...body },
1949
- headers: writeHeaders({ idempotencyKey })
2114
+ body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
2115
+ headers: requestHeaders(headers, writeHeaders({ idempotencyKey }))
1950
2116
  }
1951
2117
  );
1952
2118
  }
@@ -1954,17 +2120,21 @@ var _ContentClient = class _ContentClient {
1954
2120
  * Update a content item by ID (partial update)
1955
2121
  * @param id - Entry ID
1956
2122
  * @param data - Fields to update
1957
- * @param options - Update options (slug, locale, parentId, sortOrder)
2123
+ * @param options - Update options (slug, locale, parentId, sortOrder), and `headers` this one
2124
+ * request adds, as for {@link create}. `ifMatch` and `idempotencyKey` win over the same
2125
+ * header among them. `locale` defaults to the client's own, the locale whose entity tag
2126
+ * {@link fetchOneWithTag} reads, so the tag it hands back is checked against the same locale.
1958
2127
  */
1959
2128
  async update(id, data, options) {
1960
- const { idempotencyKey, ifMatch, ...body } = options ?? {};
2129
+ const { idempotencyKey, ifMatch, headers, locale, ...body } = options ?? {};
2130
+ const sent = callLocale(locale, this.clientLocale());
1961
2131
  return this.httpClient.fetchPayload(
1962
2132
  "/v1/{contentType}/{id}",
1963
2133
  "patch",
1964
2134
  {
1965
2135
  path: { contentType: this.contentType, id },
1966
- body: { content: data, ...body },
1967
- headers: writeHeaders({ idempotencyKey, ifMatch })
2136
+ body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
2137
+ headers: requestHeaders(headers, writeHeaders({ idempotencyKey, ifMatch }))
1968
2138
  }
1969
2139
  );
1970
2140
  }
@@ -1995,32 +2165,35 @@ var _ContentClient = class _ContentClient {
1995
2165
  * Get version history for one locale of an entry.
1996
2166
  *
1997
2167
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
1998
- * schema default, no fallback is applied, and a locale with no history returns an empty array
1999
- * rather than another locale's rows. Every row names the locale it belongs to.
2168
+ * client's own (`withLocale()`), else the schema default; no fallback is applied, and a locale
2169
+ * with no history returns an empty array rather than another locale's rows. Every row names the
2170
+ * locale it belongs to.
2000
2171
  */
2001
2172
  async versions(id, options) {
2173
+ const locale = callLocale(options?.locale, this.clientLocale());
2002
2174
  return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions", "get", {
2003
2175
  path: { contentType: this.contentType, id },
2004
2176
  query: {
2005
2177
  limit: options?.limit ?? 10,
2006
- ...options?.locale === void 0 ? {} : { locale: options.locale }
2178
+ ...locale === void 0 ? {} : { locale }
2007
2179
  }
2008
2180
  });
2009
2181
  }
2010
2182
  /**
2011
2183
  * Get a specific version of an entry.
2012
2184
  *
2013
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2014
- * different content in each one.
2185
+ * `locale` defaults to the client's own (`withLocale()`), else the schema default. Version
2186
+ * numbers are per locale, so version 2 is different content in each one.
2015
2187
  */
2016
2188
  async version(id, versionNumber, options) {
2189
+ const locale = callLocale(options?.locale, this.clientLocale());
2017
2190
  return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions/{versionNumber}", "get", {
2018
2191
  path: {
2019
2192
  contentType: this.contentType,
2020
2193
  id,
2021
2194
  versionNumber: String(versionNumber)
2022
2195
  },
2023
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
2196
+ query: locale === void 0 ? void 0 : { locale }
2024
2197
  });
2025
2198
  }
2026
2199
  /**
@@ -2059,8 +2232,9 @@ var _ContentClient = class _ContentClient {
2059
2232
  if (options?.include != null) {
2060
2233
  params.include = options.include.join(",");
2061
2234
  }
2062
- if (options?.locale != null && options.locale !== "") {
2063
- params.locale = options.locale;
2235
+ const locale = options?.locale ?? this.clientLocale();
2236
+ if (locale != null && locale !== "") {
2237
+ params.locale = locale;
2064
2238
  }
2065
2239
  return this.httpClient.fetchPayload(
2066
2240
  "/v1/{contentType}/{id}/children",
@@ -2078,19 +2252,20 @@ var _ContentClient = class _ContentClient {
2078
2252
  * Create a new ContentClient for a different content type
2079
2253
  */
2080
2254
  ofType(contentType) {
2081
- return new _ContentClient(this.httpClient, contentType, this.defaultLocale);
2255
+ return new _ContentClient(this.httpClient, contentType, this.clientLocale);
2082
2256
  }
2083
2257
  /**
2084
- * Create a new ContentClient with a different default locale
2258
+ * Create a new ContentClient with a different default locale, fixed: an update of the client's
2259
+ * locale (`updateConfig({ locale })`) does not reach it
2085
2260
  */
2086
2261
  withLocale(locale) {
2087
2262
  return new _ContentClient(this.httpClient, this.contentType, locale);
2088
2263
  }
2089
2264
  /**
2090
- * Get the current default locale
2265
+ * Get the default locale as it is now: the client's, or the one `withLocale()` fixed
2091
2266
  */
2092
2267
  getDefaultLocale() {
2093
- return this.defaultLocale;
2268
+ return this.clientLocale();
2094
2269
  }
2095
2270
  };
2096
2271
  __name(_ContentClient, "ContentClient");
@@ -2099,7 +2274,7 @@ var ContentClient = _ContentClient;
2099
2274
  // src/errors/file-errors.ts
2100
2275
  var _FileUploadError = class _FileUploadError extends SDKError {
2101
2276
  constructor(code, message, options = {}) {
2102
- super(message, options.statusCode, options.cause, { fileErrorCode: code });
2277
+ super(message, options.statusCode, options.cause, { ...options.context, fileErrorCode: code });
2103
2278
  __publicField(this, "code");
2104
2279
  __publicField(this, "retryable");
2105
2280
  this.code = code;
@@ -2146,11 +2321,52 @@ function validateFile(file, constraints = {}) {
2146
2321
  }
2147
2322
  __name(validateFile, "validateFile");
2148
2323
 
2324
+ // src/errors/file-error-codes.ts
2325
+ var FILE_ERROR_CODES = [
2326
+ "UPLOAD_TOO_LARGE",
2327
+ "UNSUPPORTED_MIME",
2328
+ "DIMENSION_OUT_OF_RANGE",
2329
+ "ASPECT_RATIO",
2330
+ "CORRUPT_FILE",
2331
+ "UNSUPPORTED_CODEC",
2332
+ "IMAGES_LIMIT_EXCEEDED",
2333
+ "STREAM_ENCODE_FAILED",
2334
+ "SCAN_INFECTED",
2335
+ "INTERNAL"
2336
+ ];
2337
+
2149
2338
  // src/content/asset-client.ts
2339
+ function assertWaitOptions(options) {
2340
+ const { timeoutMs, pollIntervalMs } = options;
2341
+ if (timeoutMs !== void 0 && !(typeof timeoutMs === "number" && timeoutMs >= 0 && timeoutMs <= MAX_TIMER_DELAY_MS)) {
2342
+ throw new Error(
2343
+ `timeoutMs must be a number of milliseconds from 0 to ${MAX_TIMER_DELAY_MS}, and got ${String(timeoutMs)}`
2344
+ );
2345
+ }
2346
+ if (pollIntervalMs !== void 0 && !isTimerDelay(pollIntervalMs)) {
2347
+ throw new Error(
2348
+ `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)}`
2349
+ );
2350
+ }
2351
+ }
2352
+ __name(assertWaitOptions, "assertWaitOptions");
2150
2353
  function hasText(value) {
2151
2354
  return value != null && value !== "";
2152
2355
  }
2153
2356
  __name(hasText, "hasText");
2357
+ function processingFailure(subject, stored) {
2358
+ const storedCode = stored?.code;
2359
+ const code = FILE_ERROR_CODES.find((known) => known === storedCode) ?? "PROCESSING_FAILED";
2360
+ return new FileUploadError(
2361
+ code,
2362
+ `Asset ${subject}: ${stored?.message ?? "File processing failed"}`,
2363
+ {
2364
+ retriable: stored?.retriable === true,
2365
+ context: { processingError: stored }
2366
+ }
2367
+ );
2368
+ }
2369
+ __name(processingFailure, "processingFailure");
2154
2370
  async function computeSha256Hex(blob) {
2155
2371
  try {
2156
2372
  const subtle = globalThis.crypto?.subtle;
@@ -2166,11 +2382,17 @@ async function computeSha256Hex(blob) {
2166
2382
  }
2167
2383
  __name(computeSha256Hex, "computeSha256Hex");
2168
2384
  var _AssetFileBuilder = class _AssetFileBuilder {
2169
- constructor(httpClient, assetType, entryUid, defaultLocale) {
2385
+ /**
2386
+ * @param locale - The client's locale, sent when a call names none: the function
2387
+ * `TypedRelyIOClient` hands over, or a locale fixed for this builder
2388
+ */
2389
+ constructor(httpClient, assetType, entryUid, locale) {
2170
2390
  this.httpClient = httpClient;
2171
2391
  this.assetType = assetType;
2172
2392
  this.entryUid = entryUid;
2173
- this.defaultLocale = defaultLocale;
2393
+ /** The client's locale, asked on every call rather than copied when this builder was taken. */
2394
+ __publicField(this, "clientLocale");
2395
+ this.clientLocale = readClientLocale(locale);
2174
2396
  }
2175
2397
  /**
2176
2398
  * The path parameters every `/file/*` route on this builder takes.
@@ -2183,7 +2405,16 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2183
2405
  return { contentType: this.assetType, id: this.entryUid };
2184
2406
  }
2185
2407
  withLocale(locale) {
2186
- return locale ?? this.defaultLocale;
2408
+ return locale ?? this.clientLocale();
2409
+ }
2410
+ /**
2411
+ * The `locale` body field of a multipart call: the session's, else the client's. The API finds
2412
+ * the binding by it, so a session a `withLocale()` client opened must name the same locale on
2413
+ * every later call or its `objectKey` is refused as another binding's.
2414
+ */
2415
+ localeField(locale) {
2416
+ const sent = this.withLocale(locale);
2417
+ return hasText(sent) ? { locale: sent } : {};
2187
2418
  }
2188
2419
  /**
2189
2420
  * Issue a single upload target — an R2 presigned PUT (image/file) or a
@@ -2242,7 +2473,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2242
2473
  uploadId: target.uploadId,
2243
2474
  objectKey: target.objectKey,
2244
2475
  partNumber: target.partNumber,
2245
- ...hasText(target.locale) ? { locale: target.locale } : {}
2476
+ ...this.localeField(target.locale)
2246
2477
  }
2247
2478
  });
2248
2479
  }
@@ -2253,7 +2484,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2253
2484
  body: {
2254
2485
  uploadId: target.uploadId,
2255
2486
  objectKey: target.objectKey,
2256
- ...hasText(target.locale) ? { locale: target.locale } : {}
2487
+ ...this.localeField(target.locale)
2257
2488
  }
2258
2489
  });
2259
2490
  return payload.parts;
@@ -2266,7 +2497,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2266
2497
  uploadId: target.uploadId,
2267
2498
  objectKey: target.objectKey,
2268
2499
  parts: target.parts.map((p) => ({ partNumber: p.partNumber, etag: p.etag })),
2269
- ...hasText(target.locale) ? { locale: target.locale } : {}
2500
+ ...this.localeField(target.locale)
2270
2501
  }
2271
2502
  });
2272
2503
  }
@@ -2277,7 +2508,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2277
2508
  body: {
2278
2509
  uploadId: target.uploadId,
2279
2510
  objectKey: target.objectKey,
2280
- ...hasText(target.locale) ? { locale: target.locale } : {}
2511
+ ...this.localeField(target.locale)
2281
2512
  }
2282
2513
  });
2283
2514
  }
@@ -2297,6 +2528,25 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2297
2528
  { path: this.target, query: params }
2298
2529
  );
2299
2530
  }
2531
+ /**
2532
+ * Read where this file's upload got to — `status`, and the processing stage, progress and error
2533
+ * the pipeline recorded — whatever the asset entry is published in.
2534
+ *
2535
+ * An asset is a draft until its file is ready, and stays one when its file fails, so a key that
2536
+ * reads published content finds no entry for an upload in flight or one that failed. This read
2537
+ * answers for the binding itself. It takes the capability the upload calls take, so a read-only
2538
+ * key is refused with `ReadOnlyKeyError`, and it never returns the entry's fields.
2539
+ */
2540
+ async status(options = {}) {
2541
+ const params = {};
2542
+ const locale = this.withLocale(options.locale);
2543
+ if (hasText(locale)) params.locale = locale;
2544
+ return this.httpClient.fetchPayload(
2545
+ "/v1/{contentType}/{id}/file",
2546
+ "get",
2547
+ { path: this.target, query: params }
2548
+ );
2549
+ }
2300
2550
  /**
2301
2551
  * Update the binding's delivery visibility (token-based; no byte relocation —
2302
2552
  * a downgrade purges the gateway cache). Returns the refreshed asset entry.
@@ -2335,14 +2585,31 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2335
2585
  });
2336
2586
  }
2337
2587
  /**
2338
- * Poll the asset entry until its file binding reaches `ready` (resolves with
2339
- * the ready entry) or `failed` (throws). Times out after `timeoutMs`.
2588
+ * Poll the asset entry until its file binding reaches `ready`, and resolve with the ready entry.
2589
+ *
2590
+ * Each poll reads the entry through the key's lens. When that finds nothing — a key that reads
2591
+ * published content, and an asset that is a draft until its file is ready and stays one when it
2592
+ * fails — the poll reads the binding itself ({@link status}), so a failed upload rejects as one
2593
+ * rather than running out the limit (REL-1481).
2594
+ *
2595
+ * @throws {FileUploadError} When processing failed. `code` is the processing code the service
2596
+ * stored — `UNSUPPORTED_CODEC`, `CORRUPT_FILE` and so on — or `PROCESSING_FAILED` where it
2597
+ * stored none this SDK knows; `context.processingError` holds what it stored, and `retryable`
2598
+ * is its `retriable` hint.
2599
+ * @throws {TimeoutError} When `timeoutMs` passes first. The file may still become ready; the
2600
+ * error's `context.timeout` is the limit and `context.fileStatus` the status last seen. A file
2601
+ * that is `ready` in an asset the key's lens never shows — created with `publish: false`, or
2602
+ * awaiting a workflow — ends here too, and the message says so.
2603
+ * @throws {ReadOnlyKeyError} When the key's lens does not show the asset and the key may not read
2604
+ * its binding either: nothing it can read would ever report the file.
2340
2605
  */
2341
2606
  async waitUntilReady(options = {}) {
2607
+ assertWaitOptions(options);
2342
2608
  const timeoutMs = options.timeoutMs ?? 6e4;
2343
2609
  const pollIntervalMs = options.pollIntervalMs ?? 1500;
2344
2610
  const locale = this.withLocale(options.locale);
2345
2611
  const deadline = Date.now() + timeoutMs;
2612
+ const subject = `${this.assetType}/${this.entryUid}`;
2346
2613
  for (; ; ) {
2347
2614
  const builder = new ContentByIdBuilder(
2348
2615
  this.httpClient,
@@ -2352,15 +2619,24 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2352
2619
  );
2353
2620
  if (hasText(locale)) builder.locale(locale);
2354
2621
  const entry = await builder.execute();
2355
- const status = entry?.file?.status;
2356
- if (entry && status === "ready") return entry;
2357
- if (status === "failed") {
2358
- const message = entry?.file?.processing?.error?.message ?? "File processing failed";
2359
- throw new Error(`Asset ${this.assetType}/${this.entryUid}: ${message}`);
2622
+ let status;
2623
+ if (entry === null) {
2624
+ const binding = await this.status({ ...hasText(locale) ? { locale } : {} });
2625
+ status = binding.status;
2626
+ if (status === "failed") throw processingFailure(subject, binding.processing?.error);
2627
+ } else {
2628
+ status = entry.file?.status;
2629
+ if (status === "ready") return entry;
2630
+ if (status === "failed") throw processingFailure(subject, entry.file?.processing?.error);
2360
2631
  }
2361
2632
  if (Date.now() >= deadline) {
2362
- throw new Error(
2363
- `Timed out after ${timeoutMs}ms waiting for ${this.assetType}/${this.entryUid} (status: ${status ?? "unknown"})`
2633
+ 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" : "";
2634
+ throw new TimeoutError(
2635
+ `Timed out after ${timeoutMs}ms waiting for ${subject} (status: ${status ?? "unknown"})${unseen}`,
2636
+ timeoutMs,
2637
+ void 0,
2638
+ void 0,
2639
+ { fileStatus: status }
2364
2640
  );
2365
2641
  }
2366
2642
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
@@ -2370,11 +2646,14 @@ var _AssetFileBuilder = class _AssetFileBuilder {
2370
2646
  __name(_AssetFileBuilder, "AssetFileBuilder");
2371
2647
  var AssetFileBuilder = _AssetFileBuilder;
2372
2648
  var _AssetUploadBuilder = class _AssetUploadBuilder {
2373
- constructor(httpClient, assetType, file, defaultLocale) {
2649
+ /**
2650
+ * @param locale - The client's locale, the upload's when `.locale()` names none: the function
2651
+ * `TypedRelyIOClient` hands over, or a locale fixed for this upload
2652
+ */
2653
+ constructor(httpClient, assetType, file, locale) {
2374
2654
  this.httpClient = httpClient;
2375
2655
  this.assetType = assetType;
2376
2656
  this.file = file;
2377
- this.defaultLocale = defaultLocale;
2378
2657
  __publicField(this, "_fileName");
2379
2658
  __publicField(this, "_visibility");
2380
2659
  __publicField(this, "_locale");
@@ -2386,6 +2665,9 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2386
2665
  __publicField(this, "_onProgress");
2387
2666
  __publicField(this, "_validate");
2388
2667
  __publicField(this, "_maxPartRetries", 3);
2668
+ /** The client's locale, read once when the upload starts. */
2669
+ __publicField(this, "clientLocale");
2670
+ this.clientLocale = readClientLocale(locale);
2389
2671
  }
2390
2672
  /** Subscribe to client → storage upload progress (single PUT + multipart). */
2391
2673
  onProgress(callback) {
@@ -2435,8 +2717,14 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2435
2717
  this._slug = slug;
2436
2718
  return this;
2437
2719
  }
2438
- /** Wait until the file binding becomes `ready` before resolving. */
2720
+ /**
2721
+ * Wait until the file binding becomes `ready` before resolving.
2722
+ *
2723
+ * @throws {Error} When `timeoutMs` or `pollIntervalMs` is one the wait cannot honour — refused
2724
+ * here, before anything is uploaded, rather than after the bytes are in.
2725
+ */
2439
2726
  waitForReady(options = true) {
2727
+ if (typeof options === "object") assertWaitOptions(options);
2440
2728
  if (options === false) {
2441
2729
  this._waitForReady = false;
2442
2730
  } else {
@@ -2451,7 +2739,8 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2451
2739
  if (!fileName) {
2452
2740
  throw new Error('A file name is required: pass a File, or call .filename("name.ext")');
2453
2741
  }
2454
- const locale = this._locale ?? this.defaultLocale;
2742
+ const clientLocale = this.clientLocale();
2743
+ const locale = this._locale ?? clientLocale;
2455
2744
  if (this._validate) {
2456
2745
  const violations = validateFile(this.file, this._validate);
2457
2746
  if (violations.length > 0) {
@@ -2462,7 +2751,7 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2462
2751
  }
2463
2752
  }
2464
2753
  const hash = await computeSha256Hex(this.file);
2465
- const client = new AssetClient(this.httpClient, this.assetType, this.defaultLocale);
2754
+ const client = new AssetClient(this.httpClient, this.assetType, clientLocale);
2466
2755
  const created = await client.create(this._content, {
2467
2756
  ...hasText(this._slug) ? { slug: this._slug } : {},
2468
2757
  ...hasText(locale) ? { locale } : {},
@@ -2613,17 +2902,26 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
2613
2902
  __name(_AssetUploadBuilder, "AssetUploadBuilder");
2614
2903
  var AssetUploadBuilder = _AssetUploadBuilder;
2615
2904
  var _AssetClient = class _AssetClient {
2616
- constructor(httpClient, assetType, defaultLocale) {
2905
+ /**
2906
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
2907
+ * every call, or a locale fixed for this client
2908
+ */
2909
+ constructor(httpClient, assetType, locale) {
2617
2910
  this.httpClient = httpClient;
2618
2911
  this.assetType = assetType;
2619
- this.defaultLocale = defaultLocale;
2912
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
2913
+ __publicField(this, "clientLocale");
2914
+ this.clientLocale = readClientLocale(locale);
2620
2915
  }
2621
- /** Create a query builder for this asset type. */
2916
+ /**
2917
+ * Create a query builder for this asset type. It resolves asset reads; its conditions name the
2918
+ * asset type's fields, which the `file` and `urls` blocks are not.
2919
+ */
2622
2920
  query() {
2623
2921
  return new ContentQueryBuilder(
2624
2922
  this.httpClient,
2625
2923
  this.assetType,
2626
- this.defaultLocale
2924
+ this.clientLocale
2627
2925
  );
2628
2926
  }
2629
2927
  /** Find an asset entry by id (or slug) with fluent options. */
@@ -2632,7 +2930,7 @@ var _AssetClient = class _AssetClient {
2632
2930
  this.httpClient,
2633
2931
  this.assetType,
2634
2932
  id,
2635
- this.defaultLocale
2933
+ this.clientLocale
2636
2934
  );
2637
2935
  }
2638
2936
  /** Fetch a single asset entry by id (or slug), or `null` if not found. */
@@ -2653,28 +2951,34 @@ var _AssetClient = class _AssetClient {
2653
2951
  * Create a new asset entry as a draft. The binary is uploaded separately via
2654
2952
  * `file(uid)` (or use the high-level `upload()` helper), and the entry
2655
2953
  * auto-publishes when its file becomes ready (unless `publish: false`).
2954
+ * `locale` defaults to the client's own (`withLocale()`).
2656
2955
  */
2657
2956
  async create(data, options) {
2658
- const { idempotencyKey, ...rest } = options ?? {};
2957
+ const { idempotencyKey, locale, ...rest } = options ?? {};
2958
+ const sent = callLocale(locale, this.clientLocale());
2659
2959
  return this.httpClient.fetchPayload(
2660
2960
  "/v1/{contentType}",
2661
2961
  "post",
2662
2962
  {
2663
2963
  path: { contentType: this.assetType },
2664
- body: { content: data, ...rest },
2964
+ body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
2665
2965
  headers: writeHeaders({ idempotencyKey })
2666
2966
  }
2667
2967
  );
2668
2968
  }
2669
- /** Update an asset entry's metadata fields (and/or slug). */
2969
+ /**
2970
+ * Update an asset entry's metadata fields (and/or slug). `locale` defaults to the client's own
2971
+ * (`withLocale()`).
2972
+ */
2670
2973
  async update(id, data, options) {
2671
- const { idempotencyKey, ifMatch, ...rest } = options ?? {};
2974
+ const { idempotencyKey, ifMatch, locale, ...rest } = options ?? {};
2975
+ const sent = callLocale(locale, this.clientLocale());
2672
2976
  return this.httpClient.fetchPayload(
2673
2977
  "/v1/{contentType}/{id}",
2674
2978
  "patch",
2675
2979
  {
2676
2980
  path: { contentType: this.assetType, id },
2677
- body: { content: data, ...rest },
2981
+ body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
2678
2982
  headers: writeHeaders({ idempotencyKey, ifMatch })
2679
2983
  }
2680
2984
  );
@@ -2688,21 +2992,24 @@ var _AssetClient = class _AssetClient {
2688
2992
  }
2689
2993
  /** Get the file sub-resource builder for a specific asset entry. */
2690
2994
  file(entryUid) {
2691
- return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.defaultLocale);
2995
+ return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.clientLocale);
2692
2996
  }
2693
2997
  /** Start a high-level upload (create → presign → PUT → confirm). */
2694
2998
  upload(file) {
2695
- return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.defaultLocale);
2999
+ return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.clientLocale);
2696
3000
  }
2697
3001
  /** Get the asset type id. */
2698
3002
  getAssetType() {
2699
3003
  return this.assetType;
2700
3004
  }
2701
- /** Get the current default locale. */
3005
+ /** Get the default locale as it is now: the client's, or the one `withLocale()` fixed. */
2702
3006
  getDefaultLocale() {
2703
- return this.defaultLocale;
3007
+ return this.clientLocale();
2704
3008
  }
2705
- /** Create a new AssetClient for this type with a different default locale. */
3009
+ /**
3010
+ * Create a new AssetClient for this type with a different default locale, fixed: an update of the
3011
+ * client's locale (`updateConfig({ locale })`) does not reach it.
3012
+ */
2706
3013
  withLocale(locale) {
2707
3014
  return new _AssetClient(this.httpClient, this.assetType, locale);
2708
3015
  }
@@ -2718,11 +3025,18 @@ __name(isAssetEntry, "isAssetEntry");
2718
3025
 
2719
3026
  // src/content/singleton-client.ts
2720
3027
  var _SingletonClient = class _SingletonClient {
2721
- constructor(httpClient, singletonKey) {
3028
+ /**
3029
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
3030
+ * every call, or a locale fixed for this client
3031
+ */
3032
+ constructor(httpClient, singletonKey, locale) {
2722
3033
  this.httpClient = httpClient;
2723
3034
  this.singletonKey = singletonKey;
2724
3035
  __publicField(this, "includeFields");
2725
3036
  __publicField(this, "localeValue");
3037
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
3038
+ __publicField(this, "clientLocale");
3039
+ this.clientLocale = readClientLocale(locale);
2726
3040
  }
2727
3041
  /**
2728
3042
  * Include reference fields in the response
@@ -2745,11 +3059,6 @@ var _SingletonClient = class _SingletonClient {
2745
3059
  * @param options - Optional fetch options (alternative to fluent methods)
2746
3060
  */
2747
3061
  async fetch(options) {
2748
- const includeValue = options?.include ?? this.includeFields;
2749
- options?.locale ?? this.localeValue;
2750
- if (includeValue) {
2751
- includeValue.join(",");
2752
- }
2753
3062
  try {
2754
3063
  return (await this.fetchWithTag(options)).content;
2755
3064
  } catch (error) {
@@ -2767,7 +3076,7 @@ var _SingletonClient = class _SingletonClient {
2767
3076
  async fetchWithTag(options) {
2768
3077
  const query = {};
2769
3078
  const includeValue = options?.include ?? this.includeFields;
2770
- const localeValueFinal = options?.locale ?? this.localeValue;
3079
+ const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
2771
3080
  if (includeValue) query.include = includeValue.join(",");
2772
3081
  if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
2773
3082
  const response = await this.httpClient.send(
@@ -2781,11 +3090,12 @@ var _SingletonClient = class _SingletonClient {
2781
3090
  * Update singleton content. The API auto-publishes on PATCH — there is no
2782
3091
  * separate publish route; calling `update()` writes and publishes.
2783
3092
  * @param data - The content fields to update
2784
- * @param locale - Optional locale for localized content (overrides fluent locale)
3093
+ * @param locale - Optional locale for localized content (overrides the fluent locale, which
3094
+ * overrides the client's own)
2785
3095
  * @param options - `If-Match` / `Idempotency-Key`, both declared on this route
2786
3096
  */
2787
3097
  async update(data, locale, options) {
2788
- const finalLocale = locale ?? this.localeValue;
3098
+ const finalLocale = this.localeOf(locale);
2789
3099
  return this.httpClient.fetchPayload(
2790
3100
  "/v1/singletons/{key}",
2791
3101
  "patch",
@@ -2814,15 +3124,17 @@ var _SingletonClient = class _SingletonClient {
2814
3124
  * Get version history for one locale of the singleton.
2815
3125
  *
2816
3126
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2817
- * schema default, no fallback is applied, and a locale with no history returns an empty array
2818
- * rather than another locale's rows. Every row names the locale it belongs to.
3127
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
3128
+ * fallback is applied, and a locale with no history returns an empty array rather than another
3129
+ * locale's rows. Every row names the locale it belongs to.
2819
3130
  */
2820
3131
  async versions(options) {
3132
+ const locale = this.localeOf(options?.locale);
2821
3133
  const payload = await this.httpClient.fetchPayload("/v1/singletons/{key}/versions", "get", {
2822
3134
  path: { key: this.singletonKey },
2823
3135
  query: {
2824
3136
  limit: options?.limit ?? 10,
2825
- ...options?.locale === void 0 ? {} : { locale: options.locale }
3137
+ ...locale === void 0 ? {} : { locale }
2826
3138
  }
2827
3139
  });
2828
3140
  return payload.versions;
@@ -2830,20 +3142,25 @@ var _SingletonClient = class _SingletonClient {
2830
3142
  /**
2831
3143
  * Get a specific version of the singleton.
2832
3144
  *
2833
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2834
- * different content in each one.
3145
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
3146
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
2835
3147
  */
2836
3148
  async version(versionNumber, options) {
3149
+ const locale = this.localeOf(options?.locale);
2837
3150
  try {
2838
3151
  return await this.httpClient.fetchPayload("/v1/singletons/{key}/versions/{versionNumber}", "get", {
2839
3152
  path: { key: this.singletonKey, versionNumber: String(versionNumber) },
2840
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
3153
+ query: locale === void 0 ? void 0 : { locale }
2841
3154
  });
2842
3155
  } catch (error) {
2843
3156
  if (isResourceNotFound(error)) return null;
2844
3157
  throw error;
2845
3158
  }
2846
3159
  }
3160
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
3161
+ localeOf(named) {
3162
+ return callLocale(named ?? this.localeValue, this.clientLocale());
3163
+ }
2847
3164
  /**
2848
3165
  * Get the singleton key
2849
3166
  */
@@ -2864,11 +3181,18 @@ var SingletonClient = _SingletonClient;
2864
3181
 
2865
3182
  // src/content/settings-client.ts
2866
3183
  var _SettingsClient = class _SettingsClient {
2867
- constructor(httpClient, groupId) {
3184
+ /**
3185
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
3186
+ * every call, or a locale fixed for this client
3187
+ */
3188
+ constructor(httpClient, groupId, locale) {
2868
3189
  this.httpClient = httpClient;
2869
3190
  this.groupId = groupId;
2870
3191
  __publicField(this, "includeFields");
2871
3192
  __publicField(this, "localeValue");
3193
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
3194
+ __publicField(this, "clientLocale");
3195
+ this.clientLocale = readClientLocale(locale);
2872
3196
  }
2873
3197
  /**
2874
3198
  * Include reference fields in the response
@@ -2891,11 +3215,6 @@ var _SettingsClient = class _SettingsClient {
2891
3215
  * @param options - Optional fetch options (alternative to fluent methods)
2892
3216
  */
2893
3217
  async fetch(options) {
2894
- const includeValue = options?.include ?? this.includeFields;
2895
- options?.locale ?? this.localeValue;
2896
- if (includeValue) {
2897
- includeValue.join(",");
2898
- }
2899
3218
  try {
2900
3219
  return (await this.fetchWithTag(options)).settings;
2901
3220
  } catch (error) {
@@ -2905,12 +3224,20 @@ var _SettingsClient = class _SettingsClient {
2905
3224
  }
2906
3225
  /**
2907
3226
  * Update settings group
3227
+ *
3228
+ * The fields travel as `content` beside an optional `locale`, the body the route validates
3229
+ * (`UpdateSettingsDto`); any other top-level key is refused `REQUEST_INVALID`.
3230
+ *
2908
3231
  * @param settings - The settings fields to update
2909
- * @param locale - Optional locale for localized settings (overrides fluent locale)
3232
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
3233
+ * overrides the client's own)
2910
3234
  */
2911
3235
  async update(settings, locale, options) {
2912
- const finalLocale = locale ?? this.localeValue;
2913
- const body = finalLocale != null && finalLocale !== "" ? { ...settings, locale: finalLocale } : settings;
3236
+ const finalLocale = this.localeOf(locale);
3237
+ const body = {
3238
+ content: settings,
3239
+ ...finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : {}
3240
+ };
2914
3241
  return this.httpClient.fetchPayload(
2915
3242
  "/v1/settings/{groupId}",
2916
3243
  "patch",
@@ -2925,7 +3252,7 @@ var _SettingsClient = class _SettingsClient {
2925
3252
  async fetchWithTag(options) {
2926
3253
  const query = {};
2927
3254
  const includeValue = options?.include ?? this.includeFields;
2928
- const localeValueFinal = options?.locale ?? this.localeValue;
3255
+ const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
2929
3256
  if (includeValue) query.include = includeValue.join(",");
2930
3257
  if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
2931
3258
  const response = await this.httpClient.send(
@@ -2937,16 +3264,20 @@ var _SettingsClient = class _SettingsClient {
2937
3264
  }
2938
3265
  /**
2939
3266
  * Reset settings to default values
2940
- * @param locale - Optional locale for localized settings
3267
+ *
3268
+ * The route reads its locale from `?locale=` and takes no body, so that is where it is sent.
3269
+ *
3270
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
3271
+ * overrides the client's own)
2941
3272
  */
2942
3273
  async reset(locale, options) {
2943
- const finalLocale = locale ?? this.localeValue;
3274
+ const finalLocale = this.localeOf(locale);
2944
3275
  return this.httpClient.fetchPayload(
2945
3276
  "/v1/settings/{groupId}/reset",
2946
3277
  "post",
2947
3278
  {
2948
3279
  path: { groupId: this.groupId },
2949
- body: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
3280
+ query: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
2950
3281
  headers: writeHeaders(options)
2951
3282
  }
2952
3283
  );
@@ -2977,15 +3308,17 @@ var _SettingsClient = class _SettingsClient {
2977
3308
  * Get version history for one locale of the settings group.
2978
3309
  *
2979
3310
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
2980
- * schema default, no fallback is applied, and a locale with no history returns an empty array
2981
- * rather than another locale's rows. Every row names the locale it belongs to.
3311
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
3312
+ * fallback is applied, and a locale with no history returns an empty array rather than another
3313
+ * locale's rows. Every row names the locale it belongs to.
2982
3314
  */
2983
3315
  async versions(options) {
3316
+ const locale = this.localeOf(options?.locale);
2984
3317
  const payload = await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions", "get", {
2985
3318
  path: { groupId: this.groupId },
2986
3319
  query: {
2987
3320
  limit: options?.limit ?? 10,
2988
- ...options?.locale === void 0 ? {} : { locale: options.locale }
3321
+ ...locale === void 0 ? {} : { locale }
2989
3322
  }
2990
3323
  });
2991
3324
  return payload.versions;
@@ -2993,20 +3326,25 @@ var _SettingsClient = class _SettingsClient {
2993
3326
  /**
2994
3327
  * Get a specific version of the settings.
2995
3328
  *
2996
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
2997
- * different content in each one.
3329
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
3330
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
2998
3331
  */
2999
3332
  async version(versionNumber, options) {
3333
+ const locale = this.localeOf(options?.locale);
3000
3334
  try {
3001
3335
  return await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions/{versionNumber}", "get", {
3002
3336
  path: { groupId: this.groupId, versionNumber: String(versionNumber) },
3003
- query: options?.locale === void 0 ? void 0 : { locale: options.locale }
3337
+ query: locale === void 0 ? void 0 : { locale }
3004
3338
  });
3005
3339
  } catch (error) {
3006
3340
  if (isResourceNotFound(error)) return null;
3007
3341
  throw error;
3008
3342
  }
3009
3343
  }
3344
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
3345
+ localeOf(named) {
3346
+ return callLocale(named ?? this.localeValue, this.clientLocale());
3347
+ }
3010
3348
  /**
3011
3349
  * Get the settings group ID
3012
3350
  */
@@ -3027,14 +3365,31 @@ var SettingsClient = _SettingsClient;
3027
3365
 
3028
3366
  // src/search/search-client.ts
3029
3367
  var _SearchBuilder = class _SearchBuilder {
3030
- constructor(httpClient, query) {
3368
+ /**
3369
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3370
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3371
+ */
3372
+ constructor(httpClient, query, locale) {
3031
3373
  this.httpClient = httpClient;
3032
3374
  __publicField(this, "query");
3033
3375
  __publicField(this, "searchOptions", {});
3376
+ __publicField(this, "requestHeaders");
3377
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
3378
+ __publicField(this, "clientLocale");
3034
3379
  this.query = query;
3380
+ this.clientLocale = readClientLocale(locale);
3035
3381
  }
3036
3382
  /**
3037
- * Search within a single content type
3383
+ * Headers this search adds to the client's own, e.g. `X-RelyIO-Dataset` to search another
3384
+ * dataset the key can see. A name the client already sends is replaced for this search only.
3385
+ */
3386
+ headers(headers) {
3387
+ this.requestHeaders = headers;
3388
+ return this;
3389
+ }
3390
+ /**
3391
+ * Search within a single content type. Where a schema types the client, the name is one of its
3392
+ * content types and the results are that type's entries.
3038
3393
  * @param contentType - Content type to search in
3039
3394
  */
3040
3395
  in(contentType) {
@@ -3043,7 +3398,8 @@ var _SearchBuilder = class _SearchBuilder {
3043
3398
  return this;
3044
3399
  }
3045
3400
  /**
3046
- * Search across multiple content types
3401
+ * Search across multiple content types. Where a schema types the client, the names are its content
3402
+ * types and the results are a union of their entries — every type's, for `'*'`.
3047
3403
  * @param contentTypes - Array of content types or '*' for all
3048
3404
  */
3049
3405
  across(contentTypes) {
@@ -3052,10 +3408,12 @@ var _SearchBuilder = class _SearchBuilder {
3052
3408
  return this;
3053
3409
  }
3054
3410
  /**
3055
- * Add filter conditions
3411
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
3412
+ * refused here, before anything is sent.
3056
3413
  * @param conditions - Filter conditions
3057
3414
  */
3058
3415
  where(conditions) {
3416
+ refuseMetadataConditions(conditions);
3059
3417
  this.searchOptions.where = {
3060
3418
  ...this.searchOptions.where,
3061
3419
  ...conditions
@@ -3078,6 +3436,16 @@ var _SearchBuilder = class _SearchBuilder {
3078
3436
  this.searchOptions.fields = projection;
3079
3437
  return this;
3080
3438
  }
3439
+ /**
3440
+ * Order the results by a field instead of by relevance. Called again, it adds a tie-breaker.
3441
+ * `_score` names relevance itself.
3442
+ * @param field - Field path to sort by (e.g. `updatedAt`, `pricing.basePrice`)
3443
+ * @param direction - `asc` or `desc` (the route's default is `desc`)
3444
+ */
3445
+ sort(field, direction = "desc") {
3446
+ this.searchOptions.sort = [...this.searchOptions.sort ?? [], { field, direction }];
3447
+ return this;
3448
+ }
3081
3449
  /**
3082
3450
  * Limit number of results
3083
3451
  * @param count - Maximum results
@@ -3138,6 +3506,9 @@ var _SearchBuilder = class _SearchBuilder {
3138
3506
  if (this.searchOptions.fields) {
3139
3507
  body.fields = this.searchOptions.fields;
3140
3508
  }
3509
+ if (this.searchOptions.sort) {
3510
+ body.sort = this.searchOptions.sort;
3511
+ }
3141
3512
  if (this.searchOptions.limit !== void 0) {
3142
3513
  body.limit = this.searchOptions.limit;
3143
3514
  }
@@ -3150,13 +3521,14 @@ var _SearchBuilder = class _SearchBuilder {
3150
3521
  if (this.searchOptions.explain === true) {
3151
3522
  body.explain = true;
3152
3523
  }
3153
- if (this.searchOptions.locale != null && this.searchOptions.locale !== "") {
3154
- body.locale = this.searchOptions.locale;
3524
+ const locale = this.searchOptions.locale ?? this.clientLocale();
3525
+ if (locale != null && locale !== "") {
3526
+ body.locale = locale;
3155
3527
  }
3156
3528
  const response = await this.httpClient.send(
3157
3529
  "/v1/search",
3158
3530
  "post",
3159
- { body }
3531
+ { body, headers: this.requestHeaders }
3160
3532
  );
3161
3533
  return response.body;
3162
3534
  }
@@ -3176,11 +3548,18 @@ var _SearchBuilder = class _SearchBuilder {
3176
3548
  __name(_SearchBuilder, "SearchBuilder");
3177
3549
  var SearchBuilder = _SearchBuilder;
3178
3550
  var _AutocompleteBuilder = class _AutocompleteBuilder {
3179
- constructor(httpClient, query) {
3551
+ /**
3552
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3553
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3554
+ */
3555
+ constructor(httpClient, query, locale) {
3180
3556
  this.httpClient = httpClient;
3181
3557
  __publicField(this, "query");
3182
3558
  __publicField(this, "autocompleteOptions", {});
3559
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
3560
+ __publicField(this, "clientLocale");
3183
3561
  this.query = query;
3562
+ this.clientLocale = readClientLocale(locale);
3184
3563
  }
3185
3564
  /**
3186
3565
  * Autocomplete within a content type
@@ -3206,10 +3585,12 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
3206
3585
  return this;
3207
3586
  }
3208
3587
  /**
3209
- * Add filter conditions
3588
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
3589
+ * refused here, before anything is sent.
3210
3590
  * @param conditions - Filter conditions
3211
3591
  */
3212
3592
  where(conditions) {
3593
+ refuseMetadataConditions(conditions);
3213
3594
  this.autocompleteOptions.where = {
3214
3595
  ...this.autocompleteOptions.where,
3215
3596
  ...conditions
@@ -3256,8 +3637,9 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
3256
3637
  if (this.autocompleteOptions.limit !== void 0) {
3257
3638
  body.limit = this.autocompleteOptions.limit;
3258
3639
  }
3259
- if (this.autocompleteOptions.locale != null && this.autocompleteOptions.locale !== "") {
3260
- body.locale = this.autocompleteOptions.locale;
3640
+ const locale = this.autocompleteOptions.locale ?? this.clientLocale();
3641
+ if (locale != null && locale !== "") {
3642
+ body.locale = locale;
3261
3643
  }
3262
3644
  const response = await this.httpClient.send("/v1/search/autocomplete", "post", { body });
3263
3645
  return response.body;
@@ -3272,11 +3654,27 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
3272
3654
  __name(_AutocompleteBuilder, "AutocompleteBuilder");
3273
3655
  var AutocompleteBuilder = _AutocompleteBuilder;
3274
3656
  var _SimilarBuilder = class _SimilarBuilder {
3275
- constructor(httpClient, sourceId) {
3657
+ /**
3658
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
3659
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
3660
+ */
3661
+ constructor(httpClient, sourceId, locale) {
3276
3662
  this.httpClient = httpClient;
3277
3663
  __publicField(this, "sourceId");
3278
3664
  __publicField(this, "similarOptions", {});
3665
+ __publicField(this, "requestHeaders");
3666
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
3667
+ __publicField(this, "clientLocale");
3279
3668
  this.sourceId = sourceId;
3669
+ this.clientLocale = readClientLocale(locale);
3670
+ }
3671
+ /**
3672
+ * Headers this read adds to the client's own, e.g. `X-RelyIO-Dataset` to read another dataset
3673
+ * the key can see. A name the client already sends is replaced for this read only.
3674
+ */
3675
+ headers(headers) {
3676
+ this.requestHeaders = headers;
3677
+ return this;
3280
3678
  }
3281
3679
  /**
3282
3680
  * Find similar content within a content type
@@ -3284,19 +3682,24 @@ var _SimilarBuilder = class _SimilarBuilder {
3284
3682
  */
3285
3683
  in(contentType) {
3286
3684
  this.similarOptions.contentType = contentType;
3685
+ this.similarOptions.contentTypes = void 0;
3287
3686
  return this;
3288
3687
  }
3289
3688
  /**
3290
- * Add filter conditions
3291
- * @param conditions - Filter conditions
3689
+ * Find similar content across several content types, or `'*'` for every type
3690
+ * @param contentTypes - Array of content types or '*' for all
3292
3691
  */
3293
- where(conditions) {
3294
- this.similarOptions.where = {
3295
- ...this.similarOptions.where,
3296
- ...conditions
3297
- };
3692
+ across(contentTypes) {
3693
+ this.similarOptions.contentTypes = contentTypes;
3694
+ this.similarOptions.contentType = void 0;
3298
3695
  return this;
3299
3696
  }
3697
+ /*
3698
+ * No `where()` (REL-1452). Similar ranks from the source entry's stored vector, and the vector
3699
+ * index can pre-filter by content type and locale only — never by an entry field. The API used to
3700
+ * accept `where` here and apply nothing; it now refuses the property, so the builder does not
3701
+ * offer a filter that cannot be honoured. Narrow with `.in()`, `.across()` and `.locale()`.
3702
+ */
3300
3703
  /**
3301
3704
  * Limit number of results
3302
3705
  * @param count - Maximum results
@@ -3317,26 +3720,30 @@ var _SimilarBuilder = class _SimilarBuilder {
3317
3720
  * Execute the similar query
3318
3721
  */
3319
3722
  async execute() {
3320
- if (this.similarOptions.contentType == null || this.similarOptions.contentType === "") {
3321
- throw new Error('Content type is required for similar search. Use .in("contentType")');
3723
+ const { contentType, contentTypes } = this.similarOptions;
3724
+ if ((contentType == null || contentType === "") && contentTypes == null) {
3725
+ throw new Error(
3726
+ 'Content type is required for similar search. Use .in("contentType") or .across("*")'
3727
+ );
3322
3728
  }
3323
- const body = {
3324
- source: this.sourceId,
3325
- contentType: this.similarOptions.contentType
3326
- };
3327
- if (this.similarOptions.where && Object.keys(this.similarOptions.where).length > 0) {
3328
- body.where = this.similarOptions.where;
3729
+ const body = { source: this.sourceId };
3730
+ if (contentType != null && contentType !== "") {
3731
+ body.contentType = contentType;
3732
+ }
3733
+ if (contentTypes != null) {
3734
+ body.contentTypes = contentTypes;
3329
3735
  }
3330
3736
  if (this.similarOptions.limit !== void 0) {
3331
3737
  body.limit = this.similarOptions.limit;
3332
3738
  }
3333
- if (this.similarOptions.locale != null && this.similarOptions.locale !== "") {
3334
- body.locale = this.similarOptions.locale;
3739
+ const locale = this.similarOptions.locale ?? this.clientLocale();
3740
+ if (locale != null && locale !== "") {
3741
+ body.locale = locale;
3335
3742
  }
3336
3743
  const response = await this.httpClient.send(
3337
3744
  "/v1/search/similar",
3338
3745
  "post",
3339
- { body }
3746
+ { body, headers: this.requestHeaders }
3340
3747
  );
3341
3748
  return response.body;
3342
3749
  }
@@ -3356,37 +3763,37 @@ var _SimilarBuilder = class _SimilarBuilder {
3356
3763
  __name(_SimilarBuilder, "SimilarBuilder");
3357
3764
  var SimilarBuilder = _SimilarBuilder;
3358
3765
  var _SearchClient = class _SearchClient {
3359
- constructor(httpClient) {
3766
+ /**
3767
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`): every builder
3768
+ * here sends it when the query names none, as `content()`'s reads do — the function
3769
+ * `TypedRelyIOClient` hands over, or a locale fixed for this client
3770
+ */
3771
+ constructor(httpClient, locale) {
3360
3772
  this.httpClient = httpClient;
3773
+ /** The client's locale, handed to every builder here to ask when it sends. */
3774
+ __publicField(this, "clientLocale");
3775
+ this.clientLocale = readClientLocale(locale);
3361
3776
  }
3362
3777
  /**
3363
3778
  * Start a search query
3364
3779
  * @param query - Search query string
3365
3780
  */
3366
3781
  search(query) {
3367
- return new SearchBuilder(this.httpClient, query);
3782
+ return new SearchBuilder(this.httpClient, query, this.clientLocale);
3368
3783
  }
3369
3784
  /**
3370
3785
  * Start an autocomplete query
3371
3786
  * @param query - Partial query to autocomplete
3372
3787
  */
3373
3788
  autocomplete(query) {
3374
- return new AutocompleteBuilder(this.httpClient, query);
3789
+ return new AutocompleteBuilder(this.httpClient, query, this.clientLocale);
3375
3790
  }
3376
3791
  /**
3377
3792
  * Find content similar to a given entry
3378
3793
  * @param sourceId - Entry ID to find similar content for
3379
3794
  */
3380
3795
  similar(sourceId) {
3381
- return new SimilarBuilder(this.httpClient, sourceId);
3382
- }
3383
- /**
3384
- * Quick search helper - searches all content types
3385
- * @param query - Search query
3386
- * @param limit - Max results (default 20)
3387
- */
3388
- async global(query, limit = 20) {
3389
- return this.search(query).across("*").limit(limit).execute();
3796
+ return new SimilarBuilder(this.httpClient, sourceId, this.clientLocale);
3390
3797
  }
3391
3798
  };
3392
3799
  __name(_SearchClient, "SearchClient");
@@ -3394,7 +3801,12 @@ var SearchClient = _SearchClient;
3394
3801
 
3395
3802
  // src/batch/batch-client.ts
3396
3803
  var _BatchBuilder = class _BatchBuilder {
3397
- constructor(httpClient) {
3804
+ /**
3805
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), each
3806
+ * operation's when it names none: the function `TypedRelyIOClient` hands over, or a locale fixed
3807
+ * for this batch
3808
+ */
3809
+ constructor(httpClient, locale) {
3398
3810
  this.httpClient = httpClient;
3399
3811
  __publicField(this, "operations", []);
3400
3812
  __publicField(this, "defaultOptions", {
@@ -3403,6 +3815,18 @@ var _BatchBuilder = class _BatchBuilder {
3403
3815
  returnData: true,
3404
3816
  continueOnError: true
3405
3817
  });
3818
+ __publicField(this, "requestHeaders");
3819
+ /** The client's locale, asked as each operation is added rather than copied when this was built. */
3820
+ __publicField(this, "clientLocale");
3821
+ this.clientLocale = readClientLocale(locale);
3822
+ }
3823
+ /**
3824
+ * An operation's body with its locale: the one it names, else the client's as it is when the
3825
+ * operation is added.
3826
+ */
3827
+ localized(data) {
3828
+ const locale = callLocale(data.locale, this.clientLocale());
3829
+ return locale === void 0 ? data : { ...data, locale };
3406
3830
  }
3407
3831
  // ==========================================================================
3408
3832
  // ENTRY OPERATIONS
@@ -3418,7 +3842,7 @@ var _BatchBuilder = class _BatchBuilder {
3418
3842
  id,
3419
3843
  method: "POST",
3420
3844
  path: `/${contentType}`,
3421
- body: data
3845
+ body: this.localized(data)
3422
3846
  });
3423
3847
  return this;
3424
3848
  }
@@ -3438,7 +3862,7 @@ var _BatchBuilder = class _BatchBuilder {
3438
3862
  id,
3439
3863
  method: "PATCH",
3440
3864
  path: `/${contentType}/${entryId}`,
3441
- body: data
3865
+ body: this.localized(data)
3442
3866
  });
3443
3867
  return this;
3444
3868
  }
@@ -3458,7 +3882,7 @@ var _BatchBuilder = class _BatchBuilder {
3458
3882
  id,
3459
3883
  method: "PUT",
3460
3884
  path: `/${contentType}/${entryId}`,
3461
- body: data
3885
+ body: this.localized(data)
3462
3886
  });
3463
3887
  return this;
3464
3888
  }
@@ -3490,7 +3914,7 @@ var _BatchBuilder = class _BatchBuilder {
3490
3914
  id,
3491
3915
  method: "PATCH",
3492
3916
  path: `/_singletons/${singletonKey}`,
3493
- body: data
3917
+ body: this.localized(data)
3494
3918
  });
3495
3919
  return this;
3496
3920
  }
@@ -3505,7 +3929,7 @@ var _BatchBuilder = class _BatchBuilder {
3505
3929
  id,
3506
3930
  method: "POST",
3507
3931
  path: `/_singletons/${singletonKey}`,
3508
- body: data
3932
+ body: this.localized(data)
3509
3933
  });
3510
3934
  return this;
3511
3935
  }
@@ -3513,7 +3937,8 @@ var _BatchBuilder = class _BatchBuilder {
3513
3937
  // RAW OPERATIONS
3514
3938
  // ==========================================================================
3515
3939
  /**
3516
- * Add a raw operation (for advanced use cases)
3940
+ * Add a raw operation (for advanced use cases). It is sent exactly as written: the client's
3941
+ * locale is not added to it.
3517
3942
  * @param operation - The operation to add
3518
3943
  */
3519
3944
  raw(operation) {
@@ -3604,6 +4029,15 @@ var _BatchBuilder = class _BatchBuilder {
3604
4029
  this.defaultOptions.continueOnError = false;
3605
4030
  return this;
3606
4031
  }
4032
+ /**
4033
+ * Headers the batch request adds — e.g. `{ 'X-RelyIO-Dataset': 'staging' }` to write a dataset
4034
+ * other than the client's. They replace the client's own header of the same name for this
4035
+ * request alone, and apply to every operation in it: a batch is one request.
4036
+ */
4037
+ headers(headers) {
4038
+ this.requestHeaders = { ...this.requestHeaders, ...headers };
4039
+ return this;
4040
+ }
3607
4041
  // ==========================================================================
3608
4042
  // EXECUTION
3609
4043
  // ==========================================================================
@@ -3630,9 +4064,10 @@ var _BatchBuilder = class _BatchBuilder {
3630
4064
  * Clone the builder
3631
4065
  */
3632
4066
  clone() {
3633
- const cloned = new _BatchBuilder(this.httpClient);
4067
+ const cloned = new _BatchBuilder(this.httpClient, this.clientLocale);
3634
4068
  cloned.operations = [...this.operations];
3635
4069
  cloned.defaultOptions = { ...this.defaultOptions };
4070
+ cloned.requestHeaders = this.requestHeaders === void 0 ? void 0 : { ...this.requestHeaders };
3636
4071
  return cloned;
3637
4072
  }
3638
4073
  /**
@@ -3650,7 +4085,8 @@ var _BatchBuilder = class _BatchBuilder {
3650
4085
  }
3651
4086
  const finalOptions = { ...this.defaultOptions, ...options };
3652
4087
  return this.httpClient.fetchPayload("/v1/batch", "post", {
3653
- body: { operations: this.operations, options: finalOptions }
4088
+ body: { operations: this.operations, options: finalOptions },
4089
+ headers: this.requestHeaders
3654
4090
  });
3655
4091
  }
3656
4092
  /**
@@ -3681,14 +4117,21 @@ var _BatchBuilder = class _BatchBuilder {
3681
4117
  __name(_BatchBuilder, "BatchBuilder");
3682
4118
  var BatchBuilder = _BatchBuilder;
3683
4119
  var _BatchClient = class _BatchClient {
3684
- constructor(httpClient) {
4120
+ /**
4121
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, or a locale
4122
+ * fixed for this client
4123
+ */
4124
+ constructor(httpClient, locale) {
3685
4125
  this.httpClient = httpClient;
4126
+ /** The client's locale, handed to every batch this builds to ask as operations are added. */
4127
+ __publicField(this, "clientLocale");
4128
+ this.clientLocale = readClientLocale(locale);
3686
4129
  }
3687
4130
  /**
3688
- * Create a new batch builder
4131
+ * Create a new batch builder, whose operations default to this client's locale
3689
4132
  */
3690
4133
  create() {
3691
- return new BatchBuilder(this.httpClient);
4134
+ return new BatchBuilder(this.httpClient, this.clientLocale);
3692
4135
  }
3693
4136
  /**
3694
4137
  * Quick bulk create entries
@@ -3730,12 +4173,27 @@ __name(_BatchClient, "BatchClient");
3730
4173
  var BatchClient = _BatchClient;
3731
4174
 
3732
4175
  // src/queries/adhoc-query-client.ts
4176
+ function withClientLocale(parameters, clientLocale) {
4177
+ if (clientLocale === void 0 || clientLocale === "" || parameters?.locale != null) {
4178
+ return parameters;
4179
+ }
4180
+ return { ...parameters, locale: clientLocale };
4181
+ }
4182
+ __name(withClientLocale, "withClientLocale");
3733
4183
  var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3734
- constructor(httpClient) {
4184
+ /**
4185
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
4186
+ * `locale` parameter when `.param('locale', …)` binds none: the function `TypedRelyIOClient`
4187
+ * hands over, or a locale fixed for this builder
4188
+ */
4189
+ constructor(httpClient, locale) {
3735
4190
  this.httpClient = httpClient;
3736
4191
  __publicField(this, "queryDef", {});
3737
4192
  __publicField(this, "parameters", {});
3738
4193
  __publicField(this, "options", {});
4194
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
4195
+ __publicField(this, "clientLocale");
4196
+ this.clientLocale = readClientLocale(locale);
3739
4197
  }
3740
4198
  // ==========================================================================
3741
4199
  // QUERY BLOCKS
@@ -3780,14 +4238,6 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3780
4238
  this.queryDef.search = config;
3781
4239
  return this;
3782
4240
  }
3783
- /**
3784
- * Add similar block
3785
- * @param config - Similar configuration
3786
- */
3787
- similar(config) {
3788
- this.queryDef.similar = config;
3789
- return this;
3790
- }
3791
4241
  // ==========================================================================
3792
4242
  // FETCH MODIFIERS
3793
4243
  // ==========================================================================
@@ -3964,16 +4414,17 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
3964
4414
  * Execute the query
3965
4415
  */
3966
4416
  async execute() {
3967
- if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search && !this.queryDef.similar) {
4417
+ if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search) {
3968
4418
  throw new Error(
3969
- "Query must have at least one of: fetch, aggregate, search, or similar. Use .from(), .aggregate(), .search(), or .similar()"
4419
+ "Query must have at least one of: fetch, aggregate or search. Use .from(), .aggregate() or .search()"
3970
4420
  );
3971
4421
  }
3972
4422
  const body = {
3973
4423
  query: this.queryDef
3974
4424
  };
3975
- if (Object.keys(this.parameters).length > 0) {
3976
- body.parameters = this.parameters;
4425
+ const parameters = withClientLocale(this.parameters, this.clientLocale());
4426
+ if (parameters !== void 0 && Object.keys(parameters).length > 0) {
4427
+ body.parameters = parameters;
3977
4428
  }
3978
4429
  if (Object.keys(this.options).length > 0) {
3979
4430
  body.options = this.options;
@@ -4004,7 +4455,7 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
4004
4455
  * Clone the builder
4005
4456
  */
4006
4457
  clone() {
4007
- const cloned = new _AdhocQueryBuilder(this.httpClient);
4458
+ const cloned = new _AdhocQueryBuilder(this.httpClient, this.clientLocale);
4008
4459
  cloned.queryDef = JSON.parse(JSON.stringify(this.queryDef));
4009
4460
  cloned.parameters = { ...this.parameters };
4010
4461
  cloned.options = { ...this.options };
@@ -4014,27 +4465,39 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
4014
4465
  __name(_AdhocQueryBuilder, "AdhocQueryBuilder");
4015
4466
  var AdhocQueryBuilder = _AdhocQueryBuilder;
4016
4467
  var _AdhocQueryClient = class _AdhocQueryClient {
4017
- constructor(httpClient) {
4468
+ /**
4469
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
4470
+ * `locale` parameter of every query that binds none: the function `TypedRelyIOClient` hands
4471
+ * over, or a locale fixed for this client
4472
+ */
4473
+ constructor(httpClient, locale) {
4018
4474
  this.httpClient = httpClient;
4475
+ /** The client's locale, asked on every query rather than copied when this client was taken. */
4476
+ __publicField(this, "clientLocale");
4477
+ this.clientLocale = readClientLocale(locale);
4019
4478
  }
4020
4479
  /**
4021
4480
  * Create a new query builder
4022
4481
  */
4023
4482
  build() {
4024
- return new AdhocQueryBuilder(this.httpClient);
4483
+ return new AdhocQueryBuilder(this.httpClient, this.clientLocale);
4025
4484
  }
4026
4485
  /**
4027
4486
  * Execute a query definition directly
4028
4487
  * @param definition - Query definition
4029
4488
  * @param parameters - Parameter values
4030
4489
  * @param options - Execution options
4490
+ * @param request - `headers` this one request adds to the client's own, e.g. `X-RelyIO-Dataset`
4491
+ * to query another dataset the key can see. A name the client already sends is replaced for
4492
+ * this request only.
4031
4493
  */
4032
- async execute(definition, parameters, options) {
4494
+ async execute(definition, parameters, options, request) {
4033
4495
  const body = {
4034
4496
  query: definition
4035
4497
  };
4036
- if (parameters && Object.keys(parameters).length > 0) {
4037
- body.parameters = parameters;
4498
+ const sent = withClientLocale(parameters, this.clientLocale());
4499
+ if (sent !== void 0 && Object.keys(sent).length > 0) {
4500
+ body.parameters = sent;
4038
4501
  }
4039
4502
  if (options && Object.keys(options).length > 0) {
4040
4503
  body.options = options;
@@ -4042,7 +4505,7 @@ var _AdhocQueryClient = class _AdhocQueryClient {
4042
4505
  return this.httpClient.fetchPayload(
4043
4506
  "/v1/query",
4044
4507
  "post",
4045
- { body }
4508
+ { body, headers: request?.headers }
4046
4509
  );
4047
4510
  }
4048
4511
  /**
@@ -4106,12 +4569,12 @@ async function* pollChanges(http, options = {}) {
4106
4569
  let since = options.since;
4107
4570
  let resynced;
4108
4571
  for (; ; ) {
4109
- if (aborted(signal)) return;
4572
+ if (isAborted(signal)) return;
4110
4573
  let response;
4111
4574
  try {
4112
4575
  response = await pollOnce(http, since, options);
4113
4576
  } catch (error) {
4114
- if (aborted(signal)) return;
4577
+ if (isAborted(signal)) return;
4115
4578
  if (!(error instanceof ResourceExpiredError) || since === void 0) throw error;
4116
4579
  const expired = ChangesExpiredError.of(error);
4117
4580
  const onExpired = options.onExpired ?? "throw";
@@ -4129,11 +4592,11 @@ async function* pollChanges(http, options = {}) {
4129
4592
  const expired = resynced;
4130
4593
  resynced = void 0;
4131
4594
  await options.onExpired(expired);
4132
- if (aborted(signal)) return;
4595
+ if (isAborted(signal)) return;
4133
4596
  }
4134
4597
  for (const change of data) {
4135
4598
  yield change;
4136
- if (aborted(signal)) return;
4599
+ if (isAborted(signal)) return;
4137
4600
  }
4138
4601
  if (data.length === 0) {
4139
4602
  const wait = parseRetryAfterMs(headerValue(response.headers, "Retry-After"), Date.now());
@@ -4142,6 +4605,21 @@ async function* pollChanges(http, options = {}) {
4142
4605
  }
4143
4606
  }
4144
4607
  __name(pollChanges, "pollChanges");
4608
+ async function readChangesHead(http, options = {}) {
4609
+ const response = await http.send("/v1/changes", "get", {
4610
+ query: {},
4611
+ ...options.signal === void 0 ? {} : { signal: options.signal }
4612
+ });
4613
+ const { data, page } = response.body;
4614
+ if (page.nextCursor === null) {
4615
+ throw new Error("GET /v1/changes answered without page.nextCursor");
4616
+ }
4617
+ if (data.length > 0) {
4618
+ throw new Error("GET /v1/changes without since answered changes; a head carries none");
4619
+ }
4620
+ return page.nextCursor;
4621
+ }
4622
+ __name(readChangesHead, "readChangesHead");
4145
4623
  async function pollOnce(http, since, options) {
4146
4624
  const query = {};
4147
4625
  if (since !== void 0) query.since = since;
@@ -4155,26 +4633,6 @@ async function pollOnce(http, since, options) {
4155
4633
  });
4156
4634
  }
4157
4635
  __name(pollOnce, "pollOnce");
4158
- function sleep(ms, signal) {
4159
- return new Promise((resolve) => {
4160
- if (aborted(signal)) {
4161
- resolve();
4162
- return;
4163
- }
4164
- const done = /* @__PURE__ */ __name(() => {
4165
- clearTimeout(timer);
4166
- signal?.removeEventListener("abort", done);
4167
- resolve();
4168
- }, "done");
4169
- const timer = setTimeout(done, ms);
4170
- signal?.addEventListener("abort", done, { once: true });
4171
- });
4172
- }
4173
- __name(sleep, "sleep");
4174
- function aborted(signal) {
4175
- return signal?.aborted === true;
4176
- }
4177
- __name(aborted, "aborted");
4178
4636
 
4179
4637
  // src/config/dev-detection.ts
4180
4638
  function sandboxStateOf(resolution) {
@@ -4286,7 +4744,7 @@ var DEFAULT_CONFIG = {
4286
4744
  environment: "production",
4287
4745
  headers: {},
4288
4746
  browser: {
4289
- includeCredentials: true,
4747
+ includeCredentials: false,
4290
4748
  useRelativeUrls: false
4291
4749
  },
4292
4750
  cache: {
@@ -4312,54 +4770,48 @@ var DEFAULT_CONFIG = {
4312
4770
  }
4313
4771
  };
4314
4772
  function validateConfig(config) {
4315
- if (!config.apiKey || config.apiKey.length === 0) {
4316
- throw new Error("API key is required");
4317
- }
4318
- if (typeof config.apiKey !== "string") {
4773
+ if (config.apiKey != null && typeof config.apiKey !== "string") {
4319
4774
  throw new Error("API key must be a string");
4320
4775
  }
4321
4776
  if (config.baseUrl != null && typeof config.baseUrl !== "string") {
4322
4777
  throw new Error("Base URL must be a string");
4323
4778
  }
4324
- if (config.timeout != null && (typeof config.timeout !== "number" || config.timeout < 0)) {
4325
- throw new Error("Timeout must be a positive number");
4326
- }
4327
- if (config.retryAttempts != null && (typeof config.retryAttempts !== "number" || config.retryAttempts < 0)) {
4328
- throw new Error("Retry attempts must be a positive number");
4779
+ if (config.timeout != null) assertRequestTimeout(config.timeout);
4780
+ if (config.retryAttempts != null && !(Number.isInteger(config.retryAttempts) && config.retryAttempts >= 1)) {
4781
+ throw new Error(
4782
+ `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)}`
4783
+ );
4329
4784
  }
4330
4785
  }
4331
4786
  __name(validateConfig, "validateConfig");
4332
4787
  var devOverrideNotified = false;
4333
4788
  function resolveConfig(userConfig) {
4334
4789
  validateConfig(userConfig);
4335
- const merged = {
4336
- ...DEFAULT_CONFIG,
4337
- ...userConfig,
4338
- headers: {
4339
- ...DEFAULT_CONFIG.headers,
4340
- ...userConfig.headers
4341
- },
4342
- browser: {
4343
- ...DEFAULT_CONFIG.browser,
4344
- ...userConfig.browser
4345
- },
4346
- cache: {
4347
- ...DEFAULT_CONFIG.cache,
4348
- ...userConfig.cache
4349
- },
4350
- realtime: {
4351
- ...DEFAULT_CONFIG.realtime,
4352
- ...userConfig.realtime
4353
- },
4354
- debug: {
4355
- ...DEFAULT_CONFIG.debug,
4356
- ...userConfig.debug
4357
- }
4358
- };
4359
- const dev = resolveDevOverride(userConfig.dev);
4790
+ return withHandshake(withDefaults(DEFAULT_CONFIG, userConfig, DEFAULT_CONFIG));
4791
+ }
4792
+ __name(resolveConfig, "resolveConfig");
4793
+ function resolveConfigUpdate(configured, update) {
4794
+ validateConfig(update);
4795
+ const base = update.apiKey === void 0 ? configured : withoutKeyHeader(configured);
4796
+ return withHandshake(withDefaults(base, update, DEFAULT_CONFIG));
4797
+ }
4798
+ __name(resolveConfigUpdate, "resolveConfigUpdate");
4799
+ function withConfiguredKey(configured, apiKey) {
4800
+ return { ...withoutKeyHeader(configured), apiKey };
4801
+ }
4802
+ __name(withConfiguredKey, "withConfiguredKey");
4803
+ function withoutKeyHeader(configured) {
4804
+ return { ...configured, headers: layerHeaders(configured.headers, { [API_KEY_HEADER]: null }) };
4805
+ }
4806
+ __name(withoutKeyHeader, "withoutKeyHeader");
4807
+ function withHandshake(configured) {
4808
+ const dev = resolveDevOverride(configured.dev);
4809
+ const merged = withDefaults(
4810
+ configured,
4811
+ dev.state === "active" ? { apiKey: dev.apiKey, dataset: dev.sandbox.datasetId } : {},
4812
+ DEFAULT_CONFIG
4813
+ );
4360
4814
  if (dev.state === "active") {
4361
- merged.apiKey = dev.apiKey;
4362
- merged.dataset = dev.sandbox.datasetId;
4363
4815
  if (!devOverrideNotified) {
4364
4816
  devOverrideNotified = true;
4365
4817
  console.info(
@@ -4377,30 +4829,67 @@ function resolveConfig(userConfig) {
4377
4829
  `[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.`
4378
4830
  );
4379
4831
  }
4380
- return { config: merged, sandbox: sandboxStateOf(dev) };
4832
+ return { config: merged, sandbox: sandboxStateOf(dev), configured };
4381
4833
  }
4382
- __name(resolveConfig, "resolveConfig");
4834
+ __name(withHandshake, "withHandshake");
4835
+ function withDefaults(base, given, defaults) {
4836
+ const merged = new Map(Object.entries(base));
4837
+ const givenValues = new Map(Object.entries(given ?? {}));
4838
+ const defaultValues = new Map(Object.entries(defaults));
4839
+ for (const key of /* @__PURE__ */ new Set([...merged.keys(), ...givenValues.keys()])) {
4840
+ const fallback = merged.get(key);
4841
+ const value = givenValues.get(key);
4842
+ const givenBag = isOptionBag(value) ? value : void 0;
4843
+ if (isOptionBag(fallback) && key === "headers") {
4844
+ merged.set(key, layerHeaders(fallback, givenBag));
4845
+ } else if (isOptionBag(fallback)) {
4846
+ const defaultBag = defaultValues.get(key);
4847
+ merged.set(key, withDefaults(fallback, givenBag, isOptionBag(defaultBag) ? defaultBag : {}));
4848
+ } else if (value === null) {
4849
+ if (defaultValues.has(key)) merged.set(key, defaultValues.get(key));
4850
+ else merged.delete(key);
4851
+ } else if (value !== void 0) {
4852
+ merged.set(key, value);
4853
+ }
4854
+ }
4855
+ return Object.fromEntries(merged);
4856
+ }
4857
+ __name(withDefaults, "withDefaults");
4858
+ function isOptionBag(value) {
4859
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4860
+ }
4861
+ __name(isOptionBag, "isOptionBag");
4383
4862
 
4384
4863
  // src/client/create-client.ts
4385
4864
  var API_VERSION_SEGMENT = "v1";
4386
4865
  var _TypedRelyIOClient = class _TypedRelyIOClient {
4387
4866
  constructor(config) {
4867
+ /**
4868
+ * The one HTTP client every sub-client sends through. `updateConfig()` and `setApiKey()` change it
4869
+ * in place rather than replacing it, so a sub-client taken before either sends through the change.
4870
+ */
4388
4871
  __publicField(this, "httpClient");
4389
4872
  __publicField(this, "config");
4873
+ /**
4874
+ * The configuration as `createClient()`, `setApiKey()` and `updateConfig()` gave it, before the
4875
+ * `relyio dev` handshake: what the next update is laid over, and what `withLocale()` starts from.
4876
+ */
4877
+ __publicField(this, "configured");
4390
4878
  __publicField(this, "_sandbox");
4391
- __publicField(this, "_search");
4392
- __publicField(this, "_batch");
4393
- __publicField(this, "_adhocQuery");
4394
4879
  __publicField(this, "_schema");
4880
+ /**
4881
+ * The client's locale as it is when a call is made. Every sub-client and builder is handed this
4882
+ * rather than a copy of the locale, so one taken before `updateConfig({ locale })` sends the new
4883
+ * locale, or none after `locale: null` (REL-1453).
4884
+ */
4885
+ __publicField(this, "currentLocale", /* @__PURE__ */ __name(() => this.config.locale, "currentLocale"));
4395
4886
  const { schema, ...clientConfig } = config;
4396
4887
  this._schema = schema;
4397
4888
  const resolved = resolveConfig(clientConfig);
4398
4889
  this.config = resolved.config;
4890
+ this.configured = resolved.configured;
4399
4891
  this._sandbox = resolved.sandbox;
4400
4892
  this.httpClient = new HttpClient(this.config);
4401
- this._search = new SearchClient(this.httpClient);
4402
- this._batch = new BatchClient(this.httpClient);
4403
- this._adhocQuery = new AdhocQueryClient(this.httpClient);
4404
4893
  }
4405
4894
  // ============================================================================
4406
4895
  // CORE CLIENTS
@@ -4429,10 +4918,10 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4429
4918
  return this._sandbox;
4430
4919
  }
4431
4920
  /**
4432
- * Get the ad-hoc query client
4921
+ * Get the ad-hoc query client. Every query it sends is in the client's locale as it is then.
4433
4922
  */
4434
4923
  get query() {
4435
- return this._adhocQuery;
4924
+ return new AdhocQueryClient(this.httpClient, this.currentLocale);
4436
4925
  }
4437
4926
  // ============================================================================
4438
4927
  // CONTENT OPERATIONS
@@ -4452,7 +4941,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4452
4941
  * ```
4453
4942
  */
4454
4943
  content(contentType) {
4455
- return new ContentClient(this.httpClient, contentType, this.config.locale);
4944
+ return new ContentClient(this.httpClient, contentType, this.currentLocale);
4456
4945
  }
4457
4946
  /**
4458
4947
  * Get an asset client for a specific asset type.
@@ -4473,7 +4962,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4473
4962
  * ```
4474
4963
  */
4475
4964
  asset(assetType) {
4476
- return new AssetClient(this.httpClient, assetType, this.config.locale);
4965
+ return new AssetClient(this.httpClient, assetType, this.currentLocale);
4477
4966
  }
4478
4967
  /**
4479
4968
  * Get a singleton client for a specific singleton key
@@ -4488,7 +4977,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4488
4977
  * ```
4489
4978
  */
4490
4979
  singleton(key) {
4491
- return new SingletonClient(this.httpClient, key);
4980
+ return new SingletonClient(this.httpClient, key, this.currentLocale);
4492
4981
  }
4493
4982
  /**
4494
4983
  * Get a settings client for a specific settings group
@@ -4502,13 +4991,16 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4502
4991
  * ```
4503
4992
  */
4504
4993
  settings(groupId) {
4505
- return new SettingsClient(this.httpClient, groupId);
4994
+ return new SettingsClient(this.httpClient, groupId, this.currentLocale);
4506
4995
  }
4507
4996
  // ============================================================================
4508
4997
  // SEARCH OPERATIONS
4509
4998
  // ============================================================================
4510
4999
  /**
4511
- * Start a search query with full-text, semantic, or hybrid search
5000
+ * Start a search query with full-text, semantic, or hybrid search.
5001
+ *
5002
+ * Where a schema types the client, the results are its entries — every content type's until
5003
+ * `in()` or `across()` narrows them (`INV-SS-TYPES-INFERRED`).
4512
5004
  *
4513
5005
  * @example
4514
5006
  * ```typescript
@@ -4521,7 +5013,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4521
5013
  * ```
4522
5014
  */
4523
5015
  search(query) {
4524
- return this._search.search(query);
5016
+ return this.searchClient().search(query);
4525
5017
  }
4526
5018
  /**
4527
5019
  * Start an autocomplete query for search suggestions
@@ -4537,7 +5029,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4537
5029
  * ```
4538
5030
  */
4539
5031
  autocomplete(query) {
4540
- return this._search.autocomplete(query);
5032
+ return this.searchClient().autocomplete(query);
4541
5033
  }
4542
5034
  /**
4543
5035
  * Find content similar to a given entry using vector search
@@ -4552,13 +5044,17 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4552
5044
  * ```
4553
5045
  */
4554
5046
  similar(sourceId) {
4555
- return this._search.similar(sourceId);
5047
+ return this.searchClient().similar(sourceId);
4556
5048
  }
4557
5049
  // ============================================================================
4558
5050
  // BATCH OPERATIONS
4559
5051
  // ============================================================================
4560
5052
  /**
4561
- * Start a batch operation for bulk create/update/delete
5053
+ * Start a batch operation for bulk create/update/delete.
5054
+ *
5055
+ * By default each operation lands or fails on its own. `atomic: true` makes the batch one
5056
+ * transaction, which the API accepts only when every operation is the same kind of write and none
5057
+ * writes a singleton that does not exist yet.
4562
5058
  *
4563
5059
  * @example
4564
5060
  * ```typescript
@@ -4567,13 +5063,23 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4567
5063
  * .update('product', 'entry_abc', { content: { price: 899 } })
4568
5064
  * .delete('product', 'entry_xyz')
4569
5065
  * .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
4570
- * .execute({ atomic: true })
5066
+ * .execute()
4571
5067
  *
4572
5068
  * console.log(result.summary.succeeded)
5069
+ *
5070
+ * // All or nothing: one kind of write
5071
+ * await relyio.batch()
5072
+ * .update('product', 'entry_abc', { content: { price: 899 } })
5073
+ * .update('product', 'entry_def', { content: { price: 799 } })
5074
+ * .execute({ atomic: true })
4573
5075
  * ```
4574
5076
  */
4575
5077
  batch() {
4576
- return this._batch.create();
5078
+ return new BatchClient(this.httpClient, this.currentLocale).create();
5079
+ }
5080
+ /** The search client, whose builders send the client's locale as it is when each one is sent. */
5081
+ searchClient() {
5082
+ return new SearchClient(this.httpClient, this.currentLocale);
4577
5083
  }
4578
5084
  // ============================================================================
4579
5085
  // CHANGES FEED
@@ -4606,6 +5112,25 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4606
5112
  changes(options = {}) {
4607
5113
  return pollChanges(this.httpClient, options);
4608
5114
  }
5115
+ /**
5116
+ * The dataset's current position in the changes feed, as a cursor to start
5117
+ * `changes({ since })` or `followChanges(…, { since })` from. One
5118
+ * `GET /v1/changes` without a cursor: answered at once, holding nothing.
5119
+ *
5120
+ * Take it **before** you read what you will follow. A write your read did not
5121
+ * see is then after the position and replayed; opening the feed afterwards
5122
+ * without a `since` starts after it and misses it.
5123
+ *
5124
+ * @example
5125
+ * ```typescript
5126
+ * const since = await relyio.changesHead()
5127
+ * const post = await relyio.content('post').findById(id).execute()
5128
+ * for await (const change of relyio.changes({ since, ids: [id] })) { … }
5129
+ * ```
5130
+ */
5131
+ changesHead(options = {}) {
5132
+ return readChangesHead(this.httpClient, options);
5133
+ }
4609
5134
  // ============================================================================
4610
5135
  // QUERY OPERATIONS
4611
5136
  // ============================================================================
@@ -4628,7 +5153,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4628
5153
  * ```
4629
5154
  */
4630
5155
  adhoc() {
4631
- return this._adhocQuery.build();
5156
+ return this.query.build();
4632
5157
  }
4633
5158
  /**
4634
5159
  * Execute a predefined query by name (from schema)
@@ -4643,10 +5168,12 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4643
5168
  * ```
4644
5169
  */
4645
5170
  async executeQuery(queryName, params) {
5171
+ const clientLocale = this.config.locale;
5172
+ const namesLocale = params?.locale != null || params?.locales != null;
4646
5173
  const response = await this.httpClient.request({
4647
5174
  method: "GET",
4648
5175
  url: `/${API_VERSION_SEGMENT}/${String(queryName)}`,
4649
- params: params ?? {}
5176
+ params: namesLocale || clientLocale === void 0 || clientLocale === "" ? params ?? {} : { ...params, locale: clientLocale }
4650
5177
  });
4651
5178
  const payload = readPayload(response.body);
4652
5179
  return Array.isArray(payload) ? payload : [payload];
@@ -4711,16 +5238,53 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4711
5238
  }
4712
5239
  }
4713
5240
  /**
4714
- * Update the configuration and reinitialize all clients
5241
+ * Change some of the client's options and keep the rest.
5242
+ *
5243
+ * What you pass is laid over the configuration the client holds, field by field:
5244
+ *
5245
+ * - an option you name replaces the value the client holds;
5246
+ * - an option left out, or given as `undefined`, keeps the value the client holds;
5247
+ * - an option with no default given as `null` is cleared — `locale`, `dataset`, `apiKey`, `dev`,
5248
+ * `fetch`, `browser.onCorsError`, `realtime.wsUrl`, `debug.logger` — so the client runs as though
5249
+ * it had never been given one. An option with a default takes no `null`;
5250
+ * - a bag of options you name — `browser`, `cache`, `realtime`, `debug` — keeps every field of it
5251
+ * you do not name, so `updateConfig({ browser: { includeCredentials: true } })` keeps a
5252
+ * configured `onCorsError`;
5253
+ * - `headers` is laid over the headers the client sends, a name matched without regard to case: a
5254
+ * header you name is added or replaces every spelling of it, every other one is still sent, and a
5255
+ * header given as `null` is no longer sent;
5256
+ * - naming `apiKey` — a key, or `null` — replaces every key the client holds, one given in
5257
+ * `headers` included.
5258
+ *
5259
+ * The configuration it is laid over is what `createClient()`, `setApiKey()` and earlier updates
5260
+ * gave the client. The `relyio dev` handshake is read again, as `createClient()` reads it: while a
5261
+ * sandbox is active its key and dataset are sent over the configured ones, and once it has gone
5262
+ * the configured ones are.
5263
+ *
5264
+ * The client's one HTTP client is changed in place, so every request from now on is sent as the
5265
+ * update says — including one from a `content()`, `asset()`, `singleton()` or `settings()`
5266
+ * sub-client, a `query` client, or a builder such as `search()` or `batch()`, taken before the
5267
+ * call. The locale reaches them too: each reads the client's locale when it sends, so a new
5268
+ * `locale` is the default of its next request and `locale: null` leaves that request with none. A
5269
+ * locale the call names, and a sub-client's own `withLocale()`, still win over it. A client made
5270
+ * by `withLocale()` is a client of its own: an update of this one does not reach it.
5271
+ *
5272
+ * @example
5273
+ * ```typescript
5274
+ * const relyio = createClient({ apiKey, headers: { 'X-Tenant': 'acme' }, browser: { onCorsError } })
5275
+ *
5276
+ * relyio.updateConfig({ headers: { 'X-Trace': traceId } }) // X-Tenant is still sent
5277
+ * relyio.updateConfig({ browser: { includeCredentials: true } }) // onCorsError is kept
5278
+ * relyio.updateConfig({ headers: { 'X-Tenant': null } }) // X-Tenant is no longer sent
5279
+ * relyio.updateConfig({ locale: null }) // reads name no locale of the client's
5280
+ * ```
4715
5281
  */
4716
- updateConfig(newConfig) {
4717
- const resolved = resolveConfig({ ...this.config, ...newConfig });
5282
+ updateConfig(update) {
5283
+ const resolved = resolveConfigUpdate(this.configured, update);
4718
5284
  this.config = resolved.config;
5285
+ this.configured = resolved.configured;
4719
5286
  this._sandbox = resolved.sandbox;
4720
- this.httpClient = new HttpClient(this.config);
4721
- this._search = new SearchClient(this.httpClient);
4722
- this._batch = new BatchClient(this.httpClient);
4723
- this._adhocQuery = new AdhocQueryClient(this.httpClient);
5287
+ this.httpClient.configure(this.config);
4724
5288
  }
4725
5289
  /**
4726
5290
  * Get the current configuration
@@ -4729,11 +5293,31 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4729
5293
  return { ...this.config };
4730
5294
  }
4731
5295
  /**
4732
- * Set the API key
5296
+ * Replace the API key every later request sends as `X-API-Key`.
5297
+ *
5298
+ * It reaches every request this client makes from now on, including those of a `content()`,
5299
+ * `asset()` or other sub-client taken before the call, and `getConfig().apiKey` reports it. A key
5300
+ * given in `headers`, under any spelling, is replaced with it and does not come back on a later
5301
+ * `updateConfig()`. A client already derived with `withLocale()` is a client of its own and keeps
5302
+ * its key.
5303
+ *
5304
+ * An empty or blank key is no key, as it is when passed to `createClient`: the next request
5305
+ * rejects with `MissingApiKeyError` and nothing is sent.
5306
+ *
5307
+ * Under an active `relyio dev` sandbox the sandbox's scoped key stands, as it does over the key
5308
+ * passed to `createClient` — replacing the configured key does not retarget the client at the
5309
+ * sandbox's dataset with a key the sandbox did not issue.
5310
+ *
5311
+ * @example
5312
+ * ```typescript
5313
+ * const relyio = createClient({ apiKey: process.env.RELYIO_API_KEY! })
5314
+ * relyio.setApiKey(rotatedKey) // the next read sends `X-API-Key: <rotatedKey>`
5315
+ * ```
4733
5316
  */
4734
5317
  setApiKey(apiKey) {
4735
- this.config.apiKey = apiKey;
4736
- this.httpClient.setAuthToken(apiKey);
5318
+ this.configured = withConfiguredKey(this.configured, apiKey);
5319
+ if (this._sandbox.state === "active") return;
5320
+ this.httpClient.setApiKey(apiKey);
4737
5321
  }
4738
5322
  /**
4739
5323
  * Get the HTTP client instance (for advanced usage)
@@ -4746,7 +5330,13 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4746
5330
  // ============================================================================
4747
5331
  /**
4748
5332
  * Create a locale-scoped client
4749
- * All content operations on the returned client will use the specified locale
5333
+ *
5334
+ * Every call the returned client builds is in this locale unless the call names one of its own,
5335
+ * which wins: every read — `content()`, `asset()`, `singleton()`, `settings()`, `search()`,
5336
+ * `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — and every write and
5337
+ * version-history read — `create()` and `update()`, the singleton and settings writes, the asset
5338
+ * file writes, `versions()` and `version()`, and each operation `batch()` builds. `restore()`
5339
+ * always names its locale; a delete, and a `batch().raw()` operation, carry none of the client's.
4750
5340
  *
4751
5341
  * Type-safe when schema is provided: autocompletes valid locale codes!
4752
5342
  *
@@ -4754,9 +5344,11 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4754
5344
  * ```typescript
4755
5345
  * const spanish = relyio.withLocale('es-ES') // ← Autocompletes with schema!
4756
5346
  *
4757
- * // All operations use Spanish
5347
+ * // Reads and writes use Spanish
4758
5348
  * const products = await spanish.content('product').query().execute()
4759
5349
  * const homepage = await spanish.singleton('homepage').fetch()
5350
+ * const results = await spanish.search('zapatos').execute()
5351
+ * await spanish.content('product').update(id, { title: 'Zapatos' })
4760
5352
  *
4761
5353
  * // Original client unchanged
4762
5354
  * const englishProducts = await relyio.content('product').query().execute()
@@ -4764,7 +5356,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4764
5356
  */
4765
5357
  withLocale(locale) {
4766
5358
  const newConfig = {
4767
- ...this.getConfig(),
5359
+ ...this.configured,
4768
5360
  locale,
4769
5361
  schema: this._schema
4770
5362
  };
@@ -4813,6 +5405,6 @@ function createClient(config) {
4813
5405
  }
4814
5406
  __name(createClient, "createClient");
4815
5407
 
4816
- export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthenticationError, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ChangesExpiredError, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidFieldTypeError, InvalidPayloadError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, RequiredFieldError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SchemaValidationError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, entityTagOf, isAssetEntry, isResourceNotFound, matchRoute, validateFile };
4817
- //# sourceMappingURL=chunk-5AZUUV5B.js.map
4818
- //# sourceMappingURL=chunk-5AZUUV5B.js.map
5408
+ export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ChangesExpiredError, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidPayloadError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, entityTagOf, isAborted, isAssetEntry, isResourceNotFound, matchRoute, serviceInstructedDelayMs, sleep, validateFile };
5409
+ //# sourceMappingURL=chunk-GYHAVYND.js.map
5410
+ //# sourceMappingURL=chunk-GYHAVYND.js.map