@relyio/sdk 0.6.0 → 0.8.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 +400 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-DY2XT7OF.cjs → chunk-72UK5U7T.cjs} +70 -60
- package/dist/{chunk-I3ESNANB.js → chunk-H6IBQSMM.js} +2 -2
- package/dist/{chunk-7ABNXVWL.js → chunk-QFHVF3YF.js} +1617 -404
- package/dist/{chunk-HT6NFRM2.cjs → chunk-TZL374LS.cjs} +2 -2
- package/dist/{chunk-GCMQUM6N.cjs → chunk-XIE7WJV3.cjs} +1621 -407
- package/dist/{chunk-XJVY2CLY.js → chunk-YEJUMW4X.js} +70 -60
- package/dist/client/index.cjs +4 -3
- package/dist/client/index.d.cts +5 -4
- package/dist/client/index.d.ts +5 -4
- package/dist/client/index.js +2 -1
- package/dist/{index-d1Kz1e19.d.cts → define-content-type-cEGjIwT5.d.cts} +1859 -733
- package/dist/{index-yPbhZc6q.d.ts → define-content-type-cEGjIwT5.d.ts} +1859 -733
- package/dist/{define-schema-1kr2HIzN.d.cts → define-schema-BPj2srgh.d.ts} +189 -85
- package/dist/{define-schema-ChvAzY8H.d.ts → define-schema-DgbJ5Kwn.d.cts} +189 -85
- package/dist/index-B_rIWO_l.d.cts +860 -0
- package/dist/index-Cv4tmcrw.d.ts +860 -0
- package/dist/{index-Df1VsfJR.d.cts → index-DBoPPlT1.d.cts} +684 -277
- package/dist/{index-XqoGUaAY.d.ts → index-yRJ2IqM_.d.ts} +684 -277
- package/dist/index.cjs +148 -124
- package/dist/index.d.cts +174 -64
- package/dist/index.d.ts +174 -64
- package/dist/index.js +43 -18
- package/dist/schema/index.cjs +35 -35
- package/dist/schema/index.d.cts +13 -11
- package/dist/schema/index.d.ts +13 -11
- 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 +2 -1
- package/dist/define-content-type-CDB3kyeA.d.cts +0 -1173
- package/dist/define-content-type-CDB3kyeA.d.ts +0 -1173
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkLSRPMNPT_cjs = require('./chunk-LSRPMNPT.cjs');
|
|
4
|
+
var chunkTZL374LS_cjs = require('./chunk-TZL374LS.cjs');
|
|
4
5
|
var chunkMWMSFIWN_cjs = require('./chunk-MWMSFIWN.cjs');
|
|
5
6
|
|
|
6
7
|
/* RelyIO SDK - Built with ❤️ by the RelyIO Team */
|
|
@@ -232,18 +233,6 @@ chunkMWMSFIWN_cjs.__name(_UnknownContractError, "UnknownContractError");
|
|
|
232
233
|
var UnknownContractError = _UnknownContractError;
|
|
233
234
|
|
|
234
235
|
// src/errors/auth-errors.ts
|
|
235
|
-
var _AuthenticationError = class _AuthenticationError extends SDKError {
|
|
236
|
-
constructor(message = "Authentication failed", statusCode = 401, cause, context) {
|
|
237
|
-
super(message, statusCode, cause, context);
|
|
238
|
-
chunkMWMSFIWN_cjs.__publicField(this, "code", "AUTHENTICATION_ERROR");
|
|
239
|
-
chunkMWMSFIWN_cjs.__publicField(this, "retryable", false);
|
|
240
|
-
}
|
|
241
|
-
getUserMessage() {
|
|
242
|
-
return "Authentication failed. Please check your API key and try again.";
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
chunkMWMSFIWN_cjs.__name(_AuthenticationError, "AuthenticationError");
|
|
246
|
-
var AuthenticationError = _AuthenticationError;
|
|
247
236
|
var _AuthorizationError = class _AuthorizationError extends SDKError {
|
|
248
237
|
constructor(message = "Authorization failed", statusCode = 403, cause, context) {
|
|
249
238
|
super(message, statusCode, cause, context);
|
|
@@ -422,58 +411,45 @@ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationErro
|
|
|
422
411
|
};
|
|
423
412
|
chunkMWMSFIWN_cjs.__name(_InvalidPayloadError, "InvalidPayloadError");
|
|
424
413
|
var InvalidPayloadError = _InvalidPayloadError;
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
414
|
+
|
|
415
|
+
// ../../platform/api-contract/dist/chunk-PYZCLRXR.js
|
|
416
|
+
function defineRoute(route) {
|
|
417
|
+
if (route.kind === "raw" && route.standardShape === void 0) {
|
|
418
|
+
throw new Error("kind 'raw' requires a named StandardShape");
|
|
429
419
|
}
|
|
430
|
-
|
|
431
|
-
|
|
420
|
+
if (route.kind === "raw" && route.success === 302 && !route.headers.some((header) => header.name === "Location")) {
|
|
421
|
+
throw new Error("a raw route declaring success 302 must declare its 'Location' header");
|
|
432
422
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
var SchemaValidationError = _SchemaValidationError;
|
|
436
|
-
var _RequiredFieldError = class _RequiredFieldError extends BaseValidationError {
|
|
437
|
-
constructor(fieldName, message, cause) {
|
|
438
|
-
const violation = {
|
|
439
|
-
field: fieldName,
|
|
440
|
-
message: message ?? `Field "${fieldName}" is required`,
|
|
441
|
-
code: "REQUIRED"
|
|
442
|
-
};
|
|
443
|
-
super(`Required field "${fieldName}" is missing`, [violation], 400, cause);
|
|
444
|
-
chunkMWMSFIWN_cjs.__publicField(this, "code", "REQUIRED_FIELD_ERROR");
|
|
423
|
+
if (route.kind === "stream" && route.stream === void 0) {
|
|
424
|
+
throw new Error("kind 'stream' requires a StreamDeclaration");
|
|
445
425
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const fieldName = violation?.field;
|
|
449
|
-
return `The field "${fieldName}" is required and cannot be empty.`;
|
|
426
|
+
if (route.kind === "collection" && route.page === void 0) {
|
|
427
|
+
throw new Error("kind 'collection' requires a page dialect");
|
|
450
428
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
`
|
|
464
|
-
[violation],
|
|
465
|
-
400,
|
|
466
|
-
cause
|
|
429
|
+
if ((route.kind === "object" || route.kind === "collection") && route.negotiated !== void 0) {
|
|
430
|
+
refuseMismatchedAlternate(route, route.negotiated["text/event-stream"]);
|
|
431
|
+
}
|
|
432
|
+
return route;
|
|
433
|
+
}
|
|
434
|
+
chunkMWMSFIWN_cjs.__name(defineRoute, "defineRoute");
|
|
435
|
+
function refuseMismatchedAlternate(route, stream) {
|
|
436
|
+
if (stream.kind !== "stream") {
|
|
437
|
+
throw new Error("a negotiated 'text/event-stream' alternate must be kind 'stream'");
|
|
438
|
+
}
|
|
439
|
+
if (stream.stream.mediaType !== "text/event-stream") {
|
|
440
|
+
throw new Error(
|
|
441
|
+
`a negotiated 'text/event-stream' alternate declares media type "${stream.stream.mediaType}"`
|
|
467
442
|
);
|
|
468
|
-
chunkMWMSFIWN_cjs.__publicField(this, "code", "INVALID_FIELD_TYPE");
|
|
469
443
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
444
|
+
const own = [...new Set(route.codes)].sort();
|
|
445
|
+
const alternate = [...new Set(stream.codes)].sort();
|
|
446
|
+
if (own.length !== alternate.length || own.some((code, index) => code !== alternate[index])) {
|
|
447
|
+
throw new Error(
|
|
448
|
+
`a negotiated alternate refuses with [${alternate.join(", ")}] while its route refuses with [${own.join(", ")}]; one route refuses with one set of codes on every transport`
|
|
449
|
+
);
|
|
473
450
|
}
|
|
474
|
-
}
|
|
475
|
-
chunkMWMSFIWN_cjs.__name(
|
|
476
|
-
var InvalidFieldTypeError = _InvalidFieldTypeError;
|
|
451
|
+
}
|
|
452
|
+
chunkMWMSFIWN_cjs.__name(refuseMismatchedAlternate, "refuseMismatchedAlternate");
|
|
477
453
|
|
|
478
454
|
// ../../platform/api-contract/dist/index.js
|
|
479
455
|
var HEADER_RETRY_AFTER = { name: "Retry-After" };
|
|
@@ -482,6 +458,169 @@ var HEADER_IF_MATCH = {
|
|
|
482
458
|
name: "If-Match"};
|
|
483
459
|
var HEADER_IDEMPOTENCY_KEY = {
|
|
484
460
|
name: "Idempotency-Key"};
|
|
461
|
+
var FRESH_PARAMETER = "_fresh";
|
|
462
|
+
var VISITOR_LIVE_PATH = "/visitor/changes";
|
|
463
|
+
var VISITOR_QUERY = {
|
|
464
|
+
/** The publishable key. */
|
|
465
|
+
key: "key",
|
|
466
|
+
/** A dataset id or name the key reaches; absent, the key's default dataset. */
|
|
467
|
+
dataset: "dataset",
|
|
468
|
+
/** The cursor to continue from; absent, the socket starts now. */
|
|
469
|
+
since: "since",
|
|
470
|
+
/** Comma-separated content types to keep; absent keeps every type. */
|
|
471
|
+
types: "types",
|
|
472
|
+
/** Comma-separated entry ids to keep; absent keeps every entry. */
|
|
473
|
+
ids: "ids",
|
|
474
|
+
/** The poll's client id. Required on a poll, and not read on a socket. */
|
|
475
|
+
client: "client"
|
|
476
|
+
};
|
|
477
|
+
var VISITOR_CURSOR = /^[\w.~-]{1,256}$/;
|
|
478
|
+
var VISITOR_POLL_INTERVAL_MS = 15e3;
|
|
479
|
+
var VISITOR_KEEPALIVE = { request: "ping", response: "pong" };
|
|
480
|
+
var VISITOR_FRAMES = {
|
|
481
|
+
opened: "feed.opened",
|
|
482
|
+
changes: "feed.changes",
|
|
483
|
+
resync: "feed.resync"
|
|
484
|
+
};
|
|
485
|
+
defineRoute({
|
|
486
|
+
kind: "object",
|
|
487
|
+
headers: [HEADER_RETRY_AFTER],
|
|
488
|
+
codes: [
|
|
489
|
+
"REQUEST_INVALID",
|
|
490
|
+
"MISSING_API_KEY",
|
|
491
|
+
"INVALID_API_KEY",
|
|
492
|
+
"ACCESS_DENIED",
|
|
493
|
+
"METHOD_NOT_ALLOWED",
|
|
494
|
+
"SERVICE_INDETERMINATE",
|
|
495
|
+
"USAGE_QUOTA_EXCEEDED",
|
|
496
|
+
"RATE_LIMIT_EXCEEDED"
|
|
497
|
+
]
|
|
498
|
+
});
|
|
499
|
+
var VISITOR_CLOSE_CODES = {
|
|
500
|
+
/** A query the door cannot read: a malformed `since`, filter, `dataset` or `client`. */
|
|
501
|
+
requestInvalid: 4400,
|
|
502
|
+
/** No publishable key, or one that is unknown, revoked, expired, a secret key or a preview key. */
|
|
503
|
+
keyRefused: 4401,
|
|
504
|
+
/** The page's `Origin` is absent, or not on the key's allowed origins. */
|
|
505
|
+
originRefused: 4403,
|
|
506
|
+
/** `dataset` names nothing the key reaches. */
|
|
507
|
+
datasetRefused: 4404,
|
|
508
|
+
/** The key's scope, the project's counter or the feed could not be reached just now. */
|
|
509
|
+
unavailable: 1013,
|
|
510
|
+
/**
|
|
511
|
+
* The project holds as many visitor connections as its plan allows — Starter's 100 — or its
|
|
512
|
+
* Organization is suspended. As HTTP's 402: more needs a bigger plan, or visitors leaving.
|
|
513
|
+
*/
|
|
514
|
+
allowanceReached: 4402,
|
|
515
|
+
/** This client's address holds as many connections to the project as one address may. */
|
|
516
|
+
addressLimitReached: 4429,
|
|
517
|
+
/** The project is at its per-project safety ceiling — Pro's 50,000 — whatever it would pay for. */
|
|
518
|
+
ceilingReached: 4503
|
|
519
|
+
};
|
|
520
|
+
var VISITOR_CLOSE_RETRY = {
|
|
521
|
+
4400: "stop",
|
|
522
|
+
4401: "stop",
|
|
523
|
+
4403: "stop",
|
|
524
|
+
4404: "stop",
|
|
525
|
+
1013: "retry",
|
|
526
|
+
4402: "back-off",
|
|
527
|
+
4429: "back-off",
|
|
528
|
+
4503: "back-off"
|
|
529
|
+
};
|
|
530
|
+
var VISITOR_POLL_RETRY = {
|
|
531
|
+
REQUEST_INVALID: "stop",
|
|
532
|
+
MISSING_API_KEY: "stop",
|
|
533
|
+
INVALID_API_KEY: "stop",
|
|
534
|
+
ACCESS_DENIED: "stop",
|
|
535
|
+
METHOD_NOT_ALLOWED: "stop",
|
|
536
|
+
SERVICE_INDETERMINATE: "retry",
|
|
537
|
+
USAGE_QUOTA_EXCEEDED: "back-off",
|
|
538
|
+
RATE_LIMIT_EXCEEDED: "back-off"
|
|
539
|
+
};
|
|
540
|
+
var VISITOR_ADMISSION_RETRY_AFTER_SECONDS = 60;
|
|
541
|
+
function parseVisitorFrame(text) {
|
|
542
|
+
let value;
|
|
543
|
+
try {
|
|
544
|
+
value = JSON.parse(text);
|
|
545
|
+
} catch {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
if (!isRecord2(value) || !isCursor(value.cursor)) return null;
|
|
549
|
+
switch (value.type) {
|
|
550
|
+
case VISITOR_FRAMES.opened: {
|
|
551
|
+
return hasOnly(value, ["type", "cursor"]) ? { type: VISITOR_FRAMES.opened, cursor: value.cursor } : null;
|
|
552
|
+
}
|
|
553
|
+
case VISITOR_FRAMES.changes: {
|
|
554
|
+
const changes = hasOnly(value, ["type", "changes", "cursor"]) ? readVisitorChanges(value.changes) : null;
|
|
555
|
+
return changes === null ? null : { type: VISITOR_FRAMES.changes, changes, cursor: value.cursor };
|
|
556
|
+
}
|
|
557
|
+
case VISITOR_FRAMES.resync: {
|
|
558
|
+
return hasOnly(value, ["type", "reason", "cursor"]) && isResyncReason(value.reason) ? { type: VISITOR_FRAMES.resync, reason: value.reason, cursor: value.cursor } : null;
|
|
559
|
+
}
|
|
560
|
+
default: {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
chunkMWMSFIWN_cjs.__name(parseVisitorFrame, "parseVisitorFrame");
|
|
566
|
+
function readVisitorPollAnswer(value) {
|
|
567
|
+
if (!isRecord2(value) || !isCursor(value.cursor)) return null;
|
|
568
|
+
if (value.kind === "resync") {
|
|
569
|
+
return hasOnly(value, ["kind", "reason", "cursor"]) && isResyncReason(value.reason) ? { kind: "resync", reason: value.reason, cursor: value.cursor } : null;
|
|
570
|
+
}
|
|
571
|
+
if (value.kind !== "changes" || !hasOnly(value, ["kind", "changes", "cursor"])) return null;
|
|
572
|
+
const changes = readVisitorChanges(value.changes);
|
|
573
|
+
return changes === null ? null : { kind: "changes", changes, cursor: value.cursor };
|
|
574
|
+
}
|
|
575
|
+
chunkMWMSFIWN_cjs.__name(readVisitorPollAnswer, "readVisitorPollAnswer");
|
|
576
|
+
var CHANGE_KINDS = /* @__PURE__ */ new Set([
|
|
577
|
+
"published",
|
|
578
|
+
"updated",
|
|
579
|
+
"unpublished",
|
|
580
|
+
"deleted"
|
|
581
|
+
]);
|
|
582
|
+
var RESYNC_REASONS = /* @__PURE__ */ new Set([
|
|
583
|
+
"retention",
|
|
584
|
+
"dataset-replaced",
|
|
585
|
+
"ahead-of-head",
|
|
586
|
+
"foreign-cursor",
|
|
587
|
+
"too-far-behind"
|
|
588
|
+
]);
|
|
589
|
+
function isResyncReason(value) {
|
|
590
|
+
return typeof value === "string" && RESYNC_REASONS.has(value);
|
|
591
|
+
}
|
|
592
|
+
chunkMWMSFIWN_cjs.__name(isResyncReason, "isResyncReason");
|
|
593
|
+
function readVisitorChanges(value) {
|
|
594
|
+
if (!Array.isArray(value)) return null;
|
|
595
|
+
const changes = [];
|
|
596
|
+
for (const item of value) {
|
|
597
|
+
if (!isRecord2(item) || !hasOnly(item, ["entryId", "contentType", "locale", "kind"])) return null;
|
|
598
|
+
const { entryId, contentType, locale, kind } = item;
|
|
599
|
+
if (!isNonEmptyString2(entryId) || !isNonEmptyString2(contentType)) return null;
|
|
600
|
+
if (locale !== null && typeof locale !== "string") return null;
|
|
601
|
+
if (typeof kind !== "string" || !CHANGE_KINDS.has(kind)) return null;
|
|
602
|
+
changes.push({ entryId, contentType, locale, kind });
|
|
603
|
+
}
|
|
604
|
+
return changes;
|
|
605
|
+
}
|
|
606
|
+
chunkMWMSFIWN_cjs.__name(readVisitorChanges, "readVisitorChanges");
|
|
607
|
+
function isCursor(value) {
|
|
608
|
+
return typeof value === "string" && VISITOR_CURSOR.test(value);
|
|
609
|
+
}
|
|
610
|
+
chunkMWMSFIWN_cjs.__name(isCursor, "isCursor");
|
|
611
|
+
function isRecord2(value) {
|
|
612
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
613
|
+
}
|
|
614
|
+
chunkMWMSFIWN_cjs.__name(isRecord2, "isRecord2");
|
|
615
|
+
function isNonEmptyString2(value) {
|
|
616
|
+
return typeof value === "string" && value.length > 0;
|
|
617
|
+
}
|
|
618
|
+
chunkMWMSFIWN_cjs.__name(isNonEmptyString2, "isNonEmptyString2");
|
|
619
|
+
function hasOnly(value, keys) {
|
|
620
|
+
const present = Object.keys(value);
|
|
621
|
+
return present.length === keys.length && present.every((key) => keys.includes(key));
|
|
622
|
+
}
|
|
623
|
+
chunkMWMSFIWN_cjs.__name(hasOnly, "hasOnly");
|
|
485
624
|
|
|
486
625
|
// ../../platform/api-contract/dist/client/index.js
|
|
487
626
|
var _a;
|
|
@@ -750,6 +889,8 @@ var DECLARED_PATHS = {
|
|
|
750
889
|
"/health/cache": true,
|
|
751
890
|
"/health/live": true,
|
|
752
891
|
"/health/ready": true,
|
|
892
|
+
"/internal/live/visitor-feed/{projectId}/{datasetId}/changes": true,
|
|
893
|
+
"/internal/live/visitor-key": true,
|
|
753
894
|
"/internal/media/claim": true,
|
|
754
895
|
"/internal/media/file-complete": true,
|
|
755
896
|
"/internal/media/progress": true,
|
|
@@ -873,6 +1014,20 @@ function isAborted(signal) {
|
|
|
873
1014
|
}
|
|
874
1015
|
chunkMWMSFIWN_cjs.__name(isAborted, "isAborted");
|
|
875
1016
|
|
|
1017
|
+
// src/http/request-timeout.ts
|
|
1018
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1019
|
+
function isTimerDelay(value) {
|
|
1020
|
+
return typeof value === "number" && value >= 1 && value <= MAX_TIMER_DELAY_MS;
|
|
1021
|
+
}
|
|
1022
|
+
chunkMWMSFIWN_cjs.__name(isTimerDelay, "isTimerDelay");
|
|
1023
|
+
function assertRequestTimeout(timeout) {
|
|
1024
|
+
if (isTimerDelay(timeout)) return;
|
|
1025
|
+
throw new Error(
|
|
1026
|
+
`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)}`
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
chunkMWMSFIWN_cjs.__name(assertRequestTimeout, "assertRequestTimeout");
|
|
1030
|
+
|
|
876
1031
|
// src/errors/instructed-delay.ts
|
|
877
1032
|
function serviceInstructedDelayMs(error, nowMs) {
|
|
878
1033
|
if (error instanceof ServiceIndeterminateError) {
|
|
@@ -926,43 +1081,31 @@ var DefaultRetryPolicy = _DefaultRetryPolicy;
|
|
|
926
1081
|
// src/http/http-client.ts
|
|
927
1082
|
var _HttpClient = class _HttpClient {
|
|
928
1083
|
constructor(config) {
|
|
929
|
-
|
|
930
|
-
chunkMWMSFIWN_cjs.__publicField(this, "
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
if (typeof window === "undefined") {
|
|
951
|
-
const globalWithVersion = globalThis;
|
|
952
|
-
this.defaultHeaders["User-Agent"] = `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`;
|
|
953
|
-
}
|
|
954
|
-
this.retryPolicy = new DefaultRetryPolicy({
|
|
955
|
-
maxAttempts: config.retryAttempts,
|
|
956
|
-
baseDelay: 1e3,
|
|
957
|
-
maxDelay: 1e4,
|
|
958
|
-
backoffFactor: 2,
|
|
959
|
-
jitter: true
|
|
960
|
-
});
|
|
1084
|
+
/** What every request reads off the configuration, derived by {@link configure} and nowhere else. */
|
|
1085
|
+
chunkMWMSFIWN_cjs.__publicField(this, "connection");
|
|
1086
|
+
this.connection = connectionFor(config);
|
|
1087
|
+
this.announce();
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Run on `config` from now on: every later request — whoever holds this client — is sent to its
|
|
1091
|
+
* `baseUrl`, with its headers, key and dataset, its timeout and retries, through its `fetch`, and
|
|
1092
|
+
* logged by its `debug` options.
|
|
1093
|
+
*
|
|
1094
|
+
* The client's own `updateConfig()` calls this rather than building a second client, so a
|
|
1095
|
+
* `content()` or other sub-client taken before the update sends through the update too. Anything
|
|
1096
|
+
* set on this client since it was last configured — `setDefaultHeaders()`, `setBaseUrl()` — is
|
|
1097
|
+
* replaced by what `config` says.
|
|
1098
|
+
*/
|
|
1099
|
+
configure(config) {
|
|
1100
|
+
this.connection = connectionFor(config);
|
|
1101
|
+
this.announce();
|
|
1102
|
+
}
|
|
1103
|
+
announce() {
|
|
961
1104
|
this.log("debug", "HttpClient initialized", {
|
|
962
|
-
baseUrl: this.baseUrl,
|
|
963
|
-
timeout: this.timeout,
|
|
964
|
-
retryAttempts: config.retryAttempts,
|
|
965
|
-
environment:
|
|
1105
|
+
baseUrl: this.connection.baseUrl,
|
|
1106
|
+
timeout: this.connection.timeout,
|
|
1107
|
+
retryAttempts: this.connection.config.retryAttempts,
|
|
1108
|
+
environment: chunkTZL374LS_cjs.isBrowser() ? "browser" : "node"
|
|
966
1109
|
});
|
|
967
1110
|
}
|
|
968
1111
|
/**
|
|
@@ -999,19 +1142,24 @@ var _HttpClient = class _HttpClient {
|
|
|
999
1142
|
*
|
|
1000
1143
|
* The loop always makes one attempt. The incumbent's `while (attempt <
|
|
1001
1144
|
* maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
|
|
1002
|
-
*
|
|
1145
|
+
* then accepted, and now refuses — and then dereferenced an unassigned
|
|
1146
|
+
* `lastError`. `retryAttempts` is the most attempts, the first included; an
|
|
1147
|
+
* `HttpClient` constructed directly is not validated, so the first attempt
|
|
1148
|
+
* stays unconditional.
|
|
1003
1149
|
*
|
|
1004
1150
|
* A request that would carry no `X-API-Key` makes none: it rejects with
|
|
1005
1151
|
* `MissingApiKeyError` before `fetch` is called, is not retried, and names
|
|
1006
1152
|
* `apiKey`. This is where a client built without a key learns it — the
|
|
1007
1153
|
* constructor accepts one so that a module-scope client can be evaluated by a
|
|
1008
|
-
* build that holds no key (REL-1120)
|
|
1154
|
+
* build that holds no key (REL-1120) — and so does one whose `setApiKey` was
|
|
1155
|
+
* given none.
|
|
1009
1156
|
*/
|
|
1010
1157
|
async request(config) {
|
|
1158
|
+
if (config.timeout !== void 0) assertRequestTimeout(config.timeout);
|
|
1011
1159
|
const mergedConfig = this.mergeRequestConfig(config);
|
|
1012
1160
|
if (presentKey(headerValue(mergedConfig.headers, API_KEY_HEADER)) === void 0) {
|
|
1013
1161
|
throw new MissingApiKeyError(
|
|
1014
|
-
"`apiKey` is missing: this client
|
|
1162
|
+
"`apiKey` is missing: this client holds no API key, so the request was not sent. Pass `apiKey` to createClient \u2014 the documented setup reads it from RELYIO_API_KEY.",
|
|
1015
1163
|
{ url: mergedConfig.url, method: mergedConfig.method, sent: false }
|
|
1016
1164
|
);
|
|
1017
1165
|
}
|
|
@@ -1021,7 +1169,7 @@ var _HttpClient = class _HttpClient {
|
|
|
1021
1169
|
// Show the final URL with query params
|
|
1022
1170
|
});
|
|
1023
1171
|
if (config.method === "DELETE" && mergedConfig.headers) {
|
|
1024
|
-
|
|
1172
|
+
mergedConfig.headers = layerHeaders(mergedConfig.headers, { "Content-Type": null });
|
|
1025
1173
|
}
|
|
1026
1174
|
for (let attempt = 1; ; attempt++) {
|
|
1027
1175
|
try {
|
|
@@ -1040,8 +1188,8 @@ var _HttpClient = class _HttpClient {
|
|
|
1040
1188
|
attempt,
|
|
1041
1189
|
url: mergedConfig.url
|
|
1042
1190
|
});
|
|
1043
|
-
if (this.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
|
|
1044
|
-
const delay = this.retryPolicy.delayFor(attempt, failure);
|
|
1191
|
+
if (this.connection.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
|
|
1192
|
+
const delay = this.connection.retryPolicy.delayFor(attempt, failure);
|
|
1045
1193
|
this.log("debug", "Retrying request", { attempt, delay });
|
|
1046
1194
|
await sleep(delay, config.signal);
|
|
1047
1195
|
continue;
|
|
@@ -1113,34 +1261,60 @@ var _HttpClient = class _HttpClient {
|
|
|
1113
1261
|
});
|
|
1114
1262
|
}
|
|
1115
1263
|
/**
|
|
1116
|
-
*
|
|
1264
|
+
* Add headers to every later request, each replacing any header of the same name — the name
|
|
1265
|
+
* matched without regard to case — until the client is next configured.
|
|
1117
1266
|
*/
|
|
1118
1267
|
setDefaultHeaders(headers) {
|
|
1119
|
-
this.
|
|
1268
|
+
this.connection = {
|
|
1269
|
+
...this.connection,
|
|
1270
|
+
defaultHeaders: layerHeaders(this.connection.defaultHeaders, headers)
|
|
1271
|
+
};
|
|
1120
1272
|
}
|
|
1121
1273
|
/**
|
|
1122
|
-
*
|
|
1274
|
+
* Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
|
|
1275
|
+
* reports.
|
|
1276
|
+
*
|
|
1277
|
+
* The key is read the way construction reads it (`presentKey`): an absent, empty or blank key is
|
|
1278
|
+
* no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
|
|
1279
|
+
* before anything is sent. A key header of any other spelling — one given in `headers` — goes
|
|
1280
|
+
* too, from the headers sent and from the headers the configuration reports, so the old key is
|
|
1281
|
+
* never sent beside the new one.
|
|
1282
|
+
*
|
|
1283
|
+
* The configuration is the one the owning `TypedRelyIOClient` holds (it hands its own to the
|
|
1284
|
+
* constructor), so its `getConfig().apiKey` — what a surface reads to decide a key's kind — is the
|
|
1285
|
+
* key sent from here on.
|
|
1286
|
+
*
|
|
1287
|
+
* This replaced `setAuthToken`, which added `Authorization: Bearer` beside an `X-API-Key` it
|
|
1288
|
+
* never touched: the API reads `X-API-Key` first, so the old key was the one used (REL-1385).
|
|
1123
1289
|
*/
|
|
1124
|
-
|
|
1125
|
-
|
|
1290
|
+
setApiKey(apiKey) {
|
|
1291
|
+
const { config } = this.connection;
|
|
1292
|
+
config.apiKey = apiKey;
|
|
1293
|
+
config.headers = layerHeaders(config.headers, { [API_KEY_HEADER]: null });
|
|
1294
|
+
this.connection = {
|
|
1295
|
+
...this.connection,
|
|
1296
|
+
defaultHeaders: layerHeaders(this.connection.defaultHeaders, {
|
|
1297
|
+
[API_KEY_HEADER]: presentKey(apiKey) ?? null
|
|
1298
|
+
})
|
|
1299
|
+
};
|
|
1126
1300
|
}
|
|
1127
1301
|
/**
|
|
1128
1302
|
* Get current default headers
|
|
1129
1303
|
*/
|
|
1130
1304
|
getDefaultHeaders() {
|
|
1131
|
-
return { ...this.defaultHeaders };
|
|
1305
|
+
return { ...this.connection.defaultHeaders };
|
|
1132
1306
|
}
|
|
1133
1307
|
/**
|
|
1134
1308
|
* Update base URL
|
|
1135
1309
|
*/
|
|
1136
1310
|
setBaseUrl(baseUrl) {
|
|
1137
|
-
this.
|
|
1311
|
+
this.connection = { ...this.connection, baseUrl };
|
|
1138
1312
|
}
|
|
1139
1313
|
/**
|
|
1140
1314
|
* Get current base URL
|
|
1141
1315
|
*/
|
|
1142
1316
|
getBaseUrl() {
|
|
1143
|
-
return this.baseUrl;
|
|
1317
|
+
return this.connection.baseUrl;
|
|
1144
1318
|
}
|
|
1145
1319
|
/**
|
|
1146
1320
|
* One attempt.
|
|
@@ -1162,7 +1336,7 @@ var _HttpClient = class _HttpClient {
|
|
|
1162
1336
|
const timeoutId = setTimeout(() => {
|
|
1163
1337
|
timedOut = true;
|
|
1164
1338
|
controller.abort();
|
|
1165
|
-
}, config.timeout ?? this.timeout);
|
|
1339
|
+
}, config.timeout ?? this.connection.timeout);
|
|
1166
1340
|
const onCallerAbort = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => controller.abort(), "onCallerAbort");
|
|
1167
1341
|
caller?.addEventListener("abort", onCallerAbort, { once: true });
|
|
1168
1342
|
try {
|
|
@@ -1172,14 +1346,15 @@ var _HttpClient = class _HttpClient {
|
|
|
1172
1346
|
headers: filteredHeaders,
|
|
1173
1347
|
body: this.prepareRequestBody(config),
|
|
1174
1348
|
signal: controller.signal,
|
|
1175
|
-
// Only
|
|
1176
|
-
// govern, so the field is left off and the
|
|
1177
|
-
//
|
|
1178
|
-
|
|
1179
|
-
|
|
1349
|
+
// Only in a browser — a `window` with a `document` (`isBrowser()`). A server or edge
|
|
1350
|
+
// runtime has no cookie jar for the mode to govern, so the field is left off and the
|
|
1351
|
+
// runtime's default stands; that includes Deno 1.x, whose global is a `window` with no
|
|
1352
|
+
// `document`. A Web Worker gets that default too: it has cookies but no `window`.
|
|
1353
|
+
...chunkTZL374LS_cjs.isBrowser() && {
|
|
1354
|
+
credentials: credentialsModeFor(this.connection.config.browser.includeCredentials)
|
|
1180
1355
|
}
|
|
1181
1356
|
};
|
|
1182
|
-
const send = this.config.fetch ?? globalThis.fetch;
|
|
1357
|
+
const send = this.connection.config.fetch ?? globalThis.fetch;
|
|
1183
1358
|
const response = await send(url, requestInit);
|
|
1184
1359
|
clearTimeout(timeoutId);
|
|
1185
1360
|
const responseBody = await this.parseResponse(response);
|
|
@@ -1212,10 +1387,8 @@ var _HttpClient = class _HttpClient {
|
|
|
1212
1387
|
}
|
|
1213
1388
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
1214
1389
|
if (!timedOut && isAborted(caller)) throw error;
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
config.timeout ?? this.timeout
|
|
1218
|
-
);
|
|
1390
|
+
const timeout = config.timeout ?? this.connection.timeout;
|
|
1391
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`, timeout);
|
|
1219
1392
|
}
|
|
1220
1393
|
if (error instanceof TypeError && error.message.includes("CORS")) {
|
|
1221
1394
|
const corsError = new NetworkError(
|
|
@@ -1229,9 +1402,10 @@ var _HttpClient = class _HttpClient {
|
|
|
1229
1402
|
suggestion: "Check if the API server allows requests from your domain and has proper CORS headers configured."
|
|
1230
1403
|
}
|
|
1231
1404
|
);
|
|
1232
|
-
|
|
1405
|
+
const { onCorsError } = this.connection.config.browser;
|
|
1406
|
+
if (chunkTZL374LS_cjs.isBrowser() && onCorsError) {
|
|
1233
1407
|
try {
|
|
1234
|
-
|
|
1408
|
+
onCorsError(corsError, {
|
|
1235
1409
|
url: config.url,
|
|
1236
1410
|
method: config.method,
|
|
1237
1411
|
originalError: error
|
|
@@ -1248,20 +1422,20 @@ var _HttpClient = class _HttpClient {
|
|
|
1248
1422
|
}
|
|
1249
1423
|
}
|
|
1250
1424
|
/**
|
|
1251
|
-
*
|
|
1425
|
+
* The headers without those a browser controls itself, when this is a browser; unchanged when it
|
|
1426
|
+
* is not.
|
|
1427
|
+
*
|
|
1428
|
+
* A name is matched without regard to case (RFC 9110 §5.1), because a browser refuses `Origin`
|
|
1429
|
+
* whatever case a page spells it in. This matched only the all-lowercase and all-uppercase
|
|
1430
|
+
* spellings, so `Origin` and `User-Agent` — how people write them — reached `fetch` (REL-1409).
|
|
1252
1431
|
*/
|
|
1253
1432
|
filterHeadersForBrowser(headers) {
|
|
1254
|
-
if (
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
delete filteredHeaders[header.toUpperCase()];
|
|
1261
|
-
});
|
|
1262
|
-
return filteredHeaders;
|
|
1263
|
-
}
|
|
1264
|
-
return headers;
|
|
1433
|
+
if (!chunkTZL374LS_cjs.isBrowser()) return headers;
|
|
1434
|
+
return Object.fromEntries(
|
|
1435
|
+
Object.entries(headers).filter(
|
|
1436
|
+
([name]) => !BROWSER_CONTROLLED_HEADERS.has(name.toLowerCase())
|
|
1437
|
+
)
|
|
1438
|
+
);
|
|
1265
1439
|
}
|
|
1266
1440
|
/**
|
|
1267
1441
|
* Prepare request body based on content type and environment
|
|
@@ -1297,7 +1471,7 @@ var _HttpClient = class _HttpClient {
|
|
|
1297
1471
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1298
1472
|
return url;
|
|
1299
1473
|
}
|
|
1300
|
-
return `${this.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
1474
|
+
return `${this.connection.baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
1301
1475
|
}
|
|
1302
1476
|
mergeRequestConfig(config) {
|
|
1303
1477
|
const url = this.resolveUrl(config.url);
|
|
@@ -1306,11 +1480,11 @@ var _HttpClient = class _HttpClient {
|
|
|
1306
1480
|
return {
|
|
1307
1481
|
...config,
|
|
1308
1482
|
url: finalUrl,
|
|
1309
|
-
headers:
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
timeout: config.timeout ?? this.timeout
|
|
1483
|
+
// The request's own headers replace the client's of the same name, whatever the case: a
|
|
1484
|
+
// per-request `x-relyio-dataset` sent beside the client's `X-RelyIO-Dataset` is one header
|
|
1485
|
+
// `Headers` joins into `main, staging`.
|
|
1486
|
+
headers: layerHeaders(this.connection.defaultHeaders, config.headers),
|
|
1487
|
+
timeout: config.timeout ?? this.connection.timeout
|
|
1314
1488
|
};
|
|
1315
1489
|
}
|
|
1316
1490
|
buildQueryString(params) {
|
|
@@ -1334,9 +1508,10 @@ var _HttpClient = class _HttpClient {
|
|
|
1334
1508
|
return obj;
|
|
1335
1509
|
}
|
|
1336
1510
|
log(level, message, data) {
|
|
1337
|
-
|
|
1338
|
-
if (
|
|
1339
|
-
|
|
1511
|
+
const { debug } = this.connection.config;
|
|
1512
|
+
if (!debug.enabled) return;
|
|
1513
|
+
if (debug.logger != null) {
|
|
1514
|
+
debug.logger(level, message, data);
|
|
1340
1515
|
} else {
|
|
1341
1516
|
console.log(`[RelyIO SDK ${level.toUpperCase()}] ${message}`, data ?? "");
|
|
1342
1517
|
}
|
|
@@ -1345,29 +1520,104 @@ var _HttpClient = class _HttpClient {
|
|
|
1345
1520
|
chunkMWMSFIWN_cjs.__name(_HttpClient, "HttpClient");
|
|
1346
1521
|
var HttpClient = _HttpClient;
|
|
1347
1522
|
var API_KEY_HEADER = "X-API-Key";
|
|
1523
|
+
var DATASET_HEADER = "X-RelyIO-Dataset";
|
|
1524
|
+
var BROWSER_CONTROLLED_HEADERS = /* @__PURE__ */ new Set([
|
|
1525
|
+
"user-agent",
|
|
1526
|
+
"referer",
|
|
1527
|
+
"origin",
|
|
1528
|
+
"host",
|
|
1529
|
+
"connection",
|
|
1530
|
+
"upgrade"
|
|
1531
|
+
]);
|
|
1532
|
+
function connectionFor(config) {
|
|
1533
|
+
const globalWithVersion = globalThis;
|
|
1534
|
+
const defaultHeaders = layerHeaders(
|
|
1535
|
+
layerHeaders({ "Content-Type": "application/json" }, config.headers),
|
|
1536
|
+
{
|
|
1537
|
+
[API_KEY_HEADER]: presentKey(config.apiKey),
|
|
1538
|
+
[DATASET_HEADER]: config.dataset,
|
|
1539
|
+
// Only outside a browser, which controls this header. "A browser" is the core's one
|
|
1540
|
+
// definition, `isBrowser()` — every environment question in this file asks it.
|
|
1541
|
+
"User-Agent": chunkTZL374LS_cjs.isBrowser() ? void 0 : `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`
|
|
1542
|
+
}
|
|
1543
|
+
);
|
|
1544
|
+
return {
|
|
1545
|
+
config,
|
|
1546
|
+
baseUrl: config.baseUrl,
|
|
1547
|
+
defaultHeaders,
|
|
1548
|
+
timeout: config.timeout,
|
|
1549
|
+
// The policy, not a predicate over `(error, attempt)`: whether a request may be sent again is a
|
|
1550
|
+
// property of the **route** as much as of the refusal, and a callback that never sees the
|
|
1551
|
+
// request cannot express that.
|
|
1552
|
+
retryPolicy: new DefaultRetryPolicy({
|
|
1553
|
+
maxAttempts: config.retryAttempts,
|
|
1554
|
+
baseDelay: 1e3,
|
|
1555
|
+
maxDelay: 1e4,
|
|
1556
|
+
backoffFactor: 2,
|
|
1557
|
+
jitter: true
|
|
1558
|
+
})
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
chunkMWMSFIWN_cjs.__name(connectionFor, "connectionFor");
|
|
1562
|
+
function layerHeaders(base, over) {
|
|
1563
|
+
const layered = { ...base };
|
|
1564
|
+
for (const [name, value] of Object.entries(over ?? {})) {
|
|
1565
|
+
if (value === void 0) continue;
|
|
1566
|
+
const lower = name.toLowerCase();
|
|
1567
|
+
for (const existing of Object.keys(layered)) {
|
|
1568
|
+
if (existing.toLowerCase() === lower) delete layered[existing];
|
|
1569
|
+
}
|
|
1570
|
+
if (value !== null) layered[name] = value;
|
|
1571
|
+
}
|
|
1572
|
+
return layered;
|
|
1573
|
+
}
|
|
1574
|
+
chunkMWMSFIWN_cjs.__name(layerHeaders, "layerHeaders");
|
|
1348
1575
|
function presentKey(value) {
|
|
1349
1576
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
1350
1577
|
}
|
|
1351
1578
|
chunkMWMSFIWN_cjs.__name(presentKey, "presentKey");
|
|
1352
1579
|
function credentialsModeFor(includeCredentials) {
|
|
1353
|
-
|
|
1354
|
-
case false: {
|
|
1355
|
-
return "same-origin";
|
|
1356
|
-
}
|
|
1357
|
-
case true:
|
|
1358
|
-
case void 0: {
|
|
1359
|
-
return "include";
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1580
|
+
return includeCredentials ? "include" : "same-origin";
|
|
1362
1581
|
}
|
|
1363
1582
|
chunkMWMSFIWN_cjs.__name(credentialsModeFor, "credentialsModeFor");
|
|
1364
1583
|
|
|
1584
|
+
// src/content/client-locale.ts
|
|
1585
|
+
function callLocale(named, clientLocale) {
|
|
1586
|
+
if (named !== void 0) return named;
|
|
1587
|
+
return clientLocale === void 0 || clientLocale === "" ? void 0 : clientLocale;
|
|
1588
|
+
}
|
|
1589
|
+
chunkMWMSFIWN_cjs.__name(callLocale, "callLocale");
|
|
1590
|
+
function readClientLocale(locale) {
|
|
1591
|
+
return typeof locale === "function" ? locale : () => locale;
|
|
1592
|
+
}
|
|
1593
|
+
chunkMWMSFIWN_cjs.__name(readClientLocale, "readClientLocale");
|
|
1594
|
+
|
|
1365
1595
|
// src/content/query-builder.ts
|
|
1596
|
+
function namesMetadata(key) {
|
|
1597
|
+
return key === "_metadata" || key.startsWith("_metadata.");
|
|
1598
|
+
}
|
|
1599
|
+
chunkMWMSFIWN_cjs.__name(namesMetadata, "namesMetadata");
|
|
1600
|
+
function refuseMetadataConditions(conditions) {
|
|
1601
|
+
const named = Object.keys(conditions).filter(namesMetadata);
|
|
1602
|
+
if (named.length === 0) return;
|
|
1603
|
+
throw new ValidationError(
|
|
1604
|
+
`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.`,
|
|
1605
|
+
named.map((field) => ({
|
|
1606
|
+
field,
|
|
1607
|
+
code: "METADATA_CONDITION",
|
|
1608
|
+
message: `${field} is not a field the API can filter on`
|
|
1609
|
+
}))
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
chunkMWMSFIWN_cjs.__name(refuseMetadataConditions, "refuseMetadataConditions");
|
|
1366
1613
|
var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
1367
|
-
|
|
1614
|
+
/**
|
|
1615
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
|
|
1616
|
+
* query names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
|
|
1617
|
+
*/
|
|
1618
|
+
constructor(httpClient, contentType, locale) {
|
|
1368
1619
|
this.httpClient = httpClient;
|
|
1369
1620
|
this.contentType = contentType;
|
|
1370
|
-
this.defaultLocale = defaultLocale;
|
|
1371
1621
|
chunkMWMSFIWN_cjs.__publicField(this, "queryOptions", {});
|
|
1372
1622
|
chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
|
|
1373
1623
|
chunkMWMSFIWN_cjs.__publicField(this, "localesArray");
|
|
@@ -1377,6 +1627,21 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1377
1627
|
chunkMWMSFIWN_cjs.__publicField(this, "pageNumber");
|
|
1378
1628
|
chunkMWMSFIWN_cjs.__publicField(this, "pageSizeValue");
|
|
1379
1629
|
chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
|
|
1630
|
+
/** The client's locale, asked when the query is sent rather than copied when it was built. */
|
|
1631
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
1632
|
+
chunkMWMSFIWN_cjs.__publicField(this, "freshValue");
|
|
1633
|
+
this.clientLocale = readClientLocale(locale);
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* The feed position this read follows — a change's `fresh` (`FeedChange`), or a resync's. Sent as
|
|
1637
|
+
* `?_fresh`, the one term the API declares for it: no cache — the Content API's edge or the
|
|
1638
|
+
* browser's own — holds an answer for that position from before it, so the read is answered after
|
|
1639
|
+
* the change, and every read naming the same position shares that answer. The answer is the
|
|
1640
|
+
* read's own; omit it for a read no change prompted.
|
|
1641
|
+
*/
|
|
1642
|
+
fresh(position) {
|
|
1643
|
+
this.freshValue = position;
|
|
1644
|
+
return this;
|
|
1380
1645
|
}
|
|
1381
1646
|
/**
|
|
1382
1647
|
* Headers this query adds to the client's own, e.g. `X-RelyIO-Dataset` to list another dataset
|
|
@@ -1388,9 +1653,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1388
1653
|
return this;
|
|
1389
1654
|
}
|
|
1390
1655
|
/**
|
|
1391
|
-
* Add where conditions to the query
|
|
1656
|
+
* Add where conditions to the query: conditions on the fields the content type declares. A
|
|
1657
|
+
* condition on `_metadata` is refused here, before anything is sent (`refuseMetadataConditions`).
|
|
1392
1658
|
*/
|
|
1393
1659
|
where(conditions) {
|
|
1660
|
+
refuseMetadataConditions(conditions);
|
|
1394
1661
|
this.queryOptions.where = {
|
|
1395
1662
|
...this.queryOptions.where,
|
|
1396
1663
|
...conditions
|
|
@@ -1647,7 +1914,11 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1647
1914
|
* Clone the query builder
|
|
1648
1915
|
*/
|
|
1649
1916
|
clone() {
|
|
1650
|
-
const cloned = new _ContentQueryBuilder(
|
|
1917
|
+
const cloned = new _ContentQueryBuilder(
|
|
1918
|
+
this.httpClient,
|
|
1919
|
+
this.contentType,
|
|
1920
|
+
this.clientLocale
|
|
1921
|
+
);
|
|
1651
1922
|
cloned.queryOptions = JSON.parse(JSON.stringify(this.queryOptions));
|
|
1652
1923
|
cloned.localeValue = this.localeValue;
|
|
1653
1924
|
cloned.localesArray = this.localesArray ? [...this.localesArray] : void 0;
|
|
@@ -1656,6 +1927,7 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1656
1927
|
cloned.pageNumber = this.pageNumber;
|
|
1657
1928
|
cloned.pageSizeValue = this.pageSizeValue;
|
|
1658
1929
|
cloned.requestHeaders = this.requestHeaders ? { ...this.requestHeaders } : void 0;
|
|
1930
|
+
cloned.freshValue = this.freshValue;
|
|
1659
1931
|
return cloned;
|
|
1660
1932
|
}
|
|
1661
1933
|
/**
|
|
@@ -1722,14 +1994,15 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1722
1994
|
if (this.queryOptions.cursor !== void 0) {
|
|
1723
1995
|
params.cursor = this.queryOptions.cursor;
|
|
1724
1996
|
}
|
|
1997
|
+
const clientLocale = this.clientLocale();
|
|
1725
1998
|
if (this.localeValue != null && this.localeValue !== "") {
|
|
1726
1999
|
params.locale = this.localeValue;
|
|
1727
2000
|
} else if (this.fetchAllLocales) {
|
|
1728
2001
|
params.locale = "*";
|
|
1729
2002
|
} else if (this.localesArray && this.localesArray.length > 0) {
|
|
1730
2003
|
params.locales = this.localesArray.join(",");
|
|
1731
|
-
} else if (
|
|
1732
|
-
params.locale =
|
|
2004
|
+
} else if (clientLocale != null && clientLocale !== "") {
|
|
2005
|
+
params.locale = clientLocale;
|
|
1733
2006
|
}
|
|
1734
2007
|
if (this.pageNumber !== void 0) {
|
|
1735
2008
|
params.page = this.pageNumber;
|
|
@@ -1747,23 +2020,44 @@ var _ContentQueryBuilder = class _ContentQueryBuilder {
|
|
|
1747
2020
|
params.childrenLimit = this.childrenOptions.limit;
|
|
1748
2021
|
}
|
|
1749
2022
|
}
|
|
2023
|
+
if (this.freshValue !== void 0) {
|
|
2024
|
+
params[FRESH_PARAMETER] = this.freshValue;
|
|
2025
|
+
}
|
|
1750
2026
|
return params;
|
|
1751
2027
|
}
|
|
1752
2028
|
};
|
|
1753
2029
|
chunkMWMSFIWN_cjs.__name(_ContentQueryBuilder, "ContentQueryBuilder");
|
|
1754
2030
|
var ContentQueryBuilder = _ContentQueryBuilder;
|
|
1755
2031
|
var _ContentByIdBuilder = class _ContentByIdBuilder {
|
|
1756
|
-
|
|
2032
|
+
/**
|
|
2033
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
|
|
2034
|
+
* read names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
|
|
2035
|
+
*/
|
|
2036
|
+
constructor(httpClient, contentType, id, locale) {
|
|
1757
2037
|
this.httpClient = httpClient;
|
|
1758
2038
|
this.contentType = contentType;
|
|
1759
2039
|
this.id = id;
|
|
1760
|
-
this.defaultLocale = defaultLocale;
|
|
1761
2040
|
chunkMWMSFIWN_cjs.__publicField(this, "includeRelations");
|
|
1762
2041
|
chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
|
|
1763
2042
|
chunkMWMSFIWN_cjs.__publicField(this, "localesArray");
|
|
1764
2043
|
chunkMWMSFIWN_cjs.__publicField(this, "fetchAllLocales", false);
|
|
1765
2044
|
chunkMWMSFIWN_cjs.__publicField(this, "childrenOptions");
|
|
1766
2045
|
chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
|
|
2046
|
+
/** The client's locale, asked when the read is sent rather than copied when it was built. */
|
|
2047
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
2048
|
+
chunkMWMSFIWN_cjs.__publicField(this, "freshValue");
|
|
2049
|
+
this.clientLocale = readClientLocale(locale);
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* The feed position this read follows — a change's `fresh` (`FeedChange`), or a resync's. Sent as
|
|
2053
|
+
* `?_fresh`, the one term the API declares for it: no cache — the Content API's edge or the
|
|
2054
|
+
* browser's own — holds an answer for that position from before it, so the read is answered after
|
|
2055
|
+
* the change, and every read naming the same position shares that answer. The answer is the
|
|
2056
|
+
* read's own; omit it for a read no change prompted.
|
|
2057
|
+
*/
|
|
2058
|
+
fresh(position) {
|
|
2059
|
+
this.freshValue = position;
|
|
2060
|
+
return this;
|
|
1767
2061
|
}
|
|
1768
2062
|
/**
|
|
1769
2063
|
* Include related content in the response
|
|
@@ -1833,14 +2127,15 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
|
|
|
1833
2127
|
if (this.includeRelations != null) {
|
|
1834
2128
|
params.include = this.includeRelations.join(",");
|
|
1835
2129
|
}
|
|
2130
|
+
const clientLocale = this.clientLocale();
|
|
1836
2131
|
if (this.localeValue != null && this.localeValue !== "") {
|
|
1837
2132
|
params.locale = this.localeValue;
|
|
1838
2133
|
} else if (this.fetchAllLocales) {
|
|
1839
2134
|
params.locale = "*";
|
|
1840
2135
|
} else if (this.localesArray && this.localesArray.length > 0) {
|
|
1841
2136
|
params.locales = this.localesArray.join(",");
|
|
1842
|
-
} else if (
|
|
1843
|
-
params.locale =
|
|
2137
|
+
} else if (clientLocale != null && clientLocale !== "") {
|
|
2138
|
+
params.locale = clientLocale;
|
|
1844
2139
|
}
|
|
1845
2140
|
if (this.childrenOptions != null) {
|
|
1846
2141
|
if (this.childrenOptions.contentTypes) {
|
|
@@ -1852,6 +2147,9 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
|
|
|
1852
2147
|
params.childrenLimit = this.childrenOptions.limit;
|
|
1853
2148
|
}
|
|
1854
2149
|
}
|
|
2150
|
+
if (this.freshValue !== void 0) {
|
|
2151
|
+
params[FRESH_PARAMETER] = this.freshValue;
|
|
2152
|
+
}
|
|
1855
2153
|
try {
|
|
1856
2154
|
return await this.httpClient.fetchPayload(
|
|
1857
2155
|
"/v1/{contentType}/{id}",
|
|
@@ -1905,22 +2203,28 @@ chunkMWMSFIWN_cjs.__name(entityTagOf, "entityTagOf");
|
|
|
1905
2203
|
|
|
1906
2204
|
// src/content/content-client.ts
|
|
1907
2205
|
var _ContentClient = class _ContentClient {
|
|
1908
|
-
|
|
2206
|
+
/**
|
|
2207
|
+
* @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
|
|
2208
|
+
* every call, or a locale fixed for this client
|
|
2209
|
+
*/
|
|
2210
|
+
constructor(httpClient, contentType, locale) {
|
|
1909
2211
|
this.httpClient = httpClient;
|
|
1910
2212
|
this.contentType = contentType;
|
|
1911
|
-
this.
|
|
2213
|
+
/** The client's locale, asked on every call rather than copied when this client was taken. */
|
|
2214
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
2215
|
+
this.clientLocale = readClientLocale(locale);
|
|
1912
2216
|
}
|
|
1913
2217
|
/**
|
|
1914
2218
|
* Create a new query builder for this content type
|
|
1915
2219
|
*/
|
|
1916
2220
|
query() {
|
|
1917
|
-
return new ContentQueryBuilder(this.httpClient, this.contentType, this.
|
|
2221
|
+
return new ContentQueryBuilder(this.httpClient, this.contentType, this.clientLocale);
|
|
1918
2222
|
}
|
|
1919
2223
|
/**
|
|
1920
2224
|
* Find content by ID with fluent options
|
|
1921
2225
|
*/
|
|
1922
2226
|
findById(id) {
|
|
1923
|
-
return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.
|
|
2227
|
+
return new ContentByIdBuilder(this.httpClient, this.contentType, id, this.clientLocale);
|
|
1924
2228
|
}
|
|
1925
2229
|
/**
|
|
1926
2230
|
* Fetch all content items
|
|
@@ -2004,7 +2308,7 @@ var _ContentClient = class _ContentClient {
|
|
|
2004
2308
|
async fetchOneWithTag(id, options) {
|
|
2005
2309
|
const query = {};
|
|
2006
2310
|
if (options?.include != null) query.include = options.include.join(",");
|
|
2007
|
-
const locale = options?.locale ?? this.
|
|
2311
|
+
const locale = options?.locale ?? this.clientLocale();
|
|
2008
2312
|
if (locale != null && locale !== "") query.locale = locale;
|
|
2009
2313
|
const response = await this.httpClient.send(
|
|
2010
2314
|
"/v1/{contentType}/{id}",
|
|
@@ -2034,16 +2338,17 @@ var _ContentClient = class _ContentClient {
|
|
|
2034
2338
|
* @param options - Create options (slug, locale, parentId, sortOrder), and `headers` this one
|
|
2035
2339
|
* request adds — e.g. `{ 'X-RelyIO-Dataset': 'staging' }` to write a dataset other than the
|
|
2036
2340
|
* client's. They are sent, never put in the body; `idempotencyKey` still wins over an
|
|
2037
|
-
* `Idempotency-Key` among them.
|
|
2341
|
+
* `Idempotency-Key` among them. `locale` defaults to the client's own (`withLocale()`).
|
|
2038
2342
|
*/
|
|
2039
2343
|
async create(data, options) {
|
|
2040
|
-
const { idempotencyKey, headers, ...body } = options ?? {};
|
|
2344
|
+
const { idempotencyKey, headers, locale, ...body } = options ?? {};
|
|
2345
|
+
const sent = callLocale(locale, this.clientLocale());
|
|
2041
2346
|
return this.httpClient.fetchPayload(
|
|
2042
2347
|
"/v1/{contentType}",
|
|
2043
2348
|
"post",
|
|
2044
2349
|
{
|
|
2045
2350
|
path: { contentType: this.contentType },
|
|
2046
|
-
body: { content: data, ...body },
|
|
2351
|
+
body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
|
|
2047
2352
|
headers: requestHeaders(headers, writeHeaders({ idempotencyKey }))
|
|
2048
2353
|
}
|
|
2049
2354
|
);
|
|
@@ -2054,16 +2359,18 @@ var _ContentClient = class _ContentClient {
|
|
|
2054
2359
|
* @param data - Fields to update
|
|
2055
2360
|
* @param options - Update options (slug, locale, parentId, sortOrder), and `headers` this one
|
|
2056
2361
|
* request adds, as for {@link create}. `ifMatch` and `idempotencyKey` win over the same
|
|
2057
|
-
* header among them.
|
|
2362
|
+
* header among them. `locale` defaults to the client's own, the locale whose entity tag
|
|
2363
|
+
* {@link fetchOneWithTag} reads, so the tag it hands back is checked against the same locale.
|
|
2058
2364
|
*/
|
|
2059
2365
|
async update(id, data, options) {
|
|
2060
|
-
const { idempotencyKey, ifMatch, headers, ...body } = options ?? {};
|
|
2366
|
+
const { idempotencyKey, ifMatch, headers, locale, ...body } = options ?? {};
|
|
2367
|
+
const sent = callLocale(locale, this.clientLocale());
|
|
2061
2368
|
return this.httpClient.fetchPayload(
|
|
2062
2369
|
"/v1/{contentType}/{id}",
|
|
2063
2370
|
"patch",
|
|
2064
2371
|
{
|
|
2065
2372
|
path: { contentType: this.contentType, id },
|
|
2066
|
-
body: { content: data, ...body },
|
|
2373
|
+
body: { content: data, ...body, ...sent === void 0 ? {} : { locale: sent } },
|
|
2067
2374
|
headers: requestHeaders(headers, writeHeaders({ idempotencyKey, ifMatch }))
|
|
2068
2375
|
}
|
|
2069
2376
|
);
|
|
@@ -2095,32 +2402,35 @@ var _ContentClient = class _ContentClient {
|
|
|
2095
2402
|
* Get version history for one locale of an entry.
|
|
2096
2403
|
*
|
|
2097
2404
|
* Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
|
|
2098
|
-
* schema default
|
|
2099
|
-
* rather than another locale's rows. Every row names the
|
|
2405
|
+
* client's own (`withLocale()`), else the schema default; no fallback is applied, and a locale
|
|
2406
|
+
* with no history returns an empty array rather than another locale's rows. Every row names the
|
|
2407
|
+
* locale it belongs to.
|
|
2100
2408
|
*/
|
|
2101
2409
|
async versions(id, options) {
|
|
2410
|
+
const locale = callLocale(options?.locale, this.clientLocale());
|
|
2102
2411
|
return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions", "get", {
|
|
2103
2412
|
path: { contentType: this.contentType, id },
|
|
2104
2413
|
query: {
|
|
2105
2414
|
limit: options?.limit ?? 10,
|
|
2106
|
-
...
|
|
2415
|
+
...locale === void 0 ? {} : { locale }
|
|
2107
2416
|
}
|
|
2108
2417
|
});
|
|
2109
2418
|
}
|
|
2110
2419
|
/**
|
|
2111
2420
|
* Get a specific version of an entry.
|
|
2112
2421
|
*
|
|
2113
|
-
* `locale` defaults to the
|
|
2114
|
-
* different content in each one.
|
|
2422
|
+
* `locale` defaults to the client's own (`withLocale()`), else the schema default. Version
|
|
2423
|
+
* numbers are per locale, so version 2 is different content in each one.
|
|
2115
2424
|
*/
|
|
2116
2425
|
async version(id, versionNumber, options) {
|
|
2426
|
+
const locale = callLocale(options?.locale, this.clientLocale());
|
|
2117
2427
|
return this.httpClient.fetchPayload("/v1/{contentType}/{id}/versions/{versionNumber}", "get", {
|
|
2118
2428
|
path: {
|
|
2119
2429
|
contentType: this.contentType,
|
|
2120
2430
|
id,
|
|
2121
2431
|
versionNumber: String(versionNumber)
|
|
2122
2432
|
},
|
|
2123
|
-
query:
|
|
2433
|
+
query: locale === void 0 ? void 0 : { locale }
|
|
2124
2434
|
});
|
|
2125
2435
|
}
|
|
2126
2436
|
/**
|
|
@@ -2159,7 +2469,7 @@ var _ContentClient = class _ContentClient {
|
|
|
2159
2469
|
if (options?.include != null) {
|
|
2160
2470
|
params.include = options.include.join(",");
|
|
2161
2471
|
}
|
|
2162
|
-
const locale = options?.locale ?? this.
|
|
2472
|
+
const locale = options?.locale ?? this.clientLocale();
|
|
2163
2473
|
if (locale != null && locale !== "") {
|
|
2164
2474
|
params.locale = locale;
|
|
2165
2475
|
}
|
|
@@ -2179,19 +2489,20 @@ var _ContentClient = class _ContentClient {
|
|
|
2179
2489
|
* Create a new ContentClient for a different content type
|
|
2180
2490
|
*/
|
|
2181
2491
|
ofType(contentType) {
|
|
2182
|
-
return new _ContentClient(this.httpClient, contentType, this.
|
|
2492
|
+
return new _ContentClient(this.httpClient, contentType, this.clientLocale);
|
|
2183
2493
|
}
|
|
2184
2494
|
/**
|
|
2185
|
-
* Create a new ContentClient with a different default locale
|
|
2495
|
+
* Create a new ContentClient with a different default locale, fixed: an update of the client's
|
|
2496
|
+
* locale (`updateConfig({ locale })`) does not reach it
|
|
2186
2497
|
*/
|
|
2187
2498
|
withLocale(locale) {
|
|
2188
2499
|
return new _ContentClient(this.httpClient, this.contentType, locale);
|
|
2189
2500
|
}
|
|
2190
2501
|
/**
|
|
2191
|
-
* Get the
|
|
2502
|
+
* Get the default locale as it is now: the client's, or the one `withLocale()` fixed
|
|
2192
2503
|
*/
|
|
2193
2504
|
getDefaultLocale() {
|
|
2194
|
-
return this.
|
|
2505
|
+
return this.clientLocale();
|
|
2195
2506
|
}
|
|
2196
2507
|
};
|
|
2197
2508
|
chunkMWMSFIWN_cjs.__name(_ContentClient, "ContentClient");
|
|
@@ -2200,7 +2511,7 @@ var ContentClient = _ContentClient;
|
|
|
2200
2511
|
// src/errors/file-errors.ts
|
|
2201
2512
|
var _FileUploadError = class _FileUploadError extends SDKError {
|
|
2202
2513
|
constructor(code, message, options = {}) {
|
|
2203
|
-
super(message, options.statusCode, options.cause, { fileErrorCode: code });
|
|
2514
|
+
super(message, options.statusCode, options.cause, { ...options.context, fileErrorCode: code });
|
|
2204
2515
|
chunkMWMSFIWN_cjs.__publicField(this, "code");
|
|
2205
2516
|
chunkMWMSFIWN_cjs.__publicField(this, "retryable");
|
|
2206
2517
|
this.code = code;
|
|
@@ -2247,11 +2558,52 @@ function validateFile(file, constraints = {}) {
|
|
|
2247
2558
|
}
|
|
2248
2559
|
chunkMWMSFIWN_cjs.__name(validateFile, "validateFile");
|
|
2249
2560
|
|
|
2561
|
+
// src/errors/file-error-codes.ts
|
|
2562
|
+
var FILE_ERROR_CODES = [
|
|
2563
|
+
"UPLOAD_TOO_LARGE",
|
|
2564
|
+
"UNSUPPORTED_MIME",
|
|
2565
|
+
"DIMENSION_OUT_OF_RANGE",
|
|
2566
|
+
"ASPECT_RATIO",
|
|
2567
|
+
"CORRUPT_FILE",
|
|
2568
|
+
"UNSUPPORTED_CODEC",
|
|
2569
|
+
"IMAGES_LIMIT_EXCEEDED",
|
|
2570
|
+
"STREAM_ENCODE_FAILED",
|
|
2571
|
+
"SCAN_INFECTED",
|
|
2572
|
+
"INTERNAL"
|
|
2573
|
+
];
|
|
2574
|
+
|
|
2250
2575
|
// src/content/asset-client.ts
|
|
2576
|
+
function assertWaitOptions(options) {
|
|
2577
|
+
const { timeoutMs, pollIntervalMs } = options;
|
|
2578
|
+
if (timeoutMs !== void 0 && !(typeof timeoutMs === "number" && timeoutMs >= 0 && timeoutMs <= MAX_TIMER_DELAY_MS)) {
|
|
2579
|
+
throw new Error(
|
|
2580
|
+
`timeoutMs must be a number of milliseconds from 0 to ${MAX_TIMER_DELAY_MS}, and got ${String(timeoutMs)}`
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
if (pollIntervalMs !== void 0 && !isTimerDelay(pollIntervalMs)) {
|
|
2584
|
+
throw new Error(
|
|
2585
|
+
`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)}`
|
|
2586
|
+
);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
chunkMWMSFIWN_cjs.__name(assertWaitOptions, "assertWaitOptions");
|
|
2251
2590
|
function hasText(value) {
|
|
2252
2591
|
return value != null && value !== "";
|
|
2253
2592
|
}
|
|
2254
2593
|
chunkMWMSFIWN_cjs.__name(hasText, "hasText");
|
|
2594
|
+
function processingFailure(subject, stored) {
|
|
2595
|
+
const storedCode = stored?.code;
|
|
2596
|
+
const code = FILE_ERROR_CODES.find((known) => known === storedCode) ?? "PROCESSING_FAILED";
|
|
2597
|
+
return new FileUploadError(
|
|
2598
|
+
code,
|
|
2599
|
+
`Asset ${subject}: ${stored?.message ?? "File processing failed"}`,
|
|
2600
|
+
{
|
|
2601
|
+
retriable: stored?.retriable === true,
|
|
2602
|
+
context: { processingError: stored }
|
|
2603
|
+
}
|
|
2604
|
+
);
|
|
2605
|
+
}
|
|
2606
|
+
chunkMWMSFIWN_cjs.__name(processingFailure, "processingFailure");
|
|
2255
2607
|
async function computeSha256Hex(blob) {
|
|
2256
2608
|
try {
|
|
2257
2609
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -2267,11 +2619,17 @@ async function computeSha256Hex(blob) {
|
|
|
2267
2619
|
}
|
|
2268
2620
|
chunkMWMSFIWN_cjs.__name(computeSha256Hex, "computeSha256Hex");
|
|
2269
2621
|
var _AssetFileBuilder = class _AssetFileBuilder {
|
|
2270
|
-
|
|
2622
|
+
/**
|
|
2623
|
+
* @param locale - The client's locale, sent when a call names none: the function
|
|
2624
|
+
* `TypedRelyIOClient` hands over, or a locale fixed for this builder
|
|
2625
|
+
*/
|
|
2626
|
+
constructor(httpClient, assetType, entryUid, locale) {
|
|
2271
2627
|
this.httpClient = httpClient;
|
|
2272
2628
|
this.assetType = assetType;
|
|
2273
2629
|
this.entryUid = entryUid;
|
|
2274
|
-
this.
|
|
2630
|
+
/** The client's locale, asked on every call rather than copied when this builder was taken. */
|
|
2631
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
2632
|
+
this.clientLocale = readClientLocale(locale);
|
|
2275
2633
|
}
|
|
2276
2634
|
/**
|
|
2277
2635
|
* The path parameters every `/file/*` route on this builder takes.
|
|
@@ -2284,7 +2642,16 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2284
2642
|
return { contentType: this.assetType, id: this.entryUid };
|
|
2285
2643
|
}
|
|
2286
2644
|
withLocale(locale) {
|
|
2287
|
-
return locale ?? this.
|
|
2645
|
+
return locale ?? this.clientLocale();
|
|
2646
|
+
}
|
|
2647
|
+
/**
|
|
2648
|
+
* The `locale` body field of a multipart call: the session's, else the client's. The API finds
|
|
2649
|
+
* the binding by it, so a session a `withLocale()` client opened must name the same locale on
|
|
2650
|
+
* every later call or its `objectKey` is refused as another binding's.
|
|
2651
|
+
*/
|
|
2652
|
+
localeField(locale) {
|
|
2653
|
+
const sent = this.withLocale(locale);
|
|
2654
|
+
return hasText(sent) ? { locale: sent } : {};
|
|
2288
2655
|
}
|
|
2289
2656
|
/**
|
|
2290
2657
|
* Issue a single upload target — an R2 presigned PUT (image/file) or a
|
|
@@ -2343,7 +2710,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2343
2710
|
uploadId: target.uploadId,
|
|
2344
2711
|
objectKey: target.objectKey,
|
|
2345
2712
|
partNumber: target.partNumber,
|
|
2346
|
-
...
|
|
2713
|
+
...this.localeField(target.locale)
|
|
2347
2714
|
}
|
|
2348
2715
|
});
|
|
2349
2716
|
}
|
|
@@ -2354,7 +2721,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2354
2721
|
body: {
|
|
2355
2722
|
uploadId: target.uploadId,
|
|
2356
2723
|
objectKey: target.objectKey,
|
|
2357
|
-
...
|
|
2724
|
+
...this.localeField(target.locale)
|
|
2358
2725
|
}
|
|
2359
2726
|
});
|
|
2360
2727
|
return payload.parts;
|
|
@@ -2367,7 +2734,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2367
2734
|
uploadId: target.uploadId,
|
|
2368
2735
|
objectKey: target.objectKey,
|
|
2369
2736
|
parts: target.parts.map((p) => ({ partNumber: p.partNumber, etag: p.etag })),
|
|
2370
|
-
...
|
|
2737
|
+
...this.localeField(target.locale)
|
|
2371
2738
|
}
|
|
2372
2739
|
});
|
|
2373
2740
|
}
|
|
@@ -2378,7 +2745,7 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2378
2745
|
body: {
|
|
2379
2746
|
uploadId: target.uploadId,
|
|
2380
2747
|
objectKey: target.objectKey,
|
|
2381
|
-
...
|
|
2748
|
+
...this.localeField(target.locale)
|
|
2382
2749
|
}
|
|
2383
2750
|
});
|
|
2384
2751
|
}
|
|
@@ -2398,6 +2765,25 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2398
2765
|
{ path: this.target, query: params }
|
|
2399
2766
|
);
|
|
2400
2767
|
}
|
|
2768
|
+
/**
|
|
2769
|
+
* Read where this file's upload got to — `status`, and the processing stage, progress and error
|
|
2770
|
+
* the pipeline recorded — whatever the asset entry is published in.
|
|
2771
|
+
*
|
|
2772
|
+
* An asset is a draft until its file is ready, and stays one when its file fails, so a key that
|
|
2773
|
+
* reads published content finds no entry for an upload in flight or one that failed. This read
|
|
2774
|
+
* answers for the binding itself. It takes the capability the upload calls take, so a read-only
|
|
2775
|
+
* key is refused with `ReadOnlyKeyError`, and it never returns the entry's fields.
|
|
2776
|
+
*/
|
|
2777
|
+
async status(options = {}) {
|
|
2778
|
+
const params = {};
|
|
2779
|
+
const locale = this.withLocale(options.locale);
|
|
2780
|
+
if (hasText(locale)) params.locale = locale;
|
|
2781
|
+
return this.httpClient.fetchPayload(
|
|
2782
|
+
"/v1/{contentType}/{id}/file",
|
|
2783
|
+
"get",
|
|
2784
|
+
{ path: this.target, query: params }
|
|
2785
|
+
);
|
|
2786
|
+
}
|
|
2401
2787
|
/**
|
|
2402
2788
|
* Update the binding's delivery visibility (token-based; no byte relocation —
|
|
2403
2789
|
* a downgrade purges the gateway cache). Returns the refreshed asset entry.
|
|
@@ -2436,14 +2822,31 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2436
2822
|
});
|
|
2437
2823
|
}
|
|
2438
2824
|
/**
|
|
2439
|
-
* Poll the asset entry until its file binding reaches `ready
|
|
2440
|
-
*
|
|
2825
|
+
* Poll the asset entry until its file binding reaches `ready`, and resolve with the ready entry.
|
|
2826
|
+
*
|
|
2827
|
+
* Each poll reads the entry through the key's lens. When that finds nothing — a key that reads
|
|
2828
|
+
* published content, and an asset that is a draft until its file is ready and stays one when it
|
|
2829
|
+
* fails — the poll reads the binding itself ({@link status}), so a failed upload rejects as one
|
|
2830
|
+
* rather than running out the limit (REL-1481).
|
|
2831
|
+
*
|
|
2832
|
+
* @throws {FileUploadError} When processing failed. `code` is the processing code the service
|
|
2833
|
+
* stored — `UNSUPPORTED_CODEC`, `CORRUPT_FILE` and so on — or `PROCESSING_FAILED` where it
|
|
2834
|
+
* stored none this SDK knows; `context.processingError` holds what it stored, and `retryable`
|
|
2835
|
+
* is its `retriable` hint.
|
|
2836
|
+
* @throws {TimeoutError} When `timeoutMs` passes first. The file may still become ready; the
|
|
2837
|
+
* error's `context.timeout` is the limit and `context.fileStatus` the status last seen. A file
|
|
2838
|
+
* that is `ready` in an asset the key's lens never shows — created with `publish: false`, or
|
|
2839
|
+
* awaiting a workflow — ends here too, and the message says so.
|
|
2840
|
+
* @throws {ReadOnlyKeyError} When the key's lens does not show the asset and the key may not read
|
|
2841
|
+
* its binding either: nothing it can read would ever report the file.
|
|
2441
2842
|
*/
|
|
2442
2843
|
async waitUntilReady(options = {}) {
|
|
2844
|
+
assertWaitOptions(options);
|
|
2443
2845
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
2444
2846
|
const pollIntervalMs = options.pollIntervalMs ?? 1500;
|
|
2445
2847
|
const locale = this.withLocale(options.locale);
|
|
2446
2848
|
const deadline = Date.now() + timeoutMs;
|
|
2849
|
+
const subject = `${this.assetType}/${this.entryUid}`;
|
|
2447
2850
|
for (; ; ) {
|
|
2448
2851
|
const builder = new ContentByIdBuilder(
|
|
2449
2852
|
this.httpClient,
|
|
@@ -2453,15 +2856,24 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2453
2856
|
);
|
|
2454
2857
|
if (hasText(locale)) builder.locale(locale);
|
|
2455
2858
|
const entry = await builder.execute();
|
|
2456
|
-
|
|
2457
|
-
if (entry
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
throw
|
|
2859
|
+
let status;
|
|
2860
|
+
if (entry === null) {
|
|
2861
|
+
const binding = await this.status({ ...hasText(locale) ? { locale } : {} });
|
|
2862
|
+
status = binding.status;
|
|
2863
|
+
if (status === "failed") throw processingFailure(subject, binding.processing?.error);
|
|
2864
|
+
} else {
|
|
2865
|
+
status = entry.file?.status;
|
|
2866
|
+
if (status === "ready") return entry;
|
|
2867
|
+
if (status === "failed") throw processingFailure(subject, entry.file?.processing?.error);
|
|
2461
2868
|
}
|
|
2462
2869
|
if (Date.now() >= deadline) {
|
|
2463
|
-
|
|
2464
|
-
|
|
2870
|
+
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" : "";
|
|
2871
|
+
throw new TimeoutError(
|
|
2872
|
+
`Timed out after ${timeoutMs}ms waiting for ${subject} (status: ${status ?? "unknown"})${unseen}`,
|
|
2873
|
+
timeoutMs,
|
|
2874
|
+
void 0,
|
|
2875
|
+
void 0,
|
|
2876
|
+
{ fileStatus: status }
|
|
2465
2877
|
);
|
|
2466
2878
|
}
|
|
2467
2879
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
@@ -2471,11 +2883,14 @@ var _AssetFileBuilder = class _AssetFileBuilder {
|
|
|
2471
2883
|
chunkMWMSFIWN_cjs.__name(_AssetFileBuilder, "AssetFileBuilder");
|
|
2472
2884
|
var AssetFileBuilder = _AssetFileBuilder;
|
|
2473
2885
|
var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
2474
|
-
|
|
2886
|
+
/**
|
|
2887
|
+
* @param locale - The client's locale, the upload's when `.locale()` names none: the function
|
|
2888
|
+
* `TypedRelyIOClient` hands over, or a locale fixed for this upload
|
|
2889
|
+
*/
|
|
2890
|
+
constructor(httpClient, assetType, file, locale) {
|
|
2475
2891
|
this.httpClient = httpClient;
|
|
2476
2892
|
this.assetType = assetType;
|
|
2477
2893
|
this.file = file;
|
|
2478
|
-
this.defaultLocale = defaultLocale;
|
|
2479
2894
|
chunkMWMSFIWN_cjs.__publicField(this, "_fileName");
|
|
2480
2895
|
chunkMWMSFIWN_cjs.__publicField(this, "_visibility");
|
|
2481
2896
|
chunkMWMSFIWN_cjs.__publicField(this, "_locale");
|
|
@@ -2487,6 +2902,9 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
|
2487
2902
|
chunkMWMSFIWN_cjs.__publicField(this, "_onProgress");
|
|
2488
2903
|
chunkMWMSFIWN_cjs.__publicField(this, "_validate");
|
|
2489
2904
|
chunkMWMSFIWN_cjs.__publicField(this, "_maxPartRetries", 3);
|
|
2905
|
+
/** The client's locale, read once when the upload starts. */
|
|
2906
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
2907
|
+
this.clientLocale = readClientLocale(locale);
|
|
2490
2908
|
}
|
|
2491
2909
|
/** Subscribe to client → storage upload progress (single PUT + multipart). */
|
|
2492
2910
|
onProgress(callback) {
|
|
@@ -2536,8 +2954,14 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
|
2536
2954
|
this._slug = slug;
|
|
2537
2955
|
return this;
|
|
2538
2956
|
}
|
|
2539
|
-
/**
|
|
2957
|
+
/**
|
|
2958
|
+
* Wait until the file binding becomes `ready` before resolving.
|
|
2959
|
+
*
|
|
2960
|
+
* @throws {Error} When `timeoutMs` or `pollIntervalMs` is one the wait cannot honour — refused
|
|
2961
|
+
* here, before anything is uploaded, rather than after the bytes are in.
|
|
2962
|
+
*/
|
|
2540
2963
|
waitForReady(options = true) {
|
|
2964
|
+
if (typeof options === "object") assertWaitOptions(options);
|
|
2541
2965
|
if (options === false) {
|
|
2542
2966
|
this._waitForReady = false;
|
|
2543
2967
|
} else {
|
|
@@ -2552,7 +2976,8 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
|
2552
2976
|
if (!fileName) {
|
|
2553
2977
|
throw new Error('A file name is required: pass a File, or call .filename("name.ext")');
|
|
2554
2978
|
}
|
|
2555
|
-
const
|
|
2979
|
+
const clientLocale = this.clientLocale();
|
|
2980
|
+
const locale = this._locale ?? clientLocale;
|
|
2556
2981
|
if (this._validate) {
|
|
2557
2982
|
const violations = validateFile(this.file, this._validate);
|
|
2558
2983
|
if (violations.length > 0) {
|
|
@@ -2563,7 +2988,7 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
|
2563
2988
|
}
|
|
2564
2989
|
}
|
|
2565
2990
|
const hash = await computeSha256Hex(this.file);
|
|
2566
|
-
const client = new AssetClient(this.httpClient, this.assetType,
|
|
2991
|
+
const client = new AssetClient(this.httpClient, this.assetType, clientLocale);
|
|
2567
2992
|
const created = await client.create(this._content, {
|
|
2568
2993
|
...hasText(this._slug) ? { slug: this._slug } : {},
|
|
2569
2994
|
...hasText(locale) ? { locale } : {},
|
|
@@ -2714,17 +3139,26 @@ var _AssetUploadBuilder = class _AssetUploadBuilder {
|
|
|
2714
3139
|
chunkMWMSFIWN_cjs.__name(_AssetUploadBuilder, "AssetUploadBuilder");
|
|
2715
3140
|
var AssetUploadBuilder = _AssetUploadBuilder;
|
|
2716
3141
|
var _AssetClient = class _AssetClient {
|
|
2717
|
-
|
|
3142
|
+
/**
|
|
3143
|
+
* @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
|
|
3144
|
+
* every call, or a locale fixed for this client
|
|
3145
|
+
*/
|
|
3146
|
+
constructor(httpClient, assetType, locale) {
|
|
2718
3147
|
this.httpClient = httpClient;
|
|
2719
3148
|
this.assetType = assetType;
|
|
2720
|
-
this.
|
|
3149
|
+
/** The client's locale, asked on every call rather than copied when this client was taken. */
|
|
3150
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3151
|
+
this.clientLocale = readClientLocale(locale);
|
|
2721
3152
|
}
|
|
2722
|
-
/**
|
|
3153
|
+
/**
|
|
3154
|
+
* Create a query builder for this asset type. It resolves asset reads; its conditions name the
|
|
3155
|
+
* asset type's fields, which the `file` and `urls` blocks are not.
|
|
3156
|
+
*/
|
|
2723
3157
|
query() {
|
|
2724
3158
|
return new ContentQueryBuilder(
|
|
2725
3159
|
this.httpClient,
|
|
2726
3160
|
this.assetType,
|
|
2727
|
-
this.
|
|
3161
|
+
this.clientLocale
|
|
2728
3162
|
);
|
|
2729
3163
|
}
|
|
2730
3164
|
/** Find an asset entry by id (or slug) with fluent options. */
|
|
@@ -2733,7 +3167,7 @@ var _AssetClient = class _AssetClient {
|
|
|
2733
3167
|
this.httpClient,
|
|
2734
3168
|
this.assetType,
|
|
2735
3169
|
id,
|
|
2736
|
-
this.
|
|
3170
|
+
this.clientLocale
|
|
2737
3171
|
);
|
|
2738
3172
|
}
|
|
2739
3173
|
/** Fetch a single asset entry by id (or slug), or `null` if not found. */
|
|
@@ -2754,28 +3188,34 @@ var _AssetClient = class _AssetClient {
|
|
|
2754
3188
|
* Create a new asset entry as a draft. The binary is uploaded separately via
|
|
2755
3189
|
* `file(uid)` (or use the high-level `upload()` helper), and the entry
|
|
2756
3190
|
* auto-publishes when its file becomes ready (unless `publish: false`).
|
|
3191
|
+
* `locale` defaults to the client's own (`withLocale()`).
|
|
2757
3192
|
*/
|
|
2758
3193
|
async create(data, options) {
|
|
2759
|
-
const { idempotencyKey, ...rest } = options ?? {};
|
|
3194
|
+
const { idempotencyKey, locale, ...rest } = options ?? {};
|
|
3195
|
+
const sent = callLocale(locale, this.clientLocale());
|
|
2760
3196
|
return this.httpClient.fetchPayload(
|
|
2761
3197
|
"/v1/{contentType}",
|
|
2762
3198
|
"post",
|
|
2763
3199
|
{
|
|
2764
3200
|
path: { contentType: this.assetType },
|
|
2765
|
-
body: { content: data, ...rest },
|
|
3201
|
+
body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
|
|
2766
3202
|
headers: writeHeaders({ idempotencyKey })
|
|
2767
3203
|
}
|
|
2768
3204
|
);
|
|
2769
3205
|
}
|
|
2770
|
-
/**
|
|
3206
|
+
/**
|
|
3207
|
+
* Update an asset entry's metadata fields (and/or slug). `locale` defaults to the client's own
|
|
3208
|
+
* (`withLocale()`).
|
|
3209
|
+
*/
|
|
2771
3210
|
async update(id, data, options) {
|
|
2772
|
-
const { idempotencyKey, ifMatch, ...rest } = options ?? {};
|
|
3211
|
+
const { idempotencyKey, ifMatch, locale, ...rest } = options ?? {};
|
|
3212
|
+
const sent = callLocale(locale, this.clientLocale());
|
|
2773
3213
|
return this.httpClient.fetchPayload(
|
|
2774
3214
|
"/v1/{contentType}/{id}",
|
|
2775
3215
|
"patch",
|
|
2776
3216
|
{
|
|
2777
3217
|
path: { contentType: this.assetType, id },
|
|
2778
|
-
body: { content: data, ...rest },
|
|
3218
|
+
body: { content: data, ...rest, ...sent === void 0 ? {} : { locale: sent } },
|
|
2779
3219
|
headers: writeHeaders({ idempotencyKey, ifMatch })
|
|
2780
3220
|
}
|
|
2781
3221
|
);
|
|
@@ -2789,21 +3229,24 @@ var _AssetClient = class _AssetClient {
|
|
|
2789
3229
|
}
|
|
2790
3230
|
/** Get the file sub-resource builder for a specific asset entry. */
|
|
2791
3231
|
file(entryUid) {
|
|
2792
|
-
return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.
|
|
3232
|
+
return new AssetFileBuilder(this.httpClient, this.assetType, entryUid, this.clientLocale);
|
|
2793
3233
|
}
|
|
2794
3234
|
/** Start a high-level upload (create → presign → PUT → confirm). */
|
|
2795
3235
|
upload(file) {
|
|
2796
|
-
return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.
|
|
3236
|
+
return new AssetUploadBuilder(this.httpClient, this.assetType, file, this.clientLocale);
|
|
2797
3237
|
}
|
|
2798
3238
|
/** Get the asset type id. */
|
|
2799
3239
|
getAssetType() {
|
|
2800
3240
|
return this.assetType;
|
|
2801
3241
|
}
|
|
2802
|
-
/** Get the
|
|
3242
|
+
/** Get the default locale as it is now: the client's, or the one `withLocale()` fixed. */
|
|
2803
3243
|
getDefaultLocale() {
|
|
2804
|
-
return this.
|
|
3244
|
+
return this.clientLocale();
|
|
2805
3245
|
}
|
|
2806
|
-
/**
|
|
3246
|
+
/**
|
|
3247
|
+
* Create a new AssetClient for this type with a different default locale, fixed: an update of the
|
|
3248
|
+
* client's locale (`updateConfig({ locale })`) does not reach it.
|
|
3249
|
+
*/
|
|
2807
3250
|
withLocale(locale) {
|
|
2808
3251
|
return new _AssetClient(this.httpClient, this.assetType, locale);
|
|
2809
3252
|
}
|
|
@@ -2819,12 +3262,18 @@ chunkMWMSFIWN_cjs.__name(isAssetEntry, "isAssetEntry");
|
|
|
2819
3262
|
|
|
2820
3263
|
// src/content/singleton-client.ts
|
|
2821
3264
|
var _SingletonClient = class _SingletonClient {
|
|
2822
|
-
|
|
3265
|
+
/**
|
|
3266
|
+
* @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
|
|
3267
|
+
* every call, or a locale fixed for this client
|
|
3268
|
+
*/
|
|
3269
|
+
constructor(httpClient, singletonKey, locale) {
|
|
2823
3270
|
this.httpClient = httpClient;
|
|
2824
3271
|
this.singletonKey = singletonKey;
|
|
2825
|
-
this.defaultLocale = defaultLocale;
|
|
2826
3272
|
chunkMWMSFIWN_cjs.__publicField(this, "includeFields");
|
|
2827
3273
|
chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
|
|
3274
|
+
/** The client's locale, asked on every call rather than copied when this client was taken. */
|
|
3275
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3276
|
+
this.clientLocale = readClientLocale(locale);
|
|
2828
3277
|
}
|
|
2829
3278
|
/**
|
|
2830
3279
|
* Include reference fields in the response
|
|
@@ -2864,9 +3313,10 @@ var _SingletonClient = class _SingletonClient {
|
|
|
2864
3313
|
async fetchWithTag(options) {
|
|
2865
3314
|
const query = {};
|
|
2866
3315
|
const includeValue = options?.include ?? this.includeFields;
|
|
2867
|
-
const localeValueFinal = options?.locale ?? this.localeValue ?? this.
|
|
3316
|
+
const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
|
|
2868
3317
|
if (includeValue) query.include = includeValue.join(",");
|
|
2869
3318
|
if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
|
|
3319
|
+
if (options?.fresh !== void 0) query[FRESH_PARAMETER] = options.fresh;
|
|
2870
3320
|
const response = await this.httpClient.send(
|
|
2871
3321
|
"/v1/singletons/{key}",
|
|
2872
3322
|
"get",
|
|
@@ -2878,11 +3328,12 @@ var _SingletonClient = class _SingletonClient {
|
|
|
2878
3328
|
* Update singleton content. The API auto-publishes on PATCH — there is no
|
|
2879
3329
|
* separate publish route; calling `update()` writes and publishes.
|
|
2880
3330
|
* @param data - The content fields to update
|
|
2881
|
-
* @param locale - Optional locale for localized content (overrides fluent locale
|
|
3331
|
+
* @param locale - Optional locale for localized content (overrides the fluent locale, which
|
|
3332
|
+
* overrides the client's own)
|
|
2882
3333
|
* @param options - `If-Match` / `Idempotency-Key`, both declared on this route
|
|
2883
3334
|
*/
|
|
2884
3335
|
async update(data, locale, options) {
|
|
2885
|
-
const finalLocale =
|
|
3336
|
+
const finalLocale = this.localeOf(locale);
|
|
2886
3337
|
return this.httpClient.fetchPayload(
|
|
2887
3338
|
"/v1/singletons/{key}",
|
|
2888
3339
|
"patch",
|
|
@@ -2911,15 +3362,17 @@ var _SingletonClient = class _SingletonClient {
|
|
|
2911
3362
|
* Get version history for one locale of the singleton.
|
|
2912
3363
|
*
|
|
2913
3364
|
* Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
|
|
2914
|
-
*
|
|
2915
|
-
*
|
|
3365
|
+
* fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
|
|
3366
|
+
* fallback is applied, and a locale with no history returns an empty array rather than another
|
|
3367
|
+
* locale's rows. Every row names the locale it belongs to.
|
|
2916
3368
|
*/
|
|
2917
3369
|
async versions(options) {
|
|
3370
|
+
const locale = this.localeOf(options?.locale);
|
|
2918
3371
|
const payload = await this.httpClient.fetchPayload("/v1/singletons/{key}/versions", "get", {
|
|
2919
3372
|
path: { key: this.singletonKey },
|
|
2920
3373
|
query: {
|
|
2921
3374
|
limit: options?.limit ?? 10,
|
|
2922
|
-
...
|
|
3375
|
+
...locale === void 0 ? {} : { locale }
|
|
2923
3376
|
}
|
|
2924
3377
|
});
|
|
2925
3378
|
return payload.versions;
|
|
@@ -2927,20 +3380,25 @@ var _SingletonClient = class _SingletonClient {
|
|
|
2927
3380
|
/**
|
|
2928
3381
|
* Get a specific version of the singleton.
|
|
2929
3382
|
*
|
|
2930
|
-
* `locale` defaults to the
|
|
2931
|
-
* different content in each one.
|
|
3383
|
+
* `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
|
|
3384
|
+
* schema default. Version numbers are per locale, so version 2 is different content in each one.
|
|
2932
3385
|
*/
|
|
2933
3386
|
async version(versionNumber, options) {
|
|
3387
|
+
const locale = this.localeOf(options?.locale);
|
|
2934
3388
|
try {
|
|
2935
3389
|
return await this.httpClient.fetchPayload("/v1/singletons/{key}/versions/{versionNumber}", "get", {
|
|
2936
3390
|
path: { key: this.singletonKey, versionNumber: String(versionNumber) },
|
|
2937
|
-
query:
|
|
3391
|
+
query: locale === void 0 ? void 0 : { locale }
|
|
2938
3392
|
});
|
|
2939
3393
|
} catch (error) {
|
|
2940
3394
|
if (isResourceNotFound(error)) return null;
|
|
2941
3395
|
throw error;
|
|
2942
3396
|
}
|
|
2943
3397
|
}
|
|
3398
|
+
/** The locale a write or history read sends: the call's, the fluent one, else the client's. */
|
|
3399
|
+
localeOf(named) {
|
|
3400
|
+
return callLocale(named ?? this.localeValue, this.clientLocale());
|
|
3401
|
+
}
|
|
2944
3402
|
/**
|
|
2945
3403
|
* Get the singleton key
|
|
2946
3404
|
*/
|
|
@@ -2961,12 +3419,18 @@ var SingletonClient = _SingletonClient;
|
|
|
2961
3419
|
|
|
2962
3420
|
// src/content/settings-client.ts
|
|
2963
3421
|
var _SettingsClient = class _SettingsClient {
|
|
2964
|
-
|
|
3422
|
+
/**
|
|
3423
|
+
* @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
|
|
3424
|
+
* every call, or a locale fixed for this client
|
|
3425
|
+
*/
|
|
3426
|
+
constructor(httpClient, groupId, locale) {
|
|
2965
3427
|
this.httpClient = httpClient;
|
|
2966
3428
|
this.groupId = groupId;
|
|
2967
|
-
this.defaultLocale = defaultLocale;
|
|
2968
3429
|
chunkMWMSFIWN_cjs.__publicField(this, "includeFields");
|
|
2969
3430
|
chunkMWMSFIWN_cjs.__publicField(this, "localeValue");
|
|
3431
|
+
/** The client's locale, asked on every call rather than copied when this client was taken. */
|
|
3432
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3433
|
+
this.clientLocale = readClientLocale(locale);
|
|
2970
3434
|
}
|
|
2971
3435
|
/**
|
|
2972
3436
|
* Include reference fields in the response
|
|
@@ -2998,12 +3462,20 @@ var _SettingsClient = class _SettingsClient {
|
|
|
2998
3462
|
}
|
|
2999
3463
|
/**
|
|
3000
3464
|
* Update settings group
|
|
3465
|
+
*
|
|
3466
|
+
* The fields travel as `content` beside an optional `locale`, the body the route validates
|
|
3467
|
+
* (`UpdateSettingsDto`); any other top-level key is refused `REQUEST_INVALID`.
|
|
3468
|
+
*
|
|
3001
3469
|
* @param settings - The settings fields to update
|
|
3002
|
-
* @param locale - Optional locale for localized settings (overrides fluent locale
|
|
3470
|
+
* @param locale - Optional locale for localized settings (overrides the fluent locale, which
|
|
3471
|
+
* overrides the client's own)
|
|
3003
3472
|
*/
|
|
3004
3473
|
async update(settings, locale, options) {
|
|
3005
|
-
const finalLocale =
|
|
3006
|
-
const body =
|
|
3474
|
+
const finalLocale = this.localeOf(locale);
|
|
3475
|
+
const body = {
|
|
3476
|
+
content: settings,
|
|
3477
|
+
...finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : {}
|
|
3478
|
+
};
|
|
3007
3479
|
return this.httpClient.fetchPayload(
|
|
3008
3480
|
"/v1/settings/{groupId}",
|
|
3009
3481
|
"patch",
|
|
@@ -3018,7 +3490,7 @@ var _SettingsClient = class _SettingsClient {
|
|
|
3018
3490
|
async fetchWithTag(options) {
|
|
3019
3491
|
const query = {};
|
|
3020
3492
|
const includeValue = options?.include ?? this.includeFields;
|
|
3021
|
-
const localeValueFinal = options?.locale ?? this.localeValue ?? this.
|
|
3493
|
+
const localeValueFinal = options?.locale ?? this.localeValue ?? this.clientLocale();
|
|
3022
3494
|
if (includeValue) query.include = includeValue.join(",");
|
|
3023
3495
|
if (localeValueFinal != null && localeValueFinal !== "") query.locale = localeValueFinal;
|
|
3024
3496
|
const response = await this.httpClient.send(
|
|
@@ -3030,16 +3502,20 @@ var _SettingsClient = class _SettingsClient {
|
|
|
3030
3502
|
}
|
|
3031
3503
|
/**
|
|
3032
3504
|
* Reset settings to default values
|
|
3033
|
-
*
|
|
3505
|
+
*
|
|
3506
|
+
* The route reads its locale from `?locale=` and takes no body, so that is where it is sent.
|
|
3507
|
+
*
|
|
3508
|
+
* @param locale - Optional locale for localized settings (overrides the fluent locale, which
|
|
3509
|
+
* overrides the client's own)
|
|
3034
3510
|
*/
|
|
3035
3511
|
async reset(locale, options) {
|
|
3036
|
-
const finalLocale =
|
|
3512
|
+
const finalLocale = this.localeOf(locale);
|
|
3037
3513
|
return this.httpClient.fetchPayload(
|
|
3038
3514
|
"/v1/settings/{groupId}/reset",
|
|
3039
3515
|
"post",
|
|
3040
3516
|
{
|
|
3041
3517
|
path: { groupId: this.groupId },
|
|
3042
|
-
|
|
3518
|
+
query: finalLocale != null && finalLocale !== "" ? { locale: finalLocale } : void 0,
|
|
3043
3519
|
headers: writeHeaders(options)
|
|
3044
3520
|
}
|
|
3045
3521
|
);
|
|
@@ -3070,15 +3546,17 @@ var _SettingsClient = class _SettingsClient {
|
|
|
3070
3546
|
* Get version history for one locale of the settings group.
|
|
3071
3547
|
*
|
|
3072
3548
|
* Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
|
|
3073
|
-
*
|
|
3074
|
-
*
|
|
3549
|
+
* fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
|
|
3550
|
+
* fallback is applied, and a locale with no history returns an empty array rather than another
|
|
3551
|
+
* locale's rows. Every row names the locale it belongs to.
|
|
3075
3552
|
*/
|
|
3076
3553
|
async versions(options) {
|
|
3554
|
+
const locale = this.localeOf(options?.locale);
|
|
3077
3555
|
const payload = await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions", "get", {
|
|
3078
3556
|
path: { groupId: this.groupId },
|
|
3079
3557
|
query: {
|
|
3080
3558
|
limit: options?.limit ?? 10,
|
|
3081
|
-
...
|
|
3559
|
+
...locale === void 0 ? {} : { locale }
|
|
3082
3560
|
}
|
|
3083
3561
|
});
|
|
3084
3562
|
return payload.versions;
|
|
@@ -3086,20 +3564,25 @@ var _SettingsClient = class _SettingsClient {
|
|
|
3086
3564
|
/**
|
|
3087
3565
|
* Get a specific version of the settings.
|
|
3088
3566
|
*
|
|
3089
|
-
* `locale` defaults to the
|
|
3090
|
-
* different content in each one.
|
|
3567
|
+
* `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
|
|
3568
|
+
* schema default. Version numbers are per locale, so version 2 is different content in each one.
|
|
3091
3569
|
*/
|
|
3092
3570
|
async version(versionNumber, options) {
|
|
3571
|
+
const locale = this.localeOf(options?.locale);
|
|
3093
3572
|
try {
|
|
3094
3573
|
return await this.httpClient.fetchPayload("/v1/settings/{groupId}/versions/{versionNumber}", "get", {
|
|
3095
3574
|
path: { groupId: this.groupId, versionNumber: String(versionNumber) },
|
|
3096
|
-
query:
|
|
3575
|
+
query: locale === void 0 ? void 0 : { locale }
|
|
3097
3576
|
});
|
|
3098
3577
|
} catch (error) {
|
|
3099
3578
|
if (isResourceNotFound(error)) return null;
|
|
3100
3579
|
throw error;
|
|
3101
3580
|
}
|
|
3102
3581
|
}
|
|
3582
|
+
/** The locale a write or history read sends: the call's, the fluent one, else the client's. */
|
|
3583
|
+
localeOf(named) {
|
|
3584
|
+
return callLocale(named ?? this.localeValue, this.clientLocale());
|
|
3585
|
+
}
|
|
3103
3586
|
/**
|
|
3104
3587
|
* Get the settings group ID
|
|
3105
3588
|
*/
|
|
@@ -3121,15 +3604,19 @@ var SettingsClient = _SettingsClient;
|
|
|
3121
3604
|
// src/search/search-client.ts
|
|
3122
3605
|
var _SearchBuilder = class _SearchBuilder {
|
|
3123
3606
|
/**
|
|
3124
|
-
* @param
|
|
3607
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
|
|
3608
|
+
* `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
|
|
3125
3609
|
*/
|
|
3126
|
-
constructor(httpClient, query,
|
|
3610
|
+
constructor(httpClient, query, locale) {
|
|
3127
3611
|
this.httpClient = httpClient;
|
|
3128
|
-
this.defaultLocale = defaultLocale;
|
|
3129
3612
|
chunkMWMSFIWN_cjs.__publicField(this, "query");
|
|
3130
3613
|
chunkMWMSFIWN_cjs.__publicField(this, "searchOptions", {});
|
|
3131
3614
|
chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
|
|
3615
|
+
chunkMWMSFIWN_cjs.__publicField(this, "freshValue");
|
|
3616
|
+
/** The client's locale, asked when the query is sent rather than copied when it was built. */
|
|
3617
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3132
3618
|
this.query = query;
|
|
3619
|
+
this.clientLocale = readClientLocale(locale);
|
|
3133
3620
|
}
|
|
3134
3621
|
/**
|
|
3135
3622
|
* Headers this search adds to the client's own, e.g. `X-RelyIO-Dataset` to search another
|
|
@@ -3139,6 +3626,15 @@ var _SearchBuilder = class _SearchBuilder {
|
|
|
3139
3626
|
this.requestHeaders = headers;
|
|
3140
3627
|
return this;
|
|
3141
3628
|
}
|
|
3629
|
+
/**
|
|
3630
|
+
* The feed position this search follows — a change's `fresh` (`FeedChange`), or a resync's. Sent
|
|
3631
|
+
* as `?_fresh` on the query string beside the body: the edge keys a search on both, so no answer
|
|
3632
|
+
* it holds from before that position can answer it. The answer is the search's own.
|
|
3633
|
+
*/
|
|
3634
|
+
fresh(position) {
|
|
3635
|
+
this.freshValue = position;
|
|
3636
|
+
return this;
|
|
3637
|
+
}
|
|
3142
3638
|
/**
|
|
3143
3639
|
* Search within a single content type. Where a schema types the client, the name is one of its
|
|
3144
3640
|
* content types and the results are that type's entries.
|
|
@@ -3160,10 +3656,12 @@ var _SearchBuilder = class _SearchBuilder {
|
|
|
3160
3656
|
return this;
|
|
3161
3657
|
}
|
|
3162
3658
|
/**
|
|
3163
|
-
* Add filter conditions
|
|
3659
|
+
* Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
|
|
3660
|
+
* refused here, before anything is sent.
|
|
3164
3661
|
* @param conditions - Filter conditions
|
|
3165
3662
|
*/
|
|
3166
3663
|
where(conditions) {
|
|
3664
|
+
refuseMetadataConditions(conditions);
|
|
3167
3665
|
this.searchOptions.where = {
|
|
3168
3666
|
...this.searchOptions.where,
|
|
3169
3667
|
...conditions
|
|
@@ -3271,14 +3769,18 @@ var _SearchBuilder = class _SearchBuilder {
|
|
|
3271
3769
|
if (this.searchOptions.explain === true) {
|
|
3272
3770
|
body.explain = true;
|
|
3273
3771
|
}
|
|
3274
|
-
const locale = this.searchOptions.locale ?? this.
|
|
3772
|
+
const locale = this.searchOptions.locale ?? this.clientLocale();
|
|
3275
3773
|
if (locale != null && locale !== "") {
|
|
3276
3774
|
body.locale = locale;
|
|
3277
3775
|
}
|
|
3278
3776
|
const response = await this.httpClient.send(
|
|
3279
3777
|
"/v1/search",
|
|
3280
3778
|
"post",
|
|
3281
|
-
{
|
|
3779
|
+
{
|
|
3780
|
+
body,
|
|
3781
|
+
headers: this.requestHeaders,
|
|
3782
|
+
...this.freshValue === void 0 ? {} : { query: { [FRESH_PARAMETER]: this.freshValue } }
|
|
3783
|
+
}
|
|
3282
3784
|
);
|
|
3283
3785
|
return response.body;
|
|
3284
3786
|
}
|
|
@@ -3299,14 +3801,17 @@ chunkMWMSFIWN_cjs.__name(_SearchBuilder, "SearchBuilder");
|
|
|
3299
3801
|
var SearchBuilder = _SearchBuilder;
|
|
3300
3802
|
var _AutocompleteBuilder = class _AutocompleteBuilder {
|
|
3301
3803
|
/**
|
|
3302
|
-
* @param
|
|
3804
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
|
|
3805
|
+
* `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
|
|
3303
3806
|
*/
|
|
3304
|
-
constructor(httpClient, query,
|
|
3807
|
+
constructor(httpClient, query, locale) {
|
|
3305
3808
|
this.httpClient = httpClient;
|
|
3306
|
-
this.defaultLocale = defaultLocale;
|
|
3307
3809
|
chunkMWMSFIWN_cjs.__publicField(this, "query");
|
|
3308
3810
|
chunkMWMSFIWN_cjs.__publicField(this, "autocompleteOptions", {});
|
|
3811
|
+
/** The client's locale, asked when the query is sent rather than copied when it was built. */
|
|
3812
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3309
3813
|
this.query = query;
|
|
3814
|
+
this.clientLocale = readClientLocale(locale);
|
|
3310
3815
|
}
|
|
3311
3816
|
/**
|
|
3312
3817
|
* Autocomplete within a content type
|
|
@@ -3332,10 +3837,12 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
|
|
|
3332
3837
|
return this;
|
|
3333
3838
|
}
|
|
3334
3839
|
/**
|
|
3335
|
-
* Add filter conditions
|
|
3840
|
+
* Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
|
|
3841
|
+
* refused here, before anything is sent.
|
|
3336
3842
|
* @param conditions - Filter conditions
|
|
3337
3843
|
*/
|
|
3338
3844
|
where(conditions) {
|
|
3845
|
+
refuseMetadataConditions(conditions);
|
|
3339
3846
|
this.autocompleteOptions.where = {
|
|
3340
3847
|
...this.autocompleteOptions.where,
|
|
3341
3848
|
...conditions
|
|
@@ -3382,7 +3889,7 @@ var _AutocompleteBuilder = class _AutocompleteBuilder {
|
|
|
3382
3889
|
if (this.autocompleteOptions.limit !== void 0) {
|
|
3383
3890
|
body.limit = this.autocompleteOptions.limit;
|
|
3384
3891
|
}
|
|
3385
|
-
const locale = this.autocompleteOptions.locale ?? this.
|
|
3892
|
+
const locale = this.autocompleteOptions.locale ?? this.clientLocale();
|
|
3386
3893
|
if (locale != null && locale !== "") {
|
|
3387
3894
|
body.locale = locale;
|
|
3388
3895
|
}
|
|
@@ -3400,15 +3907,18 @@ chunkMWMSFIWN_cjs.__name(_AutocompleteBuilder, "AutocompleteBuilder");
|
|
|
3400
3907
|
var AutocompleteBuilder = _AutocompleteBuilder;
|
|
3401
3908
|
var _SimilarBuilder = class _SimilarBuilder {
|
|
3402
3909
|
/**
|
|
3403
|
-
* @param
|
|
3910
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
|
|
3911
|
+
* `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
|
|
3404
3912
|
*/
|
|
3405
|
-
constructor(httpClient, sourceId,
|
|
3913
|
+
constructor(httpClient, sourceId, locale) {
|
|
3406
3914
|
this.httpClient = httpClient;
|
|
3407
|
-
this.defaultLocale = defaultLocale;
|
|
3408
3915
|
chunkMWMSFIWN_cjs.__publicField(this, "sourceId");
|
|
3409
3916
|
chunkMWMSFIWN_cjs.__publicField(this, "similarOptions", {});
|
|
3410
3917
|
chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
|
|
3918
|
+
/** The client's locale, asked when the read is sent rather than copied when it was built. */
|
|
3919
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
3411
3920
|
this.sourceId = sourceId;
|
|
3921
|
+
this.clientLocale = readClientLocale(locale);
|
|
3412
3922
|
}
|
|
3413
3923
|
/**
|
|
3414
3924
|
* Headers this read adds to the client's own, e.g. `X-RelyIO-Dataset` to read another dataset
|
|
@@ -3436,17 +3946,12 @@ var _SimilarBuilder = class _SimilarBuilder {
|
|
|
3436
3946
|
this.similarOptions.contentType = void 0;
|
|
3437
3947
|
return this;
|
|
3438
3948
|
}
|
|
3439
|
-
|
|
3440
|
-
*
|
|
3441
|
-
*
|
|
3949
|
+
/*
|
|
3950
|
+
* No `where()` (REL-1452). Similar ranks from the source entry's stored vector, and the vector
|
|
3951
|
+
* index can pre-filter by content type and locale only — never by an entry field. The API used to
|
|
3952
|
+
* accept `where` here and apply nothing; it now refuses the property, so the builder does not
|
|
3953
|
+
* offer a filter that cannot be honoured. Narrow with `.in()`, `.across()` and `.locale()`.
|
|
3442
3954
|
*/
|
|
3443
|
-
where(conditions) {
|
|
3444
|
-
this.similarOptions.where = {
|
|
3445
|
-
...this.similarOptions.where,
|
|
3446
|
-
...conditions
|
|
3447
|
-
};
|
|
3448
|
-
return this;
|
|
3449
|
-
}
|
|
3450
3955
|
/**
|
|
3451
3956
|
* Limit number of results
|
|
3452
3957
|
* @param count - Maximum results
|
|
@@ -3480,13 +3985,10 @@ var _SimilarBuilder = class _SimilarBuilder {
|
|
|
3480
3985
|
if (contentTypes != null) {
|
|
3481
3986
|
body.contentTypes = contentTypes;
|
|
3482
3987
|
}
|
|
3483
|
-
if (this.similarOptions.where && Object.keys(this.similarOptions.where).length > 0) {
|
|
3484
|
-
body.where = this.similarOptions.where;
|
|
3485
|
-
}
|
|
3486
3988
|
if (this.similarOptions.limit !== void 0) {
|
|
3487
3989
|
body.limit = this.similarOptions.limit;
|
|
3488
3990
|
}
|
|
3489
|
-
const locale = this.similarOptions.locale ?? this.
|
|
3991
|
+
const locale = this.similarOptions.locale ?? this.clientLocale();
|
|
3490
3992
|
if (locale != null && locale !== "") {
|
|
3491
3993
|
body.locale = locale;
|
|
3492
3994
|
}
|
|
@@ -3514,41 +4016,36 @@ chunkMWMSFIWN_cjs.__name(_SimilarBuilder, "SimilarBuilder");
|
|
|
3514
4016
|
var SimilarBuilder = _SimilarBuilder;
|
|
3515
4017
|
var _SearchClient = class _SearchClient {
|
|
3516
4018
|
/**
|
|
3517
|
-
* @param
|
|
3518
|
-
* the query names none, as `content()`'s reads do
|
|
4019
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`): every builder
|
|
4020
|
+
* here sends it when the query names none, as `content()`'s reads do — the function
|
|
4021
|
+
* `TypedRelyIOClient` hands over, or a locale fixed for this client
|
|
3519
4022
|
*/
|
|
3520
|
-
constructor(httpClient,
|
|
4023
|
+
constructor(httpClient, locale) {
|
|
3521
4024
|
this.httpClient = httpClient;
|
|
3522
|
-
|
|
4025
|
+
/** The client's locale, handed to every builder here to ask when it sends. */
|
|
4026
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
4027
|
+
this.clientLocale = readClientLocale(locale);
|
|
3523
4028
|
}
|
|
3524
4029
|
/**
|
|
3525
4030
|
* Start a search query
|
|
3526
4031
|
* @param query - Search query string
|
|
3527
4032
|
*/
|
|
3528
4033
|
search(query) {
|
|
3529
|
-
return new SearchBuilder(this.httpClient, query, this.
|
|
4034
|
+
return new SearchBuilder(this.httpClient, query, this.clientLocale);
|
|
3530
4035
|
}
|
|
3531
4036
|
/**
|
|
3532
4037
|
* Start an autocomplete query
|
|
3533
4038
|
* @param query - Partial query to autocomplete
|
|
3534
4039
|
*/
|
|
3535
4040
|
autocomplete(query) {
|
|
3536
|
-
return new AutocompleteBuilder(this.httpClient, query, this.
|
|
4041
|
+
return new AutocompleteBuilder(this.httpClient, query, this.clientLocale);
|
|
3537
4042
|
}
|
|
3538
4043
|
/**
|
|
3539
4044
|
* Find content similar to a given entry
|
|
3540
4045
|
* @param sourceId - Entry ID to find similar content for
|
|
3541
4046
|
*/
|
|
3542
4047
|
similar(sourceId) {
|
|
3543
|
-
return new SimilarBuilder(this.httpClient, sourceId, this.
|
|
3544
|
-
}
|
|
3545
|
-
/**
|
|
3546
|
-
* Quick search helper - searches all content types
|
|
3547
|
-
* @param query - Search query
|
|
3548
|
-
* @param limit - Max results (default 20)
|
|
3549
|
-
*/
|
|
3550
|
-
async global(query, limit = 20) {
|
|
3551
|
-
return this.search(query).across("*").limit(limit).execute();
|
|
4048
|
+
return new SimilarBuilder(this.httpClient, sourceId, this.clientLocale);
|
|
3552
4049
|
}
|
|
3553
4050
|
};
|
|
3554
4051
|
chunkMWMSFIWN_cjs.__name(_SearchClient, "SearchClient");
|
|
@@ -3556,7 +4053,12 @@ var SearchClient = _SearchClient;
|
|
|
3556
4053
|
|
|
3557
4054
|
// src/batch/batch-client.ts
|
|
3558
4055
|
var _BatchBuilder = class _BatchBuilder {
|
|
3559
|
-
|
|
4056
|
+
/**
|
|
4057
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), each
|
|
4058
|
+
* operation's when it names none: the function `TypedRelyIOClient` hands over, or a locale fixed
|
|
4059
|
+
* for this batch
|
|
4060
|
+
*/
|
|
4061
|
+
constructor(httpClient, locale) {
|
|
3560
4062
|
this.httpClient = httpClient;
|
|
3561
4063
|
chunkMWMSFIWN_cjs.__publicField(this, "operations", []);
|
|
3562
4064
|
chunkMWMSFIWN_cjs.__publicField(this, "defaultOptions", {
|
|
@@ -3566,6 +4068,17 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3566
4068
|
continueOnError: true
|
|
3567
4069
|
});
|
|
3568
4070
|
chunkMWMSFIWN_cjs.__publicField(this, "requestHeaders");
|
|
4071
|
+
/** The client's locale, asked as each operation is added rather than copied when this was built. */
|
|
4072
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
4073
|
+
this.clientLocale = readClientLocale(locale);
|
|
4074
|
+
}
|
|
4075
|
+
/**
|
|
4076
|
+
* An operation's body with its locale: the one it names, else the client's as it is when the
|
|
4077
|
+
* operation is added.
|
|
4078
|
+
*/
|
|
4079
|
+
localized(data) {
|
|
4080
|
+
const locale = callLocale(data.locale, this.clientLocale());
|
|
4081
|
+
return locale === void 0 ? data : { ...data, locale };
|
|
3569
4082
|
}
|
|
3570
4083
|
// ==========================================================================
|
|
3571
4084
|
// ENTRY OPERATIONS
|
|
@@ -3581,7 +4094,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3581
4094
|
id,
|
|
3582
4095
|
method: "POST",
|
|
3583
4096
|
path: `/${contentType}`,
|
|
3584
|
-
body: data
|
|
4097
|
+
body: this.localized(data)
|
|
3585
4098
|
});
|
|
3586
4099
|
return this;
|
|
3587
4100
|
}
|
|
@@ -3601,7 +4114,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3601
4114
|
id,
|
|
3602
4115
|
method: "PATCH",
|
|
3603
4116
|
path: `/${contentType}/${entryId}`,
|
|
3604
|
-
body: data
|
|
4117
|
+
body: this.localized(data)
|
|
3605
4118
|
});
|
|
3606
4119
|
return this;
|
|
3607
4120
|
}
|
|
@@ -3621,7 +4134,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3621
4134
|
id,
|
|
3622
4135
|
method: "PUT",
|
|
3623
4136
|
path: `/${contentType}/${entryId}`,
|
|
3624
|
-
body: data
|
|
4137
|
+
body: this.localized(data)
|
|
3625
4138
|
});
|
|
3626
4139
|
return this;
|
|
3627
4140
|
}
|
|
@@ -3653,7 +4166,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3653
4166
|
id,
|
|
3654
4167
|
method: "PATCH",
|
|
3655
4168
|
path: `/_singletons/${singletonKey}`,
|
|
3656
|
-
body: data
|
|
4169
|
+
body: this.localized(data)
|
|
3657
4170
|
});
|
|
3658
4171
|
return this;
|
|
3659
4172
|
}
|
|
@@ -3668,7 +4181,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3668
4181
|
id,
|
|
3669
4182
|
method: "POST",
|
|
3670
4183
|
path: `/_singletons/${singletonKey}`,
|
|
3671
|
-
body: data
|
|
4184
|
+
body: this.localized(data)
|
|
3672
4185
|
});
|
|
3673
4186
|
return this;
|
|
3674
4187
|
}
|
|
@@ -3676,7 +4189,8 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3676
4189
|
// RAW OPERATIONS
|
|
3677
4190
|
// ==========================================================================
|
|
3678
4191
|
/**
|
|
3679
|
-
* Add a raw operation (for advanced use cases)
|
|
4192
|
+
* Add a raw operation (for advanced use cases). It is sent exactly as written: the client's
|
|
4193
|
+
* locale is not added to it.
|
|
3680
4194
|
* @param operation - The operation to add
|
|
3681
4195
|
*/
|
|
3682
4196
|
raw(operation) {
|
|
@@ -3802,7 +4316,7 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3802
4316
|
* Clone the builder
|
|
3803
4317
|
*/
|
|
3804
4318
|
clone() {
|
|
3805
|
-
const cloned = new _BatchBuilder(this.httpClient);
|
|
4319
|
+
const cloned = new _BatchBuilder(this.httpClient, this.clientLocale);
|
|
3806
4320
|
cloned.operations = [...this.operations];
|
|
3807
4321
|
cloned.defaultOptions = { ...this.defaultOptions };
|
|
3808
4322
|
cloned.requestHeaders = this.requestHeaders === void 0 ? void 0 : { ...this.requestHeaders };
|
|
@@ -3855,14 +4369,21 @@ var _BatchBuilder = class _BatchBuilder {
|
|
|
3855
4369
|
chunkMWMSFIWN_cjs.__name(_BatchBuilder, "BatchBuilder");
|
|
3856
4370
|
var BatchBuilder = _BatchBuilder;
|
|
3857
4371
|
var _BatchClient = class _BatchClient {
|
|
3858
|
-
|
|
4372
|
+
/**
|
|
4373
|
+
* @param locale - The client's locale: the function `TypedRelyIOClient` hands over, or a locale
|
|
4374
|
+
* fixed for this client
|
|
4375
|
+
*/
|
|
4376
|
+
constructor(httpClient, locale) {
|
|
3859
4377
|
this.httpClient = httpClient;
|
|
4378
|
+
/** The client's locale, handed to every batch this builds to ask as operations are added. */
|
|
4379
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
4380
|
+
this.clientLocale = readClientLocale(locale);
|
|
3860
4381
|
}
|
|
3861
4382
|
/**
|
|
3862
|
-
* Create a new batch builder
|
|
4383
|
+
* Create a new batch builder, whose operations default to this client's locale
|
|
3863
4384
|
*/
|
|
3864
4385
|
create() {
|
|
3865
|
-
return new BatchBuilder(this.httpClient);
|
|
4386
|
+
return new BatchBuilder(this.httpClient, this.clientLocale);
|
|
3866
4387
|
}
|
|
3867
4388
|
/**
|
|
3868
4389
|
* Quick bulk create entries
|
|
@@ -3913,15 +4434,18 @@ function withClientLocale(parameters, clientLocale) {
|
|
|
3913
4434
|
chunkMWMSFIWN_cjs.__name(withClientLocale, "withClientLocale");
|
|
3914
4435
|
var _AdhocQueryBuilder = class _AdhocQueryBuilder {
|
|
3915
4436
|
/**
|
|
3916
|
-
* @param
|
|
3917
|
-
* when `.param('locale', …)` binds none
|
|
4437
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
|
|
4438
|
+
* `locale` parameter when `.param('locale', …)` binds none: the function `TypedRelyIOClient`
|
|
4439
|
+
* hands over, or a locale fixed for this builder
|
|
3918
4440
|
*/
|
|
3919
|
-
constructor(httpClient,
|
|
4441
|
+
constructor(httpClient, locale) {
|
|
3920
4442
|
this.httpClient = httpClient;
|
|
3921
|
-
this.defaultLocale = defaultLocale;
|
|
3922
4443
|
chunkMWMSFIWN_cjs.__publicField(this, "queryDef", {});
|
|
3923
4444
|
chunkMWMSFIWN_cjs.__publicField(this, "parameters", {});
|
|
3924
4445
|
chunkMWMSFIWN_cjs.__publicField(this, "options", {});
|
|
4446
|
+
/** The client's locale, asked when the query is sent rather than copied when it was built. */
|
|
4447
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
4448
|
+
this.clientLocale = readClientLocale(locale);
|
|
3925
4449
|
}
|
|
3926
4450
|
// ==========================================================================
|
|
3927
4451
|
// QUERY BLOCKS
|
|
@@ -3966,14 +4490,6 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
|
|
|
3966
4490
|
this.queryDef.search = config;
|
|
3967
4491
|
return this;
|
|
3968
4492
|
}
|
|
3969
|
-
/**
|
|
3970
|
-
* Add similar block
|
|
3971
|
-
* @param config - Similar configuration
|
|
3972
|
-
*/
|
|
3973
|
-
similar(config) {
|
|
3974
|
-
this.queryDef.similar = config;
|
|
3975
|
-
return this;
|
|
3976
|
-
}
|
|
3977
4493
|
// ==========================================================================
|
|
3978
4494
|
// FETCH MODIFIERS
|
|
3979
4495
|
// ==========================================================================
|
|
@@ -4150,15 +4666,15 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
|
|
|
4150
4666
|
* Execute the query
|
|
4151
4667
|
*/
|
|
4152
4668
|
async execute() {
|
|
4153
|
-
if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search
|
|
4669
|
+
if (!this.queryDef.fetch && !this.queryDef.aggregate && !this.queryDef.search) {
|
|
4154
4670
|
throw new Error(
|
|
4155
|
-
"Query must have at least one of: fetch, aggregate
|
|
4671
|
+
"Query must have at least one of: fetch, aggregate or search. Use .from(), .aggregate() or .search()"
|
|
4156
4672
|
);
|
|
4157
4673
|
}
|
|
4158
4674
|
const body = {
|
|
4159
4675
|
query: this.queryDef
|
|
4160
4676
|
};
|
|
4161
|
-
const parameters = withClientLocale(this.parameters, this.
|
|
4677
|
+
const parameters = withClientLocale(this.parameters, this.clientLocale());
|
|
4162
4678
|
if (parameters !== void 0 && Object.keys(parameters).length > 0) {
|
|
4163
4679
|
body.parameters = parameters;
|
|
4164
4680
|
}
|
|
@@ -4191,7 +4707,7 @@ var _AdhocQueryBuilder = class _AdhocQueryBuilder {
|
|
|
4191
4707
|
* Clone the builder
|
|
4192
4708
|
*/
|
|
4193
4709
|
clone() {
|
|
4194
|
-
const cloned = new _AdhocQueryBuilder(this.httpClient, this.
|
|
4710
|
+
const cloned = new _AdhocQueryBuilder(this.httpClient, this.clientLocale);
|
|
4195
4711
|
cloned.queryDef = JSON.parse(JSON.stringify(this.queryDef));
|
|
4196
4712
|
cloned.parameters = { ...this.parameters };
|
|
4197
4713
|
cloned.options = { ...this.options };
|
|
@@ -4202,18 +4718,21 @@ chunkMWMSFIWN_cjs.__name(_AdhocQueryBuilder, "AdhocQueryBuilder");
|
|
|
4202
4718
|
var AdhocQueryBuilder = _AdhocQueryBuilder;
|
|
4203
4719
|
var _AdhocQueryClient = class _AdhocQueryClient {
|
|
4204
4720
|
/**
|
|
4205
|
-
* @param
|
|
4206
|
-
* every query that binds none
|
|
4721
|
+
* @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
|
|
4722
|
+
* `locale` parameter of every query that binds none: the function `TypedRelyIOClient` hands
|
|
4723
|
+
* over, or a locale fixed for this client
|
|
4207
4724
|
*/
|
|
4208
|
-
constructor(httpClient,
|
|
4725
|
+
constructor(httpClient, locale) {
|
|
4209
4726
|
this.httpClient = httpClient;
|
|
4210
|
-
this.
|
|
4727
|
+
/** The client's locale, asked on every query rather than copied when this client was taken. */
|
|
4728
|
+
chunkMWMSFIWN_cjs.__publicField(this, "clientLocale");
|
|
4729
|
+
this.clientLocale = readClientLocale(locale);
|
|
4211
4730
|
}
|
|
4212
4731
|
/**
|
|
4213
4732
|
* Create a new query builder
|
|
4214
4733
|
*/
|
|
4215
4734
|
build() {
|
|
4216
|
-
return new AdhocQueryBuilder(this.httpClient, this.
|
|
4735
|
+
return new AdhocQueryBuilder(this.httpClient, this.clientLocale);
|
|
4217
4736
|
}
|
|
4218
4737
|
/**
|
|
4219
4738
|
* Execute a query definition directly
|
|
@@ -4228,7 +4747,7 @@ var _AdhocQueryClient = class _AdhocQueryClient {
|
|
|
4228
4747
|
const body = {
|
|
4229
4748
|
query: definition
|
|
4230
4749
|
};
|
|
4231
|
-
const sent = withClientLocale(parameters, this.
|
|
4750
|
+
const sent = withClientLocale(parameters, this.clientLocale());
|
|
4232
4751
|
if (sent !== void 0 && Object.keys(sent).length > 0) {
|
|
4233
4752
|
body.parameters = sent;
|
|
4234
4753
|
}
|
|
@@ -4277,23 +4796,67 @@ var AdhocQueryClient = _AdhocQueryClient;
|
|
|
4277
4796
|
|
|
4278
4797
|
// src/changes/changes.ts
|
|
4279
4798
|
var CHANGES_POLL_TIMEOUT_MS = 25e3 + 5e3;
|
|
4799
|
+
var EXPIRED_REASONS = {
|
|
4800
|
+
retention: "retention",
|
|
4801
|
+
"dataset-replaced": "dataset-replaced",
|
|
4802
|
+
"ahead-of-head": "ahead-of-head",
|
|
4803
|
+
"foreign-cursor": "foreign-cursor",
|
|
4804
|
+
"too-far-behind": "too-far-behind"
|
|
4805
|
+
};
|
|
4280
4806
|
var _ChangesExpiredError = class _ChangesExpiredError extends ResourceExpiredError {
|
|
4281
|
-
/** The base class's signature, so `withContext` can rebuild one. */
|
|
4282
|
-
constructor(message, statusCode = 410, cause, context) {
|
|
4807
|
+
/** The base class's signature, so `withContext` can rebuild one; then the position resynced to. */
|
|
4808
|
+
constructor(message, statusCode = 410, cause, context, fresh) {
|
|
4283
4809
|
super(message, statusCode, cause, context);
|
|
4284
4810
|
chunkMWMSFIWN_cjs.__publicField(this, "reason");
|
|
4811
|
+
/**
|
|
4812
|
+
* The position the feed resynced to, which a refetch of everything names as `?_fresh`, as a
|
|
4813
|
+
* change's {@link FeedChange.fresh} is named: the head a `/v1/changes` resync took, or the cursor
|
|
4814
|
+
* the edge's `feed.resync` sent. `undefined` when there was no resync to take one — the error was
|
|
4815
|
+
* thrown (`onExpired: 'throw'`) — and on an error a caller built itself.
|
|
4816
|
+
*/
|
|
4817
|
+
chunkMWMSFIWN_cjs.__publicField(this, "fresh");
|
|
4285
4818
|
this.name = "ChangesExpiredError";
|
|
4286
4819
|
this.reason = expiredReasonOf(message);
|
|
4820
|
+
this.fresh = fresh;
|
|
4821
|
+
}
|
|
4822
|
+
/** The base class rebuilds from its four arguments, which would drop the position resynced to. */
|
|
4823
|
+
withContext(context) {
|
|
4824
|
+
const Constructor = this.constructor;
|
|
4825
|
+
return new Constructor(
|
|
4826
|
+
this.message,
|
|
4827
|
+
this.statusCode,
|
|
4828
|
+
this.cause,
|
|
4829
|
+
{ ...this.context, ...context },
|
|
4830
|
+
this.fresh
|
|
4831
|
+
);
|
|
4832
|
+
}
|
|
4833
|
+
/** `/v1/changes`' refusal, with the head the feed resynced to when it did. */
|
|
4834
|
+
static of(expired, fresh) {
|
|
4835
|
+
return new _ChangesExpiredError(
|
|
4836
|
+
expired.message,
|
|
4837
|
+
expired.statusCode,
|
|
4838
|
+
expired,
|
|
4839
|
+
expired.context,
|
|
4840
|
+
fresh
|
|
4841
|
+
);
|
|
4287
4842
|
}
|
|
4288
|
-
|
|
4289
|
-
|
|
4843
|
+
/** The live edge's `feed.resync`: refetch everything, then continue from the cursor it sent. */
|
|
4844
|
+
static resync(reason, cursor) {
|
|
4845
|
+
return new _ChangesExpiredError(
|
|
4846
|
+
`The live edge cannot list the changes since this cursor (${reason}). Refetch everything derived from the feed; it continues from the position it sent.`,
|
|
4847
|
+
410,
|
|
4848
|
+
void 0,
|
|
4849
|
+
{ transport: "live-edge" },
|
|
4850
|
+
cursor
|
|
4851
|
+
);
|
|
4290
4852
|
}
|
|
4291
4853
|
};
|
|
4292
4854
|
chunkMWMSFIWN_cjs.__name(_ChangesExpiredError, "ChangesExpiredError");
|
|
4293
4855
|
var ChangesExpiredError = _ChangesExpiredError;
|
|
4294
4856
|
function expiredReasonOf(message) {
|
|
4295
|
-
|
|
4296
|
-
|
|
4857
|
+
for (const reason of Object.values(EXPIRED_REASONS)) {
|
|
4858
|
+
if (message.includes(`(${reason})`)) return reason;
|
|
4859
|
+
}
|
|
4297
4860
|
return "unknown";
|
|
4298
4861
|
}
|
|
4299
4862
|
chunkMWMSFIWN_cjs.__name(expiredReasonOf, "expiredReasonOf");
|
|
@@ -4313,7 +4876,7 @@ async function* pollChanges(http, options = {}) {
|
|
|
4313
4876
|
const onExpired = options.onExpired ?? "throw";
|
|
4314
4877
|
if (onExpired === "throw") throw expired;
|
|
4315
4878
|
since = void 0;
|
|
4316
|
-
resynced = typeof onExpired === "function" ?
|
|
4879
|
+
resynced = typeof onExpired === "function" ? error : void 0;
|
|
4317
4880
|
continue;
|
|
4318
4881
|
}
|
|
4319
4882
|
const { data, page } = response.body;
|
|
@@ -4322,13 +4885,13 @@ async function* pollChanges(http, options = {}) {
|
|
|
4322
4885
|
}
|
|
4323
4886
|
since = page.nextCursor;
|
|
4324
4887
|
if (resynced !== void 0 && typeof options.onExpired === "function") {
|
|
4325
|
-
const expired = resynced;
|
|
4888
|
+
const expired = ChangesExpiredError.of(resynced, page.nextCursor);
|
|
4326
4889
|
resynced = void 0;
|
|
4327
4890
|
await options.onExpired(expired);
|
|
4328
4891
|
if (isAborted(signal)) return;
|
|
4329
4892
|
}
|
|
4330
4893
|
for (const change of data) {
|
|
4331
|
-
yield change;
|
|
4894
|
+
yield { ...change, fresh: change.cursor };
|
|
4332
4895
|
if (isAborted(signal)) return;
|
|
4333
4896
|
}
|
|
4334
4897
|
if (data.length === 0) {
|
|
@@ -4367,6 +4930,477 @@ async function pollOnce(http, since, options) {
|
|
|
4367
4930
|
}
|
|
4368
4931
|
chunkMWMSFIWN_cjs.__name(pollOnce, "pollOnce");
|
|
4369
4932
|
|
|
4933
|
+
// src/config/key-kind.ts
|
|
4934
|
+
var PUBLISHABLE_KEY_PREFIX = "rly_pub_";
|
|
4935
|
+
var isPublishableKey = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name((apiKey) => apiKey?.startsWith(PUBLISHABLE_KEY_PREFIX) === true, "isPublishableKey");
|
|
4936
|
+
|
|
4937
|
+
// src/errors/live-errors.ts
|
|
4938
|
+
var _LiveEdgeError = class _LiveEdgeError extends SDKError {
|
|
4939
|
+
constructor(message, end, retry, options = {}) {
|
|
4940
|
+
super(message, options.statusCode, options.cause, options.context);
|
|
4941
|
+
chunkMWMSFIWN_cjs.__publicField(this, "code", "LIVE_EDGE_ENDED");
|
|
4942
|
+
chunkMWMSFIWN_cjs.__publicField(this, "retryable");
|
|
4943
|
+
chunkMWMSFIWN_cjs.__publicField(this, "end");
|
|
4944
|
+
chunkMWMSFIWN_cjs.__publicField(this, "retry");
|
|
4945
|
+
/** A refused poll's `Retry-After`, in milliseconds, where it carried a readable one. */
|
|
4946
|
+
chunkMWMSFIWN_cjs.__publicField(this, "retryAfterMs");
|
|
4947
|
+
this.end = end;
|
|
4948
|
+
this.retry = retry;
|
|
4949
|
+
this.retryable = retry !== "stop";
|
|
4950
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
4951
|
+
}
|
|
4952
|
+
/**
|
|
4953
|
+
* The base class rebuilds an error through its own four-argument constructor, which this class
|
|
4954
|
+
* does not have; rebuilt that way, `end` would be a string and `retry` a number.
|
|
4955
|
+
*/
|
|
4956
|
+
withContext(context) {
|
|
4957
|
+
const rebuilt = new _LiveEdgeError(this.message, this.end, this.retry, {
|
|
4958
|
+
...this.statusCode === void 0 ? {} : { statusCode: this.statusCode },
|
|
4959
|
+
...this.cause === void 0 ? {} : { cause: this.cause },
|
|
4960
|
+
...this.retryAfterMs === void 0 ? {} : { retryAfterMs: this.retryAfterMs },
|
|
4961
|
+
context: { ...this.context, ...context }
|
|
4962
|
+
});
|
|
4963
|
+
return rebuilt;
|
|
4964
|
+
}
|
|
4965
|
+
getUserMessage() {
|
|
4966
|
+
return this.message;
|
|
4967
|
+
}
|
|
4968
|
+
};
|
|
4969
|
+
chunkMWMSFIWN_cjs.__name(_LiveEdgeError, "LiveEdgeError");
|
|
4970
|
+
var LiveEdgeError = _LiveEdgeError;
|
|
4971
|
+
|
|
4972
|
+
// src/config/live-url.ts
|
|
4973
|
+
var LIVE_EDGE_OF_API = {
|
|
4974
|
+
"https://api.relyio.com": "https://live.relyio.com"
|
|
4975
|
+
};
|
|
4976
|
+
var HTTP_SCHEME_OF = {
|
|
4977
|
+
"http:": "http:",
|
|
4978
|
+
"https:": "https:",
|
|
4979
|
+
"ws:": "http:",
|
|
4980
|
+
"wss:": "https:"
|
|
4981
|
+
};
|
|
4982
|
+
function liveEdgeAddress(config) {
|
|
4983
|
+
if (config.liveUrl !== void 0) return readLiveUrl(config.liveUrl);
|
|
4984
|
+
const derived = originOf(config.baseUrl);
|
|
4985
|
+
const edge = derived === void 0 ? void 0 : LIVE_EDGE_OF_API[derived];
|
|
4986
|
+
if (edge !== void 0) return { ok: true, url: new URL(edge) };
|
|
4987
|
+
return {
|
|
4988
|
+
ok: false,
|
|
4989
|
+
message: `Live updates need the address of RelyIO\u2019s live edge, and this client cannot derive it: \`baseUrl\` is not RelyIO\u2019s API (${Object.keys(LIVE_EDGE_OF_API).join(", ")}). Set \`liveUrl\` in createClient() to the live edge this API belongs with. Nothing was sent.`
|
|
4990
|
+
};
|
|
4991
|
+
}
|
|
4992
|
+
chunkMWMSFIWN_cjs.__name(liveEdgeAddress, "liveEdgeAddress");
|
|
4993
|
+
function readLiveUrl(liveUrl) {
|
|
4994
|
+
let url;
|
|
4995
|
+
try {
|
|
4996
|
+
url = new URL(liveUrl);
|
|
4997
|
+
} catch {
|
|
4998
|
+
return { ok: false, message: `\`liveUrl\` is not a URL: "${liveUrl}". Nothing was sent.` };
|
|
4999
|
+
}
|
|
5000
|
+
const scheme = HTTP_SCHEME_OF[url.protocol];
|
|
5001
|
+
if (scheme === void 0) {
|
|
5002
|
+
return {
|
|
5003
|
+
ok: false,
|
|
5004
|
+
message: `\`liveUrl\` must be an https:, wss:, http: or ws: URL, not ${url.protocol}. Nothing was sent.`
|
|
5005
|
+
};
|
|
5006
|
+
}
|
|
5007
|
+
url.protocol = scheme;
|
|
5008
|
+
url.search = "";
|
|
5009
|
+
url.hash = "";
|
|
5010
|
+
return { ok: true, url };
|
|
5011
|
+
}
|
|
5012
|
+
chunkMWMSFIWN_cjs.__name(readLiveUrl, "readLiveUrl");
|
|
5013
|
+
function originOf(baseUrl) {
|
|
5014
|
+
try {
|
|
5015
|
+
return new URL(baseUrl).origin;
|
|
5016
|
+
} catch {
|
|
5017
|
+
return void 0;
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
chunkMWMSFIWN_cjs.__name(originOf, "originOf");
|
|
5021
|
+
|
|
5022
|
+
// src/changes/live-edge.ts
|
|
5023
|
+
var LIVE_KEEPALIVE_INTERVAL_MS = 3e4;
|
|
5024
|
+
var LIVE_POLLS_BEFORE_SOCKET = 4;
|
|
5025
|
+
async function* subscribeLiveEdge(client, options = {}) {
|
|
5026
|
+
const { signal } = options;
|
|
5027
|
+
if (isAborted(signal)) return;
|
|
5028
|
+
const key = client.apiKey;
|
|
5029
|
+
if (key === void 0 || !isPublishableKey(key)) {
|
|
5030
|
+
throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
|
|
5031
|
+
}
|
|
5032
|
+
const address = liveEdgeAddress(client);
|
|
5033
|
+
if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
|
|
5034
|
+
const request = {
|
|
5035
|
+
base: address.url,
|
|
5036
|
+
key,
|
|
5037
|
+
dataset: client.dataset,
|
|
5038
|
+
types: options.types,
|
|
5039
|
+
ids: options.ids
|
|
5040
|
+
};
|
|
5041
|
+
const reach = { position: options.since };
|
|
5042
|
+
for (; ; ) {
|
|
5043
|
+
const socket = openSocket(client, edgeUrl(request, reach.position, "socket"));
|
|
5044
|
+
if (socket !== void 0) {
|
|
5045
|
+
const ended = yield* followSocket(socket, reach, options);
|
|
5046
|
+
if (ended === "aborted") return;
|
|
5047
|
+
}
|
|
5048
|
+
const polled = yield* followPolls(client, request, reach, options);
|
|
5049
|
+
if (polled === "aborted") return;
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
chunkMWMSFIWN_cjs.__name(subscribeLiveEdge, "subscribeLiveEdge");
|
|
5053
|
+
var SOCKET_CONNECTING = 0;
|
|
5054
|
+
var SOCKET_OPEN = 1;
|
|
5055
|
+
function runtimeWebSocket() {
|
|
5056
|
+
const candidate = globalThis.WebSocket;
|
|
5057
|
+
return typeof candidate === "function" ? candidate : void 0;
|
|
5058
|
+
}
|
|
5059
|
+
chunkMWMSFIWN_cjs.__name(runtimeWebSocket, "runtimeWebSocket");
|
|
5060
|
+
function openSocket(client, url) {
|
|
5061
|
+
const Socket = client.webSocket ?? runtimeWebSocket();
|
|
5062
|
+
if (Socket === void 0) return void 0;
|
|
5063
|
+
try {
|
|
5064
|
+
return new Socket(url);
|
|
5065
|
+
} catch {
|
|
5066
|
+
return void 0;
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
chunkMWMSFIWN_cjs.__name(openSocket, "openSocket");
|
|
5070
|
+
async function* followSocket(socket, reach, options) {
|
|
5071
|
+
const { signal } = options;
|
|
5072
|
+
const inbox = socketInbox(socket, signal);
|
|
5073
|
+
let open = false;
|
|
5074
|
+
try {
|
|
5075
|
+
for (; ; ) {
|
|
5076
|
+
const event = await inbox.next();
|
|
5077
|
+
if (event === void 0) return "aborted";
|
|
5078
|
+
switch (event.kind) {
|
|
5079
|
+
case "open": {
|
|
5080
|
+
open = true;
|
|
5081
|
+
inbox.keepAlive();
|
|
5082
|
+
continue;
|
|
5083
|
+
}
|
|
5084
|
+
case "error": {
|
|
5085
|
+
if (!open) return "unopened";
|
|
5086
|
+
continue;
|
|
5087
|
+
}
|
|
5088
|
+
case "close": {
|
|
5089
|
+
if (!open) return "unopened";
|
|
5090
|
+
throw closedBy(event.code, event.reason);
|
|
5091
|
+
}
|
|
5092
|
+
case "silent": {
|
|
5093
|
+
throw new LiveEdgeError(
|
|
5094
|
+
"The live edge\u2019s socket stopped answering its keepalive, so the connection is presumed dead; reconnecting from the last cursor.",
|
|
5095
|
+
{ kind: "lost" },
|
|
5096
|
+
"retry"
|
|
5097
|
+
);
|
|
5098
|
+
}
|
|
5099
|
+
case "message": {
|
|
5100
|
+
if (event.data === VISITOR_KEEPALIVE.response) continue;
|
|
5101
|
+
const frame = typeof event.data === "string" ? parseVisitorFrame(event.data) : null;
|
|
5102
|
+
if (frame === null)
|
|
5103
|
+
throw unreadable(`a frame the wire does not declare: ${sample(event.data)}`);
|
|
5104
|
+
switch (frame.type) {
|
|
5105
|
+
case VISITOR_FRAMES.opened: {
|
|
5106
|
+
reach.position = frame.cursor;
|
|
5107
|
+
options.opened?.();
|
|
5108
|
+
options.reached?.(frame.cursor);
|
|
5109
|
+
continue;
|
|
5110
|
+
}
|
|
5111
|
+
case VISITOR_FRAMES.changes: {
|
|
5112
|
+
const prior = reach.position;
|
|
5113
|
+
if (prior === void 0) throw unreadable("changes before the socket had a position");
|
|
5114
|
+
for (const change of changesOf(frame.changes, frame.cursor, prior)) {
|
|
5115
|
+
yield change;
|
|
5116
|
+
if (isAborted(signal)) return "aborted";
|
|
5117
|
+
}
|
|
5118
|
+
reach.position = frame.cursor;
|
|
5119
|
+
if (frame.changes.length === 0) options.reached?.(frame.cursor);
|
|
5120
|
+
continue;
|
|
5121
|
+
}
|
|
5122
|
+
case VISITOR_FRAMES.resync: {
|
|
5123
|
+
await expire(frame.reason, frame.cursor, options);
|
|
5124
|
+
if (isAborted(signal)) return "aborted";
|
|
5125
|
+
reach.position = frame.cursor;
|
|
5126
|
+
options.reached?.(frame.cursor);
|
|
5127
|
+
continue;
|
|
5128
|
+
}
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
} finally {
|
|
5134
|
+
inbox.dispose();
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
chunkMWMSFIWN_cjs.__name(followSocket, "followSocket");
|
|
5138
|
+
function socketInbox(socket, signal) {
|
|
5139
|
+
const events = [];
|
|
5140
|
+
let wake;
|
|
5141
|
+
let disposed = false;
|
|
5142
|
+
let heard = true;
|
|
5143
|
+
let keepalive;
|
|
5144
|
+
const rouse = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => {
|
|
5145
|
+
const waking = wake;
|
|
5146
|
+
wake = void 0;
|
|
5147
|
+
waking?.();
|
|
5148
|
+
}, "rouse");
|
|
5149
|
+
const push = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name((event) => {
|
|
5150
|
+
if (disposed) return;
|
|
5151
|
+
events.push(event);
|
|
5152
|
+
rouse();
|
|
5153
|
+
}, "push");
|
|
5154
|
+
socket.addEventListener("open", () => push({ kind: "open" }));
|
|
5155
|
+
socket.addEventListener("message", (event) => {
|
|
5156
|
+
heard = true;
|
|
5157
|
+
push({ kind: "message", data: isRecord(event) ? event["data"] : void 0 });
|
|
5158
|
+
});
|
|
5159
|
+
socket.addEventListener("close", (event) => {
|
|
5160
|
+
const code = isRecord(event) ? event["code"] : void 0;
|
|
5161
|
+
const reason = isRecord(event) ? event["reason"] : void 0;
|
|
5162
|
+
push({
|
|
5163
|
+
kind: "close",
|
|
5164
|
+
// A close event always carries both; a socket that somehow raised one without them closed
|
|
5165
|
+
// abnormally, which is what 1006 says.
|
|
5166
|
+
code: typeof code === "number" ? code : 1006,
|
|
5167
|
+
reason: typeof reason === "string" ? reason : ""
|
|
5168
|
+
});
|
|
5169
|
+
});
|
|
5170
|
+
socket.addEventListener("error", () => push({ kind: "error" }));
|
|
5171
|
+
signal?.addEventListener("abort", rouse, { once: true });
|
|
5172
|
+
return {
|
|
5173
|
+
async next() {
|
|
5174
|
+
for (; ; ) {
|
|
5175
|
+
if (isAborted(signal)) return void 0;
|
|
5176
|
+
const event = events.shift();
|
|
5177
|
+
if (event !== void 0) return event;
|
|
5178
|
+
await new Promise((resolve) => {
|
|
5179
|
+
wake = resolve;
|
|
5180
|
+
});
|
|
5181
|
+
}
|
|
5182
|
+
},
|
|
5183
|
+
keepAlive() {
|
|
5184
|
+
keepalive = setInterval(() => {
|
|
5185
|
+
if (!heard) {
|
|
5186
|
+
push({ kind: "silent" });
|
|
5187
|
+
return;
|
|
5188
|
+
}
|
|
5189
|
+
heard = false;
|
|
5190
|
+
if (socket.readyState === SOCKET_OPEN) socket.send(VISITOR_KEEPALIVE.request);
|
|
5191
|
+
}, LIVE_KEEPALIVE_INTERVAL_MS);
|
|
5192
|
+
},
|
|
5193
|
+
dispose() {
|
|
5194
|
+
disposed = true;
|
|
5195
|
+
if (keepalive !== void 0) clearInterval(keepalive);
|
|
5196
|
+
signal?.removeEventListener("abort", rouse);
|
|
5197
|
+
if (socket.readyState === SOCKET_CONNECTING || socket.readyState === SOCKET_OPEN) {
|
|
5198
|
+
socket.close(1e3);
|
|
5199
|
+
}
|
|
5200
|
+
}
|
|
5201
|
+
};
|
|
5202
|
+
}
|
|
5203
|
+
chunkMWMSFIWN_cjs.__name(socketInbox, "socketInbox");
|
|
5204
|
+
function closedBy(code, reason) {
|
|
5205
|
+
const retry = closeRetryOf(code);
|
|
5206
|
+
const meaning = hasOwn(CLOSE_MEANING, code) ? CLOSE_MEANING[code] : code < 4e3 ? "the connection dropped" : "a refusal this version of the SDK does not know";
|
|
5207
|
+
const said = `close ${code}${reason === "" ? "" : ` ${reason}`}`;
|
|
5208
|
+
return new LiveEdgeError(
|
|
5209
|
+
`The live edge ended this subscription (${said}): ${meaning}. ${AFTER_A_CLOSE[retry]}`,
|
|
5210
|
+
{ kind: "closed", code, reason },
|
|
5211
|
+
retry
|
|
5212
|
+
);
|
|
5213
|
+
}
|
|
5214
|
+
chunkMWMSFIWN_cjs.__name(closedBy, "closedBy");
|
|
5215
|
+
var AFTER_A_CLOSE = {
|
|
5216
|
+
stop: "The same request would be refused again, so it was not retried.",
|
|
5217
|
+
retry: "Reconnecting from the last cursor after a short back-off.",
|
|
5218
|
+
"back-off": "Retrying after a back-off of at least a minute, without polling, which the same admission refuses."
|
|
5219
|
+
};
|
|
5220
|
+
function closeRetryOf(code) {
|
|
5221
|
+
if (hasOwn(VISITOR_CLOSE_RETRY, code)) return VISITOR_CLOSE_RETRY[code];
|
|
5222
|
+
return code < 4e3 ? "retry" : "stop";
|
|
5223
|
+
}
|
|
5224
|
+
chunkMWMSFIWN_cjs.__name(closeRetryOf, "closeRetryOf");
|
|
5225
|
+
var CLOSE_MEANING = {
|
|
5226
|
+
[VISITOR_CLOSE_CODES.requestInvalid]: "the edge could not read the request \u2014 a malformed cursor or filter",
|
|
5227
|
+
[VISITOR_CLOSE_CODES.keyRefused]: "the key is not a publishable key the edge accepts \u2014 unknown, revoked or expired",
|
|
5228
|
+
[VISITOR_CLOSE_CODES.originRefused]: "this page\u2019s origin is not on the publishable key\u2019s allowed origins",
|
|
5229
|
+
[VISITOR_CLOSE_CODES.datasetRefused]: "`dataset` names no dataset the key reaches",
|
|
5230
|
+
[VISITOR_CLOSE_CODES.unavailable]: "the edge could not reach what it needed to decide just now",
|
|
5231
|
+
[VISITOR_CLOSE_CODES.allowanceReached]: "the project holds as many live connections as its plan allows",
|
|
5232
|
+
[VISITOR_CLOSE_CODES.addressLimitReached]: "this address holds as many live connections to the project as one address may",
|
|
5233
|
+
[VISITOR_CLOSE_CODES.ceilingReached]: "the project is at its safety ceiling of live connections"
|
|
5234
|
+
};
|
|
5235
|
+
async function* followPolls(client, request, reach, options) {
|
|
5236
|
+
const { signal } = options;
|
|
5237
|
+
for (let poll = 0; poll < LIVE_POLLS_BEFORE_SOCKET; poll += 1) {
|
|
5238
|
+
if (isAborted(signal)) return "aborted";
|
|
5239
|
+
const answer = await pollOnce2(client, request, reach.position, signal);
|
|
5240
|
+
if (answer === void 0) return "aborted";
|
|
5241
|
+
options.opened?.();
|
|
5242
|
+
if (answer.kind === "resync") {
|
|
5243
|
+
await expire(answer.reason, answer.cursor, options);
|
|
5244
|
+
if (isAborted(signal)) return "aborted";
|
|
5245
|
+
reach.position = answer.cursor;
|
|
5246
|
+
options.reached?.(answer.cursor);
|
|
5247
|
+
} else {
|
|
5248
|
+
const prior = reach.position;
|
|
5249
|
+
if (answer.changes.length > 0 && prior === void 0) {
|
|
5250
|
+
throw unreadable("a poll without a cursor answered changes");
|
|
5251
|
+
}
|
|
5252
|
+
for (const change of changesOf(answer.changes, answer.cursor, prior ?? answer.cursor)) {
|
|
5253
|
+
yield change;
|
|
5254
|
+
if (isAborted(signal)) return "aborted";
|
|
5255
|
+
}
|
|
5256
|
+
reach.position = answer.cursor;
|
|
5257
|
+
if (answer.changes.length === 0) options.reached?.(answer.cursor);
|
|
5258
|
+
}
|
|
5259
|
+
await sleep(VISITOR_POLL_INTERVAL_MS, signal);
|
|
5260
|
+
}
|
|
5261
|
+
return isAborted(signal) ? "aborted" : "socket";
|
|
5262
|
+
}
|
|
5263
|
+
chunkMWMSFIWN_cjs.__name(followPolls, "followPolls");
|
|
5264
|
+
async function pollOnce2(client, request, since, signal) {
|
|
5265
|
+
if (isAborted(signal)) return void 0;
|
|
5266
|
+
const url = edgeUrl(request, since, "poll", client.clientId);
|
|
5267
|
+
const context = { url: edgeUrl({ ...request, key: void 0 }, since, "poll", client.clientId) };
|
|
5268
|
+
const controller = new AbortController();
|
|
5269
|
+
let timedOut = false;
|
|
5270
|
+
const timer = setTimeout(() => {
|
|
5271
|
+
timedOut = true;
|
|
5272
|
+
controller.abort();
|
|
5273
|
+
}, client.timeout);
|
|
5274
|
+
const onAbort = /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => controller.abort(), "onAbort");
|
|
5275
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5276
|
+
try {
|
|
5277
|
+
let response;
|
|
5278
|
+
let text;
|
|
5279
|
+
try {
|
|
5280
|
+
const send = client.fetch ?? globalThis.fetch;
|
|
5281
|
+
response = await send(url, { method: "GET", signal: controller.signal });
|
|
5282
|
+
text = await response.text();
|
|
5283
|
+
} catch (error) {
|
|
5284
|
+
if (isAborted(signal)) return void 0;
|
|
5285
|
+
if (timedOut) {
|
|
5286
|
+
throw new TimeoutError(
|
|
5287
|
+
`The live edge did not answer a poll within ${client.timeout}ms`,
|
|
5288
|
+
client.timeout,
|
|
5289
|
+
void 0,
|
|
5290
|
+
void 0,
|
|
5291
|
+
context
|
|
5292
|
+
);
|
|
5293
|
+
}
|
|
5294
|
+
throw ErrorMapper.mapGenericError(
|
|
5295
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
5296
|
+
context
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5299
|
+
const body = parseJson(text);
|
|
5300
|
+
if (!response.ok) throw refusedPoll(response, body, context);
|
|
5301
|
+
const answer = readVisitorPollAnswer(isRecord(body) ? body["data"] : void 0);
|
|
5302
|
+
if (answer === null)
|
|
5303
|
+
throw unreadable(`a poll answer the wire does not declare: ${sample(text)}`);
|
|
5304
|
+
return answer;
|
|
5305
|
+
} finally {
|
|
5306
|
+
clearTimeout(timer);
|
|
5307
|
+
signal?.removeEventListener("abort", onAbort);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
chunkMWMSFIWN_cjs.__name(pollOnce2, "pollOnce");
|
|
5311
|
+
function refusedPoll(response, body, context) {
|
|
5312
|
+
const headers = {};
|
|
5313
|
+
response.headers.forEach((value, name) => {
|
|
5314
|
+
headers[name] = value;
|
|
5315
|
+
});
|
|
5316
|
+
const mapped = ErrorMapper.mapHttpError(
|
|
5317
|
+
{ status: response.status, statusText: response.statusText, body, headers },
|
|
5318
|
+
{ ...context, method: "GET" }
|
|
5319
|
+
);
|
|
5320
|
+
const refusal = readError(body);
|
|
5321
|
+
if (refusal === void 0 || !hasOwn(VISITOR_POLL_RETRY, refusal.code)) return mapped;
|
|
5322
|
+
const code = refusal.code;
|
|
5323
|
+
const retryAfterMs = parseRetryAfterMs(headerValue(headers, "Retry-After"), Date.now());
|
|
5324
|
+
return new LiveEdgeError(
|
|
5325
|
+
`The live edge refused a poll (${code}): ${refusal.messages[0] ?? mapped.message}`,
|
|
5326
|
+
{ kind: "refused", code },
|
|
5327
|
+
VISITOR_POLL_RETRY[code],
|
|
5328
|
+
{
|
|
5329
|
+
statusCode: response.status,
|
|
5330
|
+
cause: mapped,
|
|
5331
|
+
...retryAfterMs === void 0 ? {} : { retryAfterMs },
|
|
5332
|
+
context
|
|
5333
|
+
}
|
|
5334
|
+
);
|
|
5335
|
+
}
|
|
5336
|
+
chunkMWMSFIWN_cjs.__name(refusedPoll, "refusedPoll");
|
|
5337
|
+
function edgeUrl(request, since, transport, clientId) {
|
|
5338
|
+
const url = new URL(request.base.href);
|
|
5339
|
+
url.pathname = `${url.pathname.replace(/\/+$/, "")}${VISITOR_LIVE_PATH}`;
|
|
5340
|
+
if (transport === "socket") url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
|
|
5341
|
+
const query = new URLSearchParams();
|
|
5342
|
+
if (request.key !== void 0) query.set(VISITOR_QUERY.key, request.key);
|
|
5343
|
+
if (request.dataset !== void 0 && request.dataset !== "") {
|
|
5344
|
+
query.set(VISITOR_QUERY.dataset, request.dataset);
|
|
5345
|
+
}
|
|
5346
|
+
if (since !== void 0) query.set(VISITOR_QUERY.since, since);
|
|
5347
|
+
if (request.types !== void 0) query.set(VISITOR_QUERY.types, request.types.join(","));
|
|
5348
|
+
if (request.ids !== void 0) query.set(VISITOR_QUERY.ids, request.ids.join(","));
|
|
5349
|
+
if (transport === "poll" && clientId !== void 0) query.set(VISITOR_QUERY.client, clientId);
|
|
5350
|
+
url.search = query.toString();
|
|
5351
|
+
return url.href;
|
|
5352
|
+
}
|
|
5353
|
+
chunkMWMSFIWN_cjs.__name(edgeUrl, "edgeUrl");
|
|
5354
|
+
function changesOf(changes, cursor, prior) {
|
|
5355
|
+
const last = changes.length - 1;
|
|
5356
|
+
return changes.map((change, index) => ({
|
|
5357
|
+
entryId: change.entryId,
|
|
5358
|
+
contentType: change.contentType,
|
|
5359
|
+
locale: change.locale,
|
|
5360
|
+
kind: change.kind,
|
|
5361
|
+
cursor: index === last ? cursor : prior,
|
|
5362
|
+
fresh: cursor
|
|
5363
|
+
}));
|
|
5364
|
+
}
|
|
5365
|
+
chunkMWMSFIWN_cjs.__name(changesOf, "changesOf");
|
|
5366
|
+
async function expire(reason, cursor, options) {
|
|
5367
|
+
const expired = ChangesExpiredError.resync(reason, cursor);
|
|
5368
|
+
const onExpired = options.onExpired ?? "throw";
|
|
5369
|
+
if (onExpired === "throw") throw expired;
|
|
5370
|
+
if (typeof onExpired === "function") await onExpired(expired);
|
|
5371
|
+
}
|
|
5372
|
+
chunkMWMSFIWN_cjs.__name(expire, "expire");
|
|
5373
|
+
function unreadable(what) {
|
|
5374
|
+
return new LiveEdgeError(
|
|
5375
|
+
`The live edge sent ${what}. This version of the SDK cannot follow it, so it stopped.`,
|
|
5376
|
+
{ kind: "unreadable", what },
|
|
5377
|
+
"stop"
|
|
5378
|
+
);
|
|
5379
|
+
}
|
|
5380
|
+
chunkMWMSFIWN_cjs.__name(unreadable, "unreadable");
|
|
5381
|
+
var NEEDS_PUBLISHABLE_KEY = `Live updates at RelyIO\u2019s edge need a publishable key (\`${PUBLISHABLE_KEY_PREFIX}\u2026\`), and this client holds none. A secret or preview key is never sent to the edge; on a server, follow \`changes()\` with it instead. Nothing was sent.`;
|
|
5382
|
+
function sample(value) {
|
|
5383
|
+
const text = typeof value === "string" ? value : `(${typeof value})`;
|
|
5384
|
+
return text.length > 200 ? `${text.slice(0, 200)}\u2026` : text;
|
|
5385
|
+
}
|
|
5386
|
+
chunkMWMSFIWN_cjs.__name(sample, "sample");
|
|
5387
|
+
function parseJson(text) {
|
|
5388
|
+
try {
|
|
5389
|
+
return JSON.parse(text);
|
|
5390
|
+
} catch {
|
|
5391
|
+
return void 0;
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
chunkMWMSFIWN_cjs.__name(parseJson, "parseJson");
|
|
5395
|
+
function isRecord(value) {
|
|
5396
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5397
|
+
}
|
|
5398
|
+
chunkMWMSFIWN_cjs.__name(isRecord, "isRecord");
|
|
5399
|
+
function hasOwn(object, key) {
|
|
5400
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
5401
|
+
}
|
|
5402
|
+
chunkMWMSFIWN_cjs.__name(hasOwn, "hasOwn");
|
|
5403
|
+
|
|
4370
5404
|
// src/config/dev-detection.ts
|
|
4371
5405
|
function sandboxStateOf(resolution) {
|
|
4372
5406
|
return resolution.state === "active" ? resolution.sandbox : resolution;
|
|
@@ -4477,7 +5511,7 @@ var DEFAULT_CONFIG = {
|
|
|
4477
5511
|
environment: "production",
|
|
4478
5512
|
headers: {},
|
|
4479
5513
|
browser: {
|
|
4480
|
-
includeCredentials:
|
|
5514
|
+
includeCredentials: false,
|
|
4481
5515
|
useRelativeUrls: false
|
|
4482
5516
|
},
|
|
4483
5517
|
cache: {
|
|
@@ -4509,45 +5543,48 @@ function validateConfig(config) {
|
|
|
4509
5543
|
if (config.baseUrl != null && typeof config.baseUrl !== "string") {
|
|
4510
5544
|
throw new Error("Base URL must be a string");
|
|
4511
5545
|
}
|
|
4512
|
-
if (config.
|
|
4513
|
-
throw new Error("
|
|
5546
|
+
if (config.liveUrl != null && typeof config.liveUrl !== "string") {
|
|
5547
|
+
throw new Error("liveUrl must be a string");
|
|
5548
|
+
}
|
|
5549
|
+
if (config.webSocket != null && typeof config.webSocket !== "function") {
|
|
5550
|
+
throw new Error("webSocket must be a WebSocket class");
|
|
4514
5551
|
}
|
|
4515
|
-
if (config.
|
|
4516
|
-
|
|
5552
|
+
if (config.timeout != null) assertRequestTimeout(config.timeout);
|
|
5553
|
+
if (config.retryAttempts != null && !(Number.isInteger(config.retryAttempts) && config.retryAttempts >= 1)) {
|
|
5554
|
+
throw new Error(
|
|
5555
|
+
`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)}`
|
|
5556
|
+
);
|
|
4517
5557
|
}
|
|
4518
5558
|
}
|
|
4519
5559
|
chunkMWMSFIWN_cjs.__name(validateConfig, "validateConfig");
|
|
4520
5560
|
var devOverrideNotified = false;
|
|
4521
5561
|
function resolveConfig(userConfig) {
|
|
4522
5562
|
validateConfig(userConfig);
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
const dev = resolveDevOverride(userConfig.dev);
|
|
5563
|
+
return withHandshake(withDefaults(DEFAULT_CONFIG, userConfig, DEFAULT_CONFIG));
|
|
5564
|
+
}
|
|
5565
|
+
chunkMWMSFIWN_cjs.__name(resolveConfig, "resolveConfig");
|
|
5566
|
+
function resolveConfigUpdate(configured, update) {
|
|
5567
|
+
validateConfig(update);
|
|
5568
|
+
const base = update.apiKey === void 0 ? configured : withoutKeyHeader(configured);
|
|
5569
|
+
return withHandshake(withDefaults(base, update, DEFAULT_CONFIG));
|
|
5570
|
+
}
|
|
5571
|
+
chunkMWMSFIWN_cjs.__name(resolveConfigUpdate, "resolveConfigUpdate");
|
|
5572
|
+
function withConfiguredKey(configured, apiKey) {
|
|
5573
|
+
return { ...withoutKeyHeader(configured), apiKey };
|
|
5574
|
+
}
|
|
5575
|
+
chunkMWMSFIWN_cjs.__name(withConfiguredKey, "withConfiguredKey");
|
|
5576
|
+
function withoutKeyHeader(configured) {
|
|
5577
|
+
return { ...configured, headers: layerHeaders(configured.headers, { [API_KEY_HEADER]: null }) };
|
|
5578
|
+
}
|
|
5579
|
+
chunkMWMSFIWN_cjs.__name(withoutKeyHeader, "withoutKeyHeader");
|
|
5580
|
+
function withHandshake(configured) {
|
|
5581
|
+
const dev = resolveDevOverride(configured.dev);
|
|
5582
|
+
const merged = withDefaults(
|
|
5583
|
+
configured,
|
|
5584
|
+
dev.state === "active" ? { apiKey: dev.apiKey, dataset: dev.sandbox.datasetId } : {},
|
|
5585
|
+
DEFAULT_CONFIG
|
|
5586
|
+
);
|
|
4548
5587
|
if (dev.state === "active") {
|
|
4549
|
-
merged.apiKey = dev.apiKey;
|
|
4550
|
-
merged.dataset = dev.sandbox.datasetId;
|
|
4551
5588
|
if (!devOverrideNotified) {
|
|
4552
5589
|
devOverrideNotified = true;
|
|
4553
5590
|
console.info(
|
|
@@ -4565,30 +5602,69 @@ function resolveConfig(userConfig) {
|
|
|
4565
5602
|
`[RelyIO] Your .relyio/dev.json could not be read (${dev.reason}) \u2014 ignoring it and using the configured dataset "${merged.dataset}". Run \`relyio dev\` to rewrite it.`
|
|
4566
5603
|
);
|
|
4567
5604
|
}
|
|
4568
|
-
return { config: merged, sandbox: sandboxStateOf(dev) };
|
|
5605
|
+
return { config: merged, sandbox: sandboxStateOf(dev), configured };
|
|
4569
5606
|
}
|
|
4570
|
-
chunkMWMSFIWN_cjs.__name(
|
|
5607
|
+
chunkMWMSFIWN_cjs.__name(withHandshake, "withHandshake");
|
|
5608
|
+
function withDefaults(base, given, defaults) {
|
|
5609
|
+
const merged = new Map(Object.entries(base));
|
|
5610
|
+
const givenValues = new Map(Object.entries(given ?? {}));
|
|
5611
|
+
const defaultValues = new Map(Object.entries(defaults));
|
|
5612
|
+
for (const key of /* @__PURE__ */ new Set([...merged.keys(), ...givenValues.keys()])) {
|
|
5613
|
+
const fallback = merged.get(key);
|
|
5614
|
+
const value = givenValues.get(key);
|
|
5615
|
+
const givenBag = isOptionBag(value) ? value : void 0;
|
|
5616
|
+
if (isOptionBag(fallback) && key === "headers") {
|
|
5617
|
+
merged.set(key, layerHeaders(fallback, givenBag));
|
|
5618
|
+
} else if (isOptionBag(fallback)) {
|
|
5619
|
+
const defaultBag = defaultValues.get(key);
|
|
5620
|
+
merged.set(key, withDefaults(fallback, givenBag, isOptionBag(defaultBag) ? defaultBag : {}));
|
|
5621
|
+
} else if (value === null) {
|
|
5622
|
+
if (defaultValues.has(key)) merged.set(key, defaultValues.get(key));
|
|
5623
|
+
else merged.delete(key);
|
|
5624
|
+
} else if (value !== void 0) {
|
|
5625
|
+
merged.set(key, value);
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
return Object.fromEntries(merged);
|
|
5629
|
+
}
|
|
5630
|
+
chunkMWMSFIWN_cjs.__name(withDefaults, "withDefaults");
|
|
5631
|
+
function isOptionBag(value) {
|
|
5632
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5633
|
+
}
|
|
5634
|
+
chunkMWMSFIWN_cjs.__name(isOptionBag, "isOptionBag");
|
|
4571
5635
|
|
|
4572
5636
|
// src/client/create-client.ts
|
|
4573
5637
|
var API_VERSION_SEGMENT = "v1";
|
|
4574
5638
|
var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
4575
5639
|
constructor(config) {
|
|
5640
|
+
/**
|
|
5641
|
+
* The one HTTP client every sub-client sends through. `updateConfig()` and `setApiKey()` change it
|
|
5642
|
+
* in place rather than replacing it, so a sub-client taken before either sends through the change.
|
|
5643
|
+
*/
|
|
4576
5644
|
chunkMWMSFIWN_cjs.__publicField(this, "httpClient");
|
|
4577
5645
|
chunkMWMSFIWN_cjs.__publicField(this, "config");
|
|
5646
|
+
/**
|
|
5647
|
+
* The configuration as `createClient()`, `setApiKey()` and `updateConfig()` gave it, before the
|
|
5648
|
+
* `relyio dev` handshake: what the next update is laid over, and what `withLocale()` starts from.
|
|
5649
|
+
*/
|
|
5650
|
+
chunkMWMSFIWN_cjs.__publicField(this, "configured");
|
|
4578
5651
|
chunkMWMSFIWN_cjs.__publicField(this, "_sandbox");
|
|
4579
|
-
chunkMWMSFIWN_cjs.__publicField(this, "_search");
|
|
4580
|
-
chunkMWMSFIWN_cjs.__publicField(this, "_batch");
|
|
4581
|
-
chunkMWMSFIWN_cjs.__publicField(this, "_adhocQuery");
|
|
4582
5652
|
chunkMWMSFIWN_cjs.__publicField(this, "_schema");
|
|
5653
|
+
/**
|
|
5654
|
+
* The client's locale as it is when a call is made. Every sub-client and builder is handed this
|
|
5655
|
+
* rather than a copy of the locale, so one taken before `updateConfig({ locale })` sends the new
|
|
5656
|
+
* locale, or none after `locale: null` (REL-1453).
|
|
5657
|
+
*/
|
|
5658
|
+
chunkMWMSFIWN_cjs.__publicField(this, "currentLocale", /* @__PURE__ */ chunkMWMSFIWN_cjs.__name(() => this.config.locale, "currentLocale"));
|
|
5659
|
+
/** The live edge's poll client id: chosen once, when first needed, and kept for this client's life. */
|
|
5660
|
+
chunkMWMSFIWN_cjs.__publicField(this, "_liveClientId");
|
|
4583
5661
|
const { schema, ...clientConfig } = config;
|
|
4584
5662
|
this._schema = schema;
|
|
4585
5663
|
const resolved = resolveConfig(clientConfig);
|
|
4586
5664
|
this.config = resolved.config;
|
|
5665
|
+
this.configured = resolved.configured;
|
|
4587
5666
|
this._sandbox = resolved.sandbox;
|
|
4588
5667
|
this.httpClient = new HttpClient(this.config);
|
|
4589
|
-
this._search = new SearchClient(this.httpClient, this.config.locale);
|
|
4590
|
-
this._batch = new BatchClient(this.httpClient);
|
|
4591
|
-
this._adhocQuery = new AdhocQueryClient(this.httpClient, this.config.locale);
|
|
4592
5668
|
}
|
|
4593
5669
|
// ============================================================================
|
|
4594
5670
|
// CORE CLIENTS
|
|
@@ -4617,10 +5693,10 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4617
5693
|
return this._sandbox;
|
|
4618
5694
|
}
|
|
4619
5695
|
/**
|
|
4620
|
-
* Get the ad-hoc query client
|
|
5696
|
+
* Get the ad-hoc query client. Every query it sends is in the client's locale as it is then.
|
|
4621
5697
|
*/
|
|
4622
5698
|
get query() {
|
|
4623
|
-
return this.
|
|
5699
|
+
return new AdhocQueryClient(this.httpClient, this.currentLocale);
|
|
4624
5700
|
}
|
|
4625
5701
|
// ============================================================================
|
|
4626
5702
|
// CONTENT OPERATIONS
|
|
@@ -4640,7 +5716,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4640
5716
|
* ```
|
|
4641
5717
|
*/
|
|
4642
5718
|
content(contentType) {
|
|
4643
|
-
return new ContentClient(this.httpClient, contentType, this.
|
|
5719
|
+
return new ContentClient(this.httpClient, contentType, this.currentLocale);
|
|
4644
5720
|
}
|
|
4645
5721
|
/**
|
|
4646
5722
|
* Get an asset client for a specific asset type.
|
|
@@ -4661,7 +5737,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4661
5737
|
* ```
|
|
4662
5738
|
*/
|
|
4663
5739
|
asset(assetType) {
|
|
4664
|
-
return new AssetClient(this.httpClient, assetType, this.
|
|
5740
|
+
return new AssetClient(this.httpClient, assetType, this.currentLocale);
|
|
4665
5741
|
}
|
|
4666
5742
|
/**
|
|
4667
5743
|
* Get a singleton client for a specific singleton key
|
|
@@ -4676,7 +5752,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4676
5752
|
* ```
|
|
4677
5753
|
*/
|
|
4678
5754
|
singleton(key) {
|
|
4679
|
-
return new SingletonClient(this.httpClient, key, this.
|
|
5755
|
+
return new SingletonClient(this.httpClient, key, this.currentLocale);
|
|
4680
5756
|
}
|
|
4681
5757
|
/**
|
|
4682
5758
|
* Get a settings client for a specific settings group
|
|
@@ -4690,7 +5766,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4690
5766
|
* ```
|
|
4691
5767
|
*/
|
|
4692
5768
|
settings(groupId) {
|
|
4693
|
-
return new SettingsClient(this.httpClient, groupId, this.
|
|
5769
|
+
return new SettingsClient(this.httpClient, groupId, this.currentLocale);
|
|
4694
5770
|
}
|
|
4695
5771
|
// ============================================================================
|
|
4696
5772
|
// SEARCH OPERATIONS
|
|
@@ -4712,7 +5788,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4712
5788
|
* ```
|
|
4713
5789
|
*/
|
|
4714
5790
|
search(query) {
|
|
4715
|
-
return this.
|
|
5791
|
+
return this.searchClient().search(query);
|
|
4716
5792
|
}
|
|
4717
5793
|
/**
|
|
4718
5794
|
* Start an autocomplete query for search suggestions
|
|
@@ -4728,7 +5804,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4728
5804
|
* ```
|
|
4729
5805
|
*/
|
|
4730
5806
|
autocomplete(query) {
|
|
4731
|
-
return this.
|
|
5807
|
+
return this.searchClient().autocomplete(query);
|
|
4732
5808
|
}
|
|
4733
5809
|
/**
|
|
4734
5810
|
* Find content similar to a given entry using vector search
|
|
@@ -4743,13 +5819,17 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4743
5819
|
* ```
|
|
4744
5820
|
*/
|
|
4745
5821
|
similar(sourceId) {
|
|
4746
|
-
return this.
|
|
5822
|
+
return this.searchClient().similar(sourceId);
|
|
4747
5823
|
}
|
|
4748
5824
|
// ============================================================================
|
|
4749
5825
|
// BATCH OPERATIONS
|
|
4750
5826
|
// ============================================================================
|
|
4751
5827
|
/**
|
|
4752
|
-
* Start a batch operation for bulk create/update/delete
|
|
5828
|
+
* Start a batch operation for bulk create/update/delete.
|
|
5829
|
+
*
|
|
5830
|
+
* By default each operation lands or fails on its own. `atomic: true` makes the batch one
|
|
5831
|
+
* transaction, which the API accepts only when every operation is the same kind of write and none
|
|
5832
|
+
* writes a singleton that does not exist yet.
|
|
4753
5833
|
*
|
|
4754
5834
|
* @example
|
|
4755
5835
|
* ```typescript
|
|
@@ -4758,13 +5838,23 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4758
5838
|
* .update('product', 'entry_abc', { content: { price: 899 } })
|
|
4759
5839
|
* .delete('product', 'entry_xyz')
|
|
4760
5840
|
* .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
|
|
4761
|
-
* .execute(
|
|
5841
|
+
* .execute()
|
|
4762
5842
|
*
|
|
4763
5843
|
* console.log(result.summary.succeeded)
|
|
5844
|
+
*
|
|
5845
|
+
* // All or nothing: one kind of write
|
|
5846
|
+
* await relyio.batch()
|
|
5847
|
+
* .update('product', 'entry_abc', { content: { price: 899 } })
|
|
5848
|
+
* .update('product', 'entry_def', { content: { price: 799 } })
|
|
5849
|
+
* .execute({ atomic: true })
|
|
4764
5850
|
* ```
|
|
4765
5851
|
*/
|
|
4766
5852
|
batch() {
|
|
4767
|
-
return this.
|
|
5853
|
+
return new BatchClient(this.httpClient, this.currentLocale).create();
|
|
5854
|
+
}
|
|
5855
|
+
/** The search client, whose builders send the client's locale as it is when each one is sent. */
|
|
5856
|
+
searchClient() {
|
|
5857
|
+
return new SearchClient(this.httpClient, this.currentLocale);
|
|
4768
5858
|
}
|
|
4769
5859
|
// ============================================================================
|
|
4770
5860
|
// CHANGES FEED
|
|
@@ -4776,13 +5866,15 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4776
5866
|
* Lazy — nothing is requested until the first `next()`. It runs until
|
|
4777
5867
|
* `signal` aborts, which ends the `for await` cleanly rather than throwing.
|
|
4778
5868
|
* A change names what changed; refetch it through the ordinary read path
|
|
4779
|
-
* (`INV-SS-CHANGE-IS-IDS`)
|
|
5869
|
+
* (`INV-SS-CHANGE-IS-IDS`), naming its `fresh` so no cache answers with the
|
|
5870
|
+
* body from before it (`FeedChange`).
|
|
4780
5871
|
*
|
|
4781
5872
|
* @example
|
|
4782
5873
|
* ```typescript
|
|
4783
5874
|
* const controller = new AbortController()
|
|
4784
5875
|
* for await (const change of relyio.changes({ since: cursor, types: ['post'], signal: controller.signal })) {
|
|
4785
|
-
* // { entryId, contentType, locale, kind, cursor }
|
|
5876
|
+
* // { entryId, contentType, locale, kind, cursor, fresh }
|
|
5877
|
+
* await relyio.content(change.contentType).findById(change.entryId).fresh(change.fresh).execute()
|
|
4786
5878
|
* }
|
|
4787
5879
|
* ```
|
|
4788
5880
|
*
|
|
@@ -4790,13 +5882,60 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4790
5882
|
* ```typescript
|
|
4791
5883
|
* for await (const change of relyio.changes({
|
|
4792
5884
|
* since: cursor,
|
|
4793
|
-
* onExpired: async
|
|
5885
|
+
* onExpired: async expired => refetchEverything(expired.fresh),
|
|
4794
5886
|
* })) { … }
|
|
4795
5887
|
* ```
|
|
4796
5888
|
*/
|
|
4797
5889
|
changes(options = {}) {
|
|
4798
5890
|
return pollChanges(this.httpClient, options);
|
|
4799
5891
|
}
|
|
5892
|
+
/**
|
|
5893
|
+
* Follow the dataset's **published** changes at RelyIO's live edge, with a publishable key
|
|
5894
|
+
* (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
|
|
5895
|
+
*
|
|
5896
|
+
* A WebSocket to the edge, from `since` or the dataset's current position; where a socket cannot
|
|
5897
|
+
* open — the runtime has none, or the network refuses it — it polls the edge instead, about every
|
|
5898
|
+
* fifteen seconds, from the same cursor. The edge is `liveUrl`, or derived from the default
|
|
5899
|
+
* `baseUrl` (see `RelyIOConfig.liveUrl`).
|
|
5900
|
+
*
|
|
5901
|
+
* One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
|
|
5902
|
+
* end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
|
|
5903
|
+
* that says whether to stop, retry or back off. Hand it to `followChanges()`, the one loop that
|
|
5904
|
+
* reconnects from the last cursor with jittered back-off and honours those answers:
|
|
5905
|
+
*
|
|
5906
|
+
* @example
|
|
5907
|
+
* ```typescript
|
|
5908
|
+
* const relyio = createClient({ apiKey: 'rly_pub_…' })
|
|
5909
|
+
* const controller = new AbortController()
|
|
5910
|
+
* await followChanges(from => relyio.liveChanges({ ...from, types: ['post'] }), {
|
|
5911
|
+
* signal: controller.signal,
|
|
5912
|
+
* // `fresh` names a position no cache holds a body for from before the change.
|
|
5913
|
+
* onChange: change =>
|
|
5914
|
+
* relyio.content(change.contentType).findById(change.entryId).fresh(change.fresh).execute(),
|
|
5915
|
+
* onResync: resync => refetchEverything(resync.cause === 'expired' ? resync.expired.fresh : undefined),
|
|
5916
|
+
* })
|
|
5917
|
+
* ```
|
|
5918
|
+
*
|
|
5919
|
+
* A client without a publishable key sends nothing: a secret or preview key is never put in the
|
|
5920
|
+
* edge's URL. On a server, follow `changes()` with it instead.
|
|
5921
|
+
*/
|
|
5922
|
+
liveChanges(options = {}) {
|
|
5923
|
+
const { apiKey, dataset, baseUrl, liveUrl, fetch: fetch2, webSocket, timeout } = this.config;
|
|
5924
|
+
this._liveClientId ?? (this._liveClientId = randomClientId());
|
|
5925
|
+
return subscribeLiveEdge(
|
|
5926
|
+
{
|
|
5927
|
+
apiKey,
|
|
5928
|
+
dataset,
|
|
5929
|
+
baseUrl,
|
|
5930
|
+
liveUrl,
|
|
5931
|
+
fetch: fetch2,
|
|
5932
|
+
webSocket,
|
|
5933
|
+
timeout,
|
|
5934
|
+
clientId: this._liveClientId
|
|
5935
|
+
},
|
|
5936
|
+
options
|
|
5937
|
+
);
|
|
5938
|
+
}
|
|
4800
5939
|
/**
|
|
4801
5940
|
* The dataset's current position in the changes feed, as a cursor to start
|
|
4802
5941
|
* `changes({ since })` or `followChanges(…, { since })` from. One
|
|
@@ -4838,7 +5977,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4838
5977
|
* ```
|
|
4839
5978
|
*/
|
|
4840
5979
|
adhoc() {
|
|
4841
|
-
return this.
|
|
5980
|
+
return this.query.build();
|
|
4842
5981
|
}
|
|
4843
5982
|
/**
|
|
4844
5983
|
* Execute a predefined query by name (from schema)
|
|
@@ -4923,16 +6062,53 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4923
6062
|
}
|
|
4924
6063
|
}
|
|
4925
6064
|
/**
|
|
4926
|
-
*
|
|
6065
|
+
* Change some of the client's options and keep the rest.
|
|
6066
|
+
*
|
|
6067
|
+
* What you pass is laid over the configuration the client holds, field by field:
|
|
6068
|
+
*
|
|
6069
|
+
* - an option you name replaces the value the client holds;
|
|
6070
|
+
* - an option left out, or given as `undefined`, keeps the value the client holds;
|
|
6071
|
+
* - an option with no default given as `null` is cleared — `locale`, `dataset`, `apiKey`, `dev`,
|
|
6072
|
+
* `fetch`, `browser.onCorsError`, `realtime.wsUrl`, `debug.logger` — so the client runs as though
|
|
6073
|
+
* it had never been given one. An option with a default takes no `null`;
|
|
6074
|
+
* - a bag of options you name — `browser`, `cache`, `realtime`, `debug` — keeps every field of it
|
|
6075
|
+
* you do not name, so `updateConfig({ browser: { includeCredentials: true } })` keeps a
|
|
6076
|
+
* configured `onCorsError`;
|
|
6077
|
+
* - `headers` is laid over the headers the client sends, a name matched without regard to case: a
|
|
6078
|
+
* header you name is added or replaces every spelling of it, every other one is still sent, and a
|
|
6079
|
+
* header given as `null` is no longer sent;
|
|
6080
|
+
* - naming `apiKey` — a key, or `null` — replaces every key the client holds, one given in
|
|
6081
|
+
* `headers` included.
|
|
6082
|
+
*
|
|
6083
|
+
* The configuration it is laid over is what `createClient()`, `setApiKey()` and earlier updates
|
|
6084
|
+
* gave the client. The `relyio dev` handshake is read again, as `createClient()` reads it: while a
|
|
6085
|
+
* sandbox is active its key and dataset are sent over the configured ones, and once it has gone
|
|
6086
|
+
* the configured ones are.
|
|
6087
|
+
*
|
|
6088
|
+
* The client's one HTTP client is changed in place, so every request from now on is sent as the
|
|
6089
|
+
* update says — including one from a `content()`, `asset()`, `singleton()` or `settings()`
|
|
6090
|
+
* sub-client, a `query` client, or a builder such as `search()` or `batch()`, taken before the
|
|
6091
|
+
* call. The locale reaches them too: each reads the client's locale when it sends, so a new
|
|
6092
|
+
* `locale` is the default of its next request and `locale: null` leaves that request with none. A
|
|
6093
|
+
* locale the call names, and a sub-client's own `withLocale()`, still win over it. A client made
|
|
6094
|
+
* by `withLocale()` is a client of its own: an update of this one does not reach it.
|
|
6095
|
+
*
|
|
6096
|
+
* @example
|
|
6097
|
+
* ```typescript
|
|
6098
|
+
* const relyio = createClient({ apiKey, headers: { 'X-Tenant': 'acme' }, browser: { onCorsError } })
|
|
6099
|
+
*
|
|
6100
|
+
* relyio.updateConfig({ headers: { 'X-Trace': traceId } }) // X-Tenant is still sent
|
|
6101
|
+
* relyio.updateConfig({ browser: { includeCredentials: true } }) // onCorsError is kept
|
|
6102
|
+
* relyio.updateConfig({ headers: { 'X-Tenant': null } }) // X-Tenant is no longer sent
|
|
6103
|
+
* relyio.updateConfig({ locale: null }) // reads name no locale of the client's
|
|
6104
|
+
* ```
|
|
4927
6105
|
*/
|
|
4928
|
-
updateConfig(
|
|
4929
|
-
const resolved =
|
|
6106
|
+
updateConfig(update) {
|
|
6107
|
+
const resolved = resolveConfigUpdate(this.configured, update);
|
|
4930
6108
|
this.config = resolved.config;
|
|
6109
|
+
this.configured = resolved.configured;
|
|
4931
6110
|
this._sandbox = resolved.sandbox;
|
|
4932
|
-
this.httpClient
|
|
4933
|
-
this._search = new SearchClient(this.httpClient, this.config.locale);
|
|
4934
|
-
this._batch = new BatchClient(this.httpClient);
|
|
4935
|
-
this._adhocQuery = new AdhocQueryClient(this.httpClient, this.config.locale);
|
|
6111
|
+
this.httpClient.configure(this.config);
|
|
4936
6112
|
}
|
|
4937
6113
|
/**
|
|
4938
6114
|
* Get the current configuration
|
|
@@ -4941,11 +6117,31 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4941
6117
|
return { ...this.config };
|
|
4942
6118
|
}
|
|
4943
6119
|
/**
|
|
4944
|
-
*
|
|
6120
|
+
* Replace the API key every later request sends as `X-API-Key`.
|
|
6121
|
+
*
|
|
6122
|
+
* It reaches every request this client makes from now on, including those of a `content()`,
|
|
6123
|
+
* `asset()` or other sub-client taken before the call, and `getConfig().apiKey` reports it. A key
|
|
6124
|
+
* given in `headers`, under any spelling, is replaced with it and does not come back on a later
|
|
6125
|
+
* `updateConfig()`. A client already derived with `withLocale()` is a client of its own and keeps
|
|
6126
|
+
* its key.
|
|
6127
|
+
*
|
|
6128
|
+
* An empty or blank key is no key, as it is when passed to `createClient`: the next request
|
|
6129
|
+
* rejects with `MissingApiKeyError` and nothing is sent.
|
|
6130
|
+
*
|
|
6131
|
+
* Under an active `relyio dev` sandbox the sandbox's scoped key stands, as it does over the key
|
|
6132
|
+
* passed to `createClient` — replacing the configured key does not retarget the client at the
|
|
6133
|
+
* sandbox's dataset with a key the sandbox did not issue.
|
|
6134
|
+
*
|
|
6135
|
+
* @example
|
|
6136
|
+
* ```typescript
|
|
6137
|
+
* const relyio = createClient({ apiKey: process.env.RELYIO_API_KEY! })
|
|
6138
|
+
* relyio.setApiKey(rotatedKey) // the next read sends `X-API-Key: <rotatedKey>`
|
|
6139
|
+
* ```
|
|
4945
6140
|
*/
|
|
4946
6141
|
setApiKey(apiKey) {
|
|
4947
|
-
this.
|
|
4948
|
-
this.
|
|
6142
|
+
this.configured = withConfiguredKey(this.configured, apiKey);
|
|
6143
|
+
if (this._sandbox.state === "active") return;
|
|
6144
|
+
this.httpClient.setApiKey(apiKey);
|
|
4949
6145
|
}
|
|
4950
6146
|
/**
|
|
4951
6147
|
* Get the HTTP client instance (for advanced usage)
|
|
@@ -4959,9 +6155,12 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4959
6155
|
/**
|
|
4960
6156
|
* Create a locale-scoped client
|
|
4961
6157
|
*
|
|
4962
|
-
* Every
|
|
4963
|
-
* `
|
|
4964
|
-
*
|
|
6158
|
+
* Every call the returned client builds is in this locale unless the call names one of its own,
|
|
6159
|
+
* which wins: every read — `content()`, `asset()`, `singleton()`, `settings()`, `search()`,
|
|
6160
|
+
* `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — and every write and
|
|
6161
|
+
* version-history read — `create()` and `update()`, the singleton and settings writes, the asset
|
|
6162
|
+
* file writes, `versions()` and `version()`, and each operation `batch()` builds. `restore()`
|
|
6163
|
+
* always names its locale; a delete, and a `batch().raw()` operation, carry none of the client's.
|
|
4965
6164
|
*
|
|
4966
6165
|
* Type-safe when schema is provided: autocompletes valid locale codes!
|
|
4967
6166
|
*
|
|
@@ -4969,10 +6168,11 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4969
6168
|
* ```typescript
|
|
4970
6169
|
* const spanish = relyio.withLocale('es-ES') // ← Autocompletes with schema!
|
|
4971
6170
|
*
|
|
4972
|
-
* // Reads use Spanish
|
|
6171
|
+
* // Reads and writes use Spanish
|
|
4973
6172
|
* const products = await spanish.content('product').query().execute()
|
|
4974
6173
|
* const homepage = await spanish.singleton('homepage').fetch()
|
|
4975
6174
|
* const results = await spanish.search('zapatos').execute()
|
|
6175
|
+
* await spanish.content('product').update(id, { title: 'Zapatos' })
|
|
4976
6176
|
*
|
|
4977
6177
|
* // Original client unchanged
|
|
4978
6178
|
* const englishProducts = await relyio.content('product').query().execute()
|
|
@@ -4980,7 +6180,7 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
|
|
|
4980
6180
|
*/
|
|
4981
6181
|
withLocale(locale) {
|
|
4982
6182
|
const newConfig = {
|
|
4983
|
-
...this.
|
|
6183
|
+
...this.configured,
|
|
4984
6184
|
locale,
|
|
4985
6185
|
schema: this._schema
|
|
4986
6186
|
};
|
|
@@ -5028,13 +6228,25 @@ function createClient(config) {
|
|
|
5028
6228
|
return new TypedRelyIOClient(config);
|
|
5029
6229
|
}
|
|
5030
6230
|
chunkMWMSFIWN_cjs.__name(createClient, "createClient");
|
|
6231
|
+
function randomClientId() {
|
|
6232
|
+
const bytes = new Uint8Array(16);
|
|
6233
|
+
const random = globalThis.crypto;
|
|
6234
|
+
if (typeof random?.getRandomValues === "function") {
|
|
6235
|
+
random.getRandomValues.call(random, bytes);
|
|
6236
|
+
} else {
|
|
6237
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
6238
|
+
bytes[index] = Math.floor(Math.random() * 256);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
6242
|
+
}
|
|
6243
|
+
chunkMWMSFIWN_cjs.__name(randomClientId, "randomClientId");
|
|
5031
6244
|
|
|
5032
6245
|
exports.AdhocQueryBuilder = AdhocQueryBuilder;
|
|
5033
6246
|
exports.AdhocQueryClient = AdhocQueryClient;
|
|
5034
6247
|
exports.AssetClient = AssetClient;
|
|
5035
6248
|
exports.AssetFileBuilder = AssetFileBuilder;
|
|
5036
6249
|
exports.AssetUploadBuilder = AssetUploadBuilder;
|
|
5037
|
-
exports.AuthenticationError = AuthenticationError;
|
|
5038
6250
|
exports.AuthorizationError = AuthorizationError;
|
|
5039
6251
|
exports.AutocompleteBuilder = AutocompleteBuilder;
|
|
5040
6252
|
exports.BaseValidationError = BaseValidationError;
|
|
@@ -5050,21 +6262,21 @@ exports.FileUploadError = FileUploadError;
|
|
|
5050
6262
|
exports.FileValidationError = FileValidationError;
|
|
5051
6263
|
exports.HttpClient = HttpClient;
|
|
5052
6264
|
exports.InvalidApiKeyError = InvalidApiKeyError;
|
|
5053
|
-
exports.InvalidFieldTypeError = InvalidFieldTypeError;
|
|
5054
6265
|
exports.InvalidPayloadError = InvalidPayloadError;
|
|
6266
|
+
exports.LIVE_KEEPALIVE_INTERVAL_MS = LIVE_KEEPALIVE_INTERVAL_MS;
|
|
6267
|
+
exports.LiveEdgeError = LiveEdgeError;
|
|
5055
6268
|
exports.MethodNotAllowedError = MethodNotAllowedError;
|
|
5056
6269
|
exports.MissingApiKeyError = MissingApiKeyError;
|
|
5057
6270
|
exports.NetworkError = NetworkError;
|
|
6271
|
+
exports.PUBLISHABLE_KEY_PREFIX = PUBLISHABLE_KEY_PREFIX;
|
|
5058
6272
|
exports.PayloadTooLargeError = PayloadTooLargeError;
|
|
5059
6273
|
exports.PlanFeatureUnavailableError = PlanFeatureUnavailableError;
|
|
5060
6274
|
exports.RateLimitError = RateLimitError;
|
|
5061
6275
|
exports.ReadOnlyKeyError = ReadOnlyKeyError;
|
|
5062
|
-
exports.RequiredFieldError = RequiredFieldError;
|
|
5063
6276
|
exports.ResourceConflictError = ResourceConflictError;
|
|
5064
6277
|
exports.ResourceExpiredError = ResourceExpiredError;
|
|
5065
6278
|
exports.ResourceNotFoundError = ResourceNotFoundError;
|
|
5066
6279
|
exports.SDKError = SDKError;
|
|
5067
|
-
exports.SchemaValidationError = SchemaValidationError;
|
|
5068
6280
|
exports.SearchBuilder = SearchBuilder;
|
|
5069
6281
|
exports.SearchClient = SearchClient;
|
|
5070
6282
|
exports.ServerError = ServerError;
|
|
@@ -5077,15 +6289,17 @@ exports.TransactionRolledBackError = TransactionRolledBackError;
|
|
|
5077
6289
|
exports.TypedRelyIOClient = TypedRelyIOClient;
|
|
5078
6290
|
exports.UnknownContractError = UnknownContractError;
|
|
5079
6291
|
exports.UsageQuotaExceededError = UsageQuotaExceededError;
|
|
6292
|
+
exports.VISITOR_ADMISSION_RETRY_AFTER_SECONDS = VISITOR_ADMISSION_RETRY_AFTER_SECONDS;
|
|
5080
6293
|
exports.ValidationError = ValidationError;
|
|
5081
6294
|
exports.createClient = createClient;
|
|
5082
6295
|
exports.entityTagOf = entityTagOf;
|
|
5083
6296
|
exports.isAborted = isAborted;
|
|
5084
6297
|
exports.isAssetEntry = isAssetEntry;
|
|
6298
|
+
exports.isPublishableKey = isPublishableKey;
|
|
5085
6299
|
exports.isResourceNotFound = isResourceNotFound;
|
|
5086
6300
|
exports.matchRoute = matchRoute;
|
|
5087
6301
|
exports.serviceInstructedDelayMs = serviceInstructedDelayMs;
|
|
5088
6302
|
exports.sleep = sleep;
|
|
5089
6303
|
exports.validateFile = validateFile;
|
|
5090
|
-
//# sourceMappingURL=chunk-
|
|
5091
|
-
//# sourceMappingURL=chunk-
|
|
6304
|
+
//# sourceMappingURL=chunk-XIE7WJV3.cjs.map
|
|
6305
|
+
//# sourceMappingURL=chunk-XIE7WJV3.cjs.map
|