@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.
- package/CHANGELOG.md +540 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-HAQELDZN.cjs → chunk-72UK5U7T.cjs} +70 -60
- package/dist/{chunk-5AZUUV5B.js → chunk-GYHAVYND.js} +1086 -494
- package/dist/{chunk-I3ESNANB.js → chunk-H6IBQSMM.js} +2 -2
- package/dist/{chunk-HT6NFRM2.cjs → chunk-TZL374LS.cjs} +2 -2
- package/dist/{chunk-CIRT6TVT.cjs → chunk-VH2DE7HZ.cjs} +1088 -497
- package/dist/{chunk-XY5KFEFY.js → chunk-YEJUMW4X.js} +70 -60
- package/dist/client/index.cjs +4 -3
- package/dist/client/index.d.cts +4 -4
- package/dist/client/index.d.ts +4 -4
- package/dist/client/index.js +2 -1
- package/dist/{index-C5mRBb6t.d.cts → define-content-type-DiVpbwNs.d.cts} +1629 -665
- package/dist/{index-mXUx2H99.d.ts → define-content-type-DiVpbwNs.d.ts} +1629 -665
- package/dist/{define-schema-DzYXk4HL.d.ts → define-schema-C-5an28C.d.ts} +211 -429
- package/dist/{define-schema-2xbHgtK-.d.cts → define-schema-D7MButVt.d.cts} +211 -429
- package/dist/{index-Dzo-upNS.d.ts → index-1G97sNA8.d.ts} +677 -296
- package/dist/index-BOQIHnsh.d.ts +818 -0
- package/dist/index-DbsTUw3Q.d.cts +818 -0
- package/dist/{index-BozPz4n1.d.cts → index-M0X45k7J.d.cts} +677 -296
- package/dist/index.cjs +180 -103
- package/dist/index.d.cts +307 -32
- package/dist/index.d.ts +307 -32
- package/dist/index.js +95 -8
- package/dist/schema/index.cjs +35 -35
- package/dist/schema/index.d.cts +21 -15
- package/dist/schema/index.d.ts +21 -15
- package/dist/schema/index.js +1 -1
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/utils/index.cjs +19 -19
- package/dist/utils/index.d.cts +10 -1
- package/dist/utils/index.d.ts +10 -1
- package/dist/utils/index.js +1 -1
- package/package.json +4 -3
- package/dist/define-content-type-CBfnTWSS.d.cts +0 -716
- 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
|
-
|
|
332
|
-
|
|
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
|
-
|
|
359
|
-
|
|
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,
|
|
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/
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
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(
|
|
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
|
-
|
|
895
|
-
__publicField(this, "
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
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:
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
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.
|
|
1062
|
+
this.connection = {
|
|
1063
|
+
...this.connection,
|
|
1064
|
+
defaultHeaders: layerHeaders(this.connection.defaultHeaders, headers)
|
|
1065
|
+
};
|
|
1072
1066
|
}
|
|
1073
1067
|
/**
|
|
1074
|
-
*
|
|
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
|
-
|
|
1077
|
-
|
|
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.
|
|
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
|
-
//
|
|
1128
|
-
|
|
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
|
-
|
|
1164
|
-
|
|
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
|
-
|
|
1199
|
+
const { onCorsError } = this.connection.config.browser;
|
|
1200
|
+
if (isBrowser() && onCorsError) {
|
|
1181
1201
|
try {
|
|
1182
|
-
|
|
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
|
-
*
|
|
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 (
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
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
|
-
|
|
1259
|
-
|
|
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
|
-
|
|
1302
|
-
if (
|
|
1303
|
-
|
|
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
|
-
|
|
1312
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
{
|
|
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(
|
|
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 (
|
|
1668
|
-
params.locale =
|
|
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
|
-
|
|
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 (
|
|
1769
|
-
params.locale =
|
|
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
|
-
{
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
1999
|
-
* rather than another locale's rows. Every row names the
|
|
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
|
-
...
|
|
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
|
|
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:
|
|
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
|
-
|
|
2063
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
|
2339
|
-
*
|
|
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
|
-
|
|
2356
|
-
if (entry
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
throw
|
|
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
|
-
|
|
2363
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
-
/**
|
|
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.
|
|
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.
|
|
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
|
-
/**
|
|
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.
|
|
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.
|
|
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
|
|
3005
|
+
/** Get the default locale as it is now: the client's, or the one `withLocale()` fixed. */
|
|
2702
3006
|
getDefaultLocale() {
|
|
2703
|
-
return this.
|
|
3007
|
+
return this.clientLocale();
|
|
2704
3008
|
}
|
|
2705
|
-
/**
|
|
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
|
-
|
|
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 =
|
|
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
|
-
*
|
|
2818
|
-
*
|
|
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
|
-
...
|
|
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
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
2913
|
-
const body =
|
|
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
|
-
*
|
|
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 =
|
|
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
|
-
|
|
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
|
-
*
|
|
2981
|
-
*
|
|
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
|
-
...
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
3154
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3260
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
3291
|
-
* @param
|
|
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
|
-
|
|
3294
|
-
this.similarOptions.
|
|
3295
|
-
|
|
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
|
-
|
|
3321
|
-
|
|
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
|
-
|
|
3325
|
-
contentType
|
|
3326
|
-
}
|
|
3327
|
-
if (
|
|
3328
|
-
body.
|
|
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
|
-
|
|
3334
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
3976
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4037
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
4595
|
+
if (isAborted(signal)) return;
|
|
4133
4596
|
}
|
|
4134
4597
|
for (const change of data) {
|
|
4135
4598
|
yield change;
|
|
4136
|
-
if (
|
|
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:
|
|
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 (
|
|
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
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
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
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
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.
|
|
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
|
-
*
|
|
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(
|
|
4717
|
-
const resolved =
|
|
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
|
|
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
|
-
*
|
|
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.
|
|
4736
|
-
this.
|
|
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
|
-
*
|
|
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
|
-
* //
|
|
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.
|
|
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,
|
|
4817
|
-
//# sourceMappingURL=chunk-
|
|
4818
|
-
//# sourceMappingURL=chunk-
|
|
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
|