@relyio/sdk 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-7W4MJXQ4.cjs → chunk-54WP2PWG.cjs} +215 -96
  4. package/dist/chunk-BBUB7C2Z.js +81 -0
  5. package/dist/{chunk-FJK7ZWKK.cjs → chunk-HMVGXUGR.cjs} +156 -221
  6. package/dist/chunk-LSRPMNPT.cjs +89 -0
  7. package/dist/{chunk-2QUK2ZGD.js → chunk-LYRYCIX5.js} +157 -219
  8. package/dist/{chunk-RJBIJ2ZK.js → chunk-QIZOBT5F.js} +215 -96
  9. package/dist/client/index.cjs +4 -3
  10. package/dist/client/index.d.cts +4 -3
  11. package/dist/client/index.d.ts +4 -3
  12. package/dist/client/index.js +2 -1
  13. package/dist/define-content-type-CBfnTWSS.d.cts +716 -0
  14. package/dist/define-content-type-CBfnTWSS.d.ts +716 -0
  15. package/dist/{define-schema-DHvUCKwj.d.cts → define-schema-BD6HSPnG.d.ts} +55 -722
  16. package/dist/{define-schema-DHvUCKwj.d.ts → define-schema-BfXeR6K8.d.cts} +55 -722
  17. package/dist/dev-handshake/index.cjs +37 -0
  18. package/dist/dev-handshake/index.d.cts +144 -0
  19. package/dist/dev-handshake/index.d.ts +144 -0
  20. package/dist/dev-handshake/index.js +4 -0
  21. package/dist/{index-DGWaawHt.d.cts → index-BDpar3FO.d.cts} +22 -6
  22. package/dist/{index-BsUqCAu8.d.cts → index-DuEhsGdE.d.ts} +516 -2155
  23. package/dist/{index-B-KiFHbx.d.ts → index-Dx01iwaf.d.ts} +22 -6
  24. package/dist/{index-BsUqCAu8.d.ts → index-ulOrcfPa.d.cts} +516 -2155
  25. package/dist/index.cjs +67 -70
  26. package/dist/index.d.cts +28 -13
  27. package/dist/index.d.ts +28 -13
  28. package/dist/index.js +3 -2
  29. package/dist/schema/index.cjs +35 -47
  30. package/dist/schema/index.d.cts +3 -2
  31. package/dist/schema/index.d.ts +3 -2
  32. package/dist/schema/index.js +1 -1
  33. package/dist/types/index.d.cts +2 -1
  34. package/dist/types/index.d.ts +2 -1
  35. package/package.json +11 -5
@@ -1,3 +1,4 @@
1
+ import { parseDevEnv, DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME, parseDevContextFile } from './chunk-BBUB7C2Z.js';
1
2
  import { __name, __publicField } from './chunk-XQ4QHWZE.js';
2
3
 
3
4
  /* RelyIO SDK - Built with ❤️ by the RelyIO Team */
@@ -165,14 +166,17 @@ var _UsageQuotaExceededError = class _UsageQuotaExceededError extends SDKError {
165
166
  __name(_UsageQuotaExceededError, "UsageQuotaExceededError");
166
167
  var UsageQuotaExceededError = _UsageQuotaExceededError;
167
168
  var _RateLimitError = class _RateLimitError extends SDKError {
168
- constructor(message = "Rate limit exceeded", limit, resetAt, context) {
169
+ constructor(message = "Rate limit exceeded", limit, resetAt, context, retryAfterMs) {
169
170
  super(message, 429, void 0, context);
170
171
  __publicField(this, "code", "RATE_LIMIT_EXCEEDED");
171
172
  __publicField(this, "retryable", true);
172
173
  __publicField(this, "limit");
173
174
  __publicField(this, "resetAt");
175
+ /** `Retry-After`, in milliseconds, where the response carried a readable one. */
176
+ __publicField(this, "retryAfterMs");
174
177
  this.limit = limit;
175
178
  this.resetAt = resetAt;
179
+ this.retryAfterMs = retryAfterMs;
176
180
  }
177
181
  getUserMessage() {
178
182
  return this.resetAt === void 0 ? "Too many requests. Please retry shortly." : `Too many requests. The window resets at ${this.resetAt}.`;
@@ -221,12 +225,15 @@ var _TransactionRolledBackError = class _TransactionRolledBackError extends SDKE
221
225
  __name(_TransactionRolledBackError, "TransactionRolledBackError");
222
226
  var TransactionRolledBackError = _TransactionRolledBackError;
223
227
  var _ServiceIndeterminateError = class _ServiceIndeterminateError extends SDKError {
224
- constructor(message = "The service could not decide this request", missing, context) {
228
+ constructor(message = "The service could not decide this request", missing, context, retryAfterMs) {
225
229
  super(message, 503, void 0, context);
226
230
  __publicField(this, "code", "SERVICE_INDETERMINATE");
227
231
  __publicField(this, "retryable", true);
228
232
  __publicField(this, "missing");
233
+ /** `Retry-After`, in milliseconds. The contract requires the header on this code. */
234
+ __publicField(this, "retryAfterMs");
229
235
  this.missing = missing;
236
+ this.retryAfterMs = retryAfterMs;
230
237
  }
231
238
  getUserMessage() {
232
239
  return "The service is temporarily unable to answer. Please retry.";
@@ -457,6 +464,14 @@ var _InvalidFieldTypeError = class _InvalidFieldTypeError extends BaseValidation
457
464
  __name(_InvalidFieldTypeError, "InvalidFieldTypeError");
458
465
  var InvalidFieldTypeError = _InvalidFieldTypeError;
459
466
 
467
+ // ../../platform/api-contract/dist/index.js
468
+ var HEADER_RETRY_AFTER = { name: "Retry-After" };
469
+ var HEADER_ENTITY_TAG = { name: "X-Entity-Tag" };
470
+ var HEADER_IF_MATCH = {
471
+ name: "If-Match"};
472
+ var HEADER_IDEMPOTENCY_KEY = {
473
+ name: "Idempotency-Key"};
474
+
460
475
  // ../../platform/api-contract/dist/client/index.js
461
476
  var _a;
462
477
  var ContractBodyError = (_a = class extends Error {
@@ -500,19 +515,47 @@ function readError(body) {
500
515
  }
501
516
  __name(readError, "readError");
502
517
 
518
+ // src/http/retry-after.ts
519
+ function headerValue(headers, name) {
520
+ if (headers === void 0) return void 0;
521
+ const wanted = name.toLowerCase();
522
+ for (const [key, value] of Object.entries(headers)) {
523
+ if (key.toLowerCase() === wanted) return value;
524
+ }
525
+ return void 0;
526
+ }
527
+ __name(headerValue, "headerValue");
528
+ function parseRetryAfterMs(value, nowMs) {
529
+ if (value === void 0) return void 0;
530
+ const trimmed = value.trim();
531
+ if (trimmed === "") return void 0;
532
+ if (/^\d+$/.test(trimmed)) {
533
+ return Number(trimmed) * 1e3;
534
+ }
535
+ if (!/[A-Za-z]/.test(trimmed)) return void 0;
536
+ const at = Date.parse(trimmed);
537
+ if (Number.isNaN(at)) return void 0;
538
+ return Math.max(0, at - nowMs);
539
+ }
540
+ __name(parseRetryAfterMs, "parseRetryAfterMs");
541
+
503
542
  // src/errors/error-mapper.ts
504
543
  var _ErrorMapper = class _ErrorMapper {
505
544
  /** Map a non-2xx response to an SDK error. */
506
545
  static mapHttpError(response, requestContext) {
507
- const { status, statusText, body } = response;
546
+ const { status, statusText, body, headers } = response;
508
547
  const refusal = readError(body);
509
548
  const context = { ...requestContext, response: body };
510
549
  if (refusal === void 0) {
511
550
  return new NetworkError(`HTTP ${status}: ${statusText}`.trim(), status, void 0, context);
512
551
  }
513
- return this.fromContractCode(refusal, status, context);
552
+ const retryAfterMs = parseRetryAfterMs(
553
+ headerValue(headers, HEADER_RETRY_AFTER.name),
554
+ Date.now()
555
+ );
556
+ return this.fromContractCode(refusal, status, context, retryAfterMs);
514
557
  }
515
- static fromContractCode(refusal, status, context) {
558
+ static fromContractCode(refusal, status, context, retryAfterMs) {
516
559
  const message = refusal.messages[0] ?? `RelyIO refused with ${refusal.code}`;
517
560
  switch (refusal.code) {
518
561
  case "MISSING_API_KEY": {
@@ -543,7 +586,8 @@ var _ErrorMapper = class _ErrorMapper {
543
586
  message,
544
587
  detailNumber(refusal, "limit"),
545
588
  detailString(refusal, "resetAt"),
546
- context
589
+ context,
590
+ retryAfterMs
547
591
  );
548
592
  }
549
593
  case "REQUEST_INVALID": {
@@ -586,7 +630,12 @@ var _ErrorMapper = class _ErrorMapper {
586
630
  );
587
631
  }
588
632
  case "SERVICE_INDETERMINATE": {
589
- return new ServiceIndeterminateError(message, detailString(refusal, "missing"), context);
633
+ return new ServiceIndeterminateError(
634
+ message,
635
+ detailString(refusal, "missing"),
636
+ context,
637
+ retryAfterMs
638
+ );
590
639
  }
591
640
  case "INTERNAL_ERROR": {
592
641
  return new ServerError(message, status, context);
@@ -628,12 +677,6 @@ var _ErrorMapper = class _ErrorMapper {
628
677
  }
629
678
  return error.name === "TypeError" && error.message.includes("fetch") || error.message.includes("timeout") || error.message.includes("Network Error") || error.message.includes("ECONNREFUSED");
630
679
  }
631
- /**
632
- * Extract retry delay from error
633
- */
634
- static getRetryDelay(_error) {
635
- return 0;
636
- }
637
680
  };
638
681
  __name(_ErrorMapper, "ErrorMapper");
639
682
  var ErrorMapper = _ErrorMapper;
@@ -692,13 +735,61 @@ function fillPath(template, params) {
692
735
  }
693
736
  __name(fillPath, "fillPath");
694
737
 
738
+ // src/http/retry-policy.ts
739
+ var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
740
+ "GET",
741
+ "HEAD",
742
+ "OPTIONS",
743
+ "PUT",
744
+ "DELETE",
745
+ "TRACE"
746
+ ]);
747
+ function isReplaySafe(request) {
748
+ if (IDEMPOTENT_METHODS.has(request.method.toUpperCase())) return true;
749
+ return headerValue(request.headers, HEADER_IDEMPOTENCY_KEY.name) !== void 0;
750
+ }
751
+ __name(isReplaySafe, "isReplaySafe");
752
+ function serviceInstructedDelayMs(error, nowMs) {
753
+ if (error instanceof ServiceIndeterminateError) {
754
+ return error.retryAfterMs;
755
+ }
756
+ if (!(error instanceof RateLimitError)) return void 0;
757
+ if (error.retryAfterMs !== void 0) return error.retryAfterMs;
758
+ if (error.resetAt === void 0) return void 0;
759
+ const resetAtMs = Date.parse(error.resetAt);
760
+ if (Number.isNaN(resetAtMs)) return void 0;
761
+ const wait = resetAtMs - nowMs;
762
+ return wait > 0 ? wait : void 0;
763
+ }
764
+ __name(serviceInstructedDelayMs, "serviceInstructedDelayMs");
765
+ var _DefaultRetryPolicy = class _DefaultRetryPolicy {
766
+ constructor(config) {
767
+ __publicField(this, "config");
768
+ this.config = config;
769
+ }
770
+ shouldRetry(attempt, error, request) {
771
+ if (attempt >= this.config.maxAttempts) return false;
772
+ if (!ErrorMapper.isRetryable(error)) return false;
773
+ return isReplaySafe(request);
774
+ }
775
+ delayFor(attempt, error) {
776
+ const instructed = serviceInstructedDelayMs(error, Date.now());
777
+ if (instructed !== void 0) return instructed;
778
+ const exponential = this.config.baseDelay * Math.pow(this.config.backoffFactor, attempt - 1);
779
+ const delay = Math.min(exponential, this.config.maxDelay);
780
+ return this.config.jitter ? delay * (0.5 + Math.random() * 0.5) : delay;
781
+ }
782
+ };
783
+ __name(_DefaultRetryPolicy, "DefaultRetryPolicy");
784
+ var DefaultRetryPolicy = _DefaultRetryPolicy;
785
+
695
786
  // src/http/http-client.ts
696
787
  var _HttpClient = class _HttpClient {
697
788
  constructor(config) {
698
789
  __publicField(this, "baseUrl");
699
790
  __publicField(this, "defaultHeaders");
700
791
  __publicField(this, "timeout");
701
- __publicField(this, "retryConfig");
792
+ __publicField(this, "retryPolicy");
702
793
  __publicField(this, "debug");
703
794
  __publicField(this, "logger");
704
795
  __publicField(this, "config");
@@ -719,16 +810,13 @@ var _HttpClient = class _HttpClient {
719
810
  const globalWithVersion = globalThis;
720
811
  this.defaultHeaders["User-Agent"] = `RelyIO-SDK/${globalWithVersion.__VERSION__ ?? "0.0.0"}`;
721
812
  }
722
- this.retryConfig = {
813
+ this.retryPolicy = new DefaultRetryPolicy({
723
814
  maxAttempts: config.retryAttempts,
724
815
  baseDelay: 1e3,
725
816
  maxDelay: 1e4,
726
817
  backoffFactor: 2,
727
- jitter: true,
728
- retryCondition: /* @__PURE__ */ __name((error, attempt) => {
729
- return ErrorMapper.isRetryable(error) && attempt < config.retryAttempts;
730
- }, "retryCondition")
731
- };
818
+ jitter: true
819
+ });
732
820
  this.log("debug", "HttpClient initialized", {
733
821
  baseUrl: this.baseUrl,
734
822
  timeout: this.timeout,
@@ -761,7 +849,16 @@ var _HttpClient = class _HttpClient {
761
849
  return readPayload(response.body);
762
850
  }
763
851
  /**
764
- * Make an HTTP request with retry logic
852
+ * Make an HTTP request, retrying only where a retry is safe.
853
+ *
854
+ * The headers are merged **once**, before the first attempt, and every attempt
855
+ * sends that same object. That is what makes a minted `Idempotency-Key` stable
856
+ * across the retries of one logical write: the service sees one key and
857
+ * answers the replay from the original outcome instead of applying it twice.
858
+ *
859
+ * The loop always makes one attempt. The incumbent's `while (attempt <
860
+ * maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
861
+ * accepts — and then dereferenced an unassigned `lastError`.
765
862
  */
766
863
  async request(config) {
767
864
  const mergedConfig = this.mergeRequestConfig(config);
@@ -770,14 +867,11 @@ var _HttpClient = class _HttpClient {
770
867
  url: mergedConfig.url
771
868
  // Show the final URL with query params
772
869
  });
773
- let lastError;
774
- let attempt = 0;
775
- while (attempt < this.retryConfig.maxAttempts) {
776
- attempt++;
870
+ if (config.method === "DELETE" && mergedConfig.headers) {
871
+ delete mergedConfig.headers["Content-Type"];
872
+ }
873
+ for (let attempt = 1; ; attempt++) {
777
874
  try {
778
- if (config.method === "DELETE" && mergedConfig.headers) {
779
- delete mergedConfig.headers["Content-Type"];
780
- }
781
875
  const response = await this.makeRequest(mergedConfig.url, mergedConfig);
782
876
  this.log("debug", "Request successful", {
783
877
  status: response.status,
@@ -786,31 +880,30 @@ var _HttpClient = class _HttpClient {
786
880
  });
787
881
  return response;
788
882
  } catch (error) {
789
- lastError = error;
883
+ const failure = error;
790
884
  this.log("warn", "Request failed", {
791
885
  error: error instanceof Error ? error.message : "Unknown error",
792
886
  attempt,
793
887
  url: mergedConfig.url
794
888
  });
795
- if (attempt < this.retryConfig.maxAttempts && this.retryConfig.retryCondition?.(lastError, attempt) === true) {
796
- const delay = this.calculateRetryDelay(attempt);
889
+ if (this.retryPolicy.shouldRetry(attempt, failure, mergedConfig)) {
890
+ const delay = this.retryPolicy.delayFor(attempt, failure);
797
891
  this.log("debug", "Retrying request", { attempt, delay });
798
892
  await this.sleep(delay);
799
893
  continue;
800
894
  }
801
- break;
895
+ const sdkError = ErrorMapper.mapGenericError(failure, {
896
+ url: mergedConfig.url,
897
+ method: mergedConfig.method,
898
+ attempt
899
+ });
900
+ this.log("error", "Request failed after all retries", {
901
+ error: sdkError.toJSON(),
902
+ url: mergedConfig.url
903
+ });
904
+ throw sdkError;
802
905
  }
803
906
  }
804
- const sdkError = ErrorMapper.mapGenericError(lastError, {
805
- url: mergedConfig.url,
806
- method: mergedConfig.method,
807
- attempt
808
- });
809
- this.log("error", "Request failed after all retries", {
810
- error: sdkError.toJSON(),
811
- url: mergedConfig.url
812
- });
813
- throw sdkError;
814
907
  }
815
908
  /**
816
909
  * Make a GET request
@@ -1058,14 +1151,6 @@ var _HttpClient = class _HttpClient {
1058
1151
  });
1059
1152
  return obj;
1060
1153
  }
1061
- calculateRetryDelay(attempt) {
1062
- const exponentialDelay = this.retryConfig.baseDelay * Math.pow(this.retryConfig.backoffFactor, attempt - 1);
1063
- const delay = Math.min(exponentialDelay, this.retryConfig.maxDelay);
1064
- if (this.retryConfig.jitter) {
1065
- return delay * (0.5 + Math.random() * 0.5);
1066
- }
1067
- return delay;
1068
- }
1069
1154
  sleep(ms) {
1070
1155
  return new Promise((resolve) => setTimeout(resolve, ms));
1071
1156
  }
@@ -1561,32 +1646,27 @@ var _ContentByIdBuilder = class _ContentByIdBuilder {
1561
1646
  __name(_ContentByIdBuilder, "ContentByIdBuilder");
1562
1647
  var ContentByIdBuilder = _ContentByIdBuilder;
1563
1648
 
1564
- // ../../platform/api-contract/dist/index.js
1565
- var HEADER_ENTITY_TAG = { name: "X-Entity-Tag" };
1566
- var HEADER_IF_MATCH = {
1567
- name: "If-Match"};
1568
- var HEADER_IDEMPOTENCY_KEY = {
1569
- name: "Idempotency-Key"};
1570
-
1571
1649
  // src/http/write-options.ts
1650
+ function mintIdempotencyKey() {
1651
+ const webCrypto = globalThis.crypto;
1652
+ if (typeof webCrypto?.randomUUID !== "function") return void 0;
1653
+ return webCrypto.randomUUID();
1654
+ }
1655
+ __name(mintIdempotencyKey, "mintIdempotencyKey");
1572
1656
  function writeHeaders(options) {
1573
- if (options === void 0) return void 0;
1574
1657
  const headers = {};
1575
- if ("ifMatch" in options && options.ifMatch !== void 0) {
1658
+ if (options !== void 0 && "ifMatch" in options && options.ifMatch !== void 0) {
1576
1659
  headers[HEADER_IF_MATCH.name] = options.ifMatch;
1577
1660
  }
1578
- if (options.idempotencyKey !== void 0) {
1579
- headers[HEADER_IDEMPOTENCY_KEY.name] = options.idempotencyKey;
1661
+ const idempotencyKey = options?.idempotencyKey ?? mintIdempotencyKey();
1662
+ if (idempotencyKey !== void 0) {
1663
+ headers[HEADER_IDEMPOTENCY_KEY.name] = idempotencyKey;
1580
1664
  }
1581
1665
  return Object.keys(headers).length > 0 ? headers : void 0;
1582
1666
  }
1583
1667
  __name(writeHeaders, "writeHeaders");
1584
1668
  function entityTagOf(response) {
1585
- const wanted = HEADER_ENTITY_TAG.name.toLowerCase();
1586
- for (const [name, value] of Object.entries(response.headers)) {
1587
- if (name.toLowerCase() === wanted) return value;
1588
- }
1589
- return void 0;
1669
+ return headerValue(response.headers, HEADER_ENTITY_TAG.name);
1590
1670
  }
1591
1671
  __name(entityTagOf, "entityTagOf");
1592
1672
 
@@ -3870,47 +3950,76 @@ function isProduction(proc) {
3870
3950
  return proc?.env?.NODE_ENV === "production";
3871
3951
  }
3872
3952
  __name(isProduction, "isProduction");
3873
- function resolveFromEnv(proc) {
3874
- const dataset = proc?.env?.RELYIO_DEV_DATASET;
3875
- const apiKey = proc?.env?.RELYIO_DEV_API_KEY;
3876
- if (dataset != null && dataset !== "" && apiKey != null && apiKey !== "") {
3877
- return { dataset, apiKey, source: "env" };
3953
+ function resolveFromEnv(proc, now) {
3954
+ const verdict = parseDevEnv(proc?.env, now);
3955
+ switch (verdict.state) {
3956
+ case "active":
3957
+ return {
3958
+ state: "active",
3959
+ override: {
3960
+ dataset: verdict.credentials.dataset,
3961
+ apiKey: verdict.credentials.apiKey,
3962
+ source: "env"
3963
+ }
3964
+ };
3965
+ case "expired":
3966
+ return { state: "expired", expiredAt: verdict.expiredAt };
3967
+ case "unreadable":
3968
+ return { state: "unreadable", reason: verdict.reason };
3969
+ case "absent":
3970
+ return { state: "absent" };
3878
3971
  }
3879
- return null;
3880
3972
  }
3881
3973
  __name(resolveFromEnv, "resolveFromEnv");
3882
- function resolveFromFile(proc) {
3883
- if (proc == null || typeof proc.cwd !== "function") return null;
3974
+ function resolveFromFile(proc, now) {
3975
+ if (proc == null || typeof proc.cwd !== "function") return { state: "absent" };
3884
3976
  const fs = getBuiltin(proc, "node:fs");
3885
3977
  const path = getBuiltin(proc, "node:path");
3886
- if (fs == null || path == null) return null;
3978
+ if (fs == null || path == null) return { state: "absent" };
3887
3979
  let dir = proc.cwd();
3888
3980
  for (; ; ) {
3889
- const candidate = path.join(dir, ".relyio", "dev.json");
3981
+ const candidate = path.join(dir, DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME);
3982
+ let raw = null;
3890
3983
  try {
3891
- if (fs.existsSync(candidate)) {
3892
- const parsed = JSON.parse(fs.readFileSync(candidate, "utf8"));
3893
- if (parsed.datasetId != null && parsed.datasetId !== "" && parsed.previewApiKey != null && parsed.previewApiKey !== "") {
3894
- if (parsed.expiresAt != null && Number.isFinite(new Date(parsed.expiresAt).getTime()) && new Date(parsed.expiresAt).getTime() < Date.now()) {
3895
- return null;
3896
- }
3897
- return { dataset: parsed.datasetId, apiKey: parsed.previewApiKey, source: "file" };
3898
- }
3899
- }
3984
+ if (fs.existsSync(candidate)) raw = fs.readFileSync(candidate, "utf8");
3900
3985
  } catch {
3986
+ return { state: "absent" };
3987
+ }
3988
+ if (raw !== null) {
3989
+ const verdict = parseDevContextFile(raw, now);
3990
+ switch (verdict.state) {
3991
+ case "active":
3992
+ return {
3993
+ state: "active",
3994
+ override: {
3995
+ dataset: verdict.context.datasetId,
3996
+ apiKey: verdict.context.previewApiKey,
3997
+ source: "file"
3998
+ }
3999
+ };
4000
+ case "expired":
4001
+ return { state: "expired", expiredAt: verdict.expiredAt };
4002
+ case "unreadable":
4003
+ return { state: "unreadable", reason: verdict.reason };
4004
+ case "absent":
4005
+ return { state: "absent" };
4006
+ }
3901
4007
  }
3902
4008
  const parent = path.dirname(dir);
3903
4009
  if (parent === dir) break;
3904
4010
  dir = parent;
3905
4011
  }
3906
- return null;
4012
+ return { state: "absent" };
3907
4013
  }
3908
4014
  __name(resolveFromFile, "resolveFromFile");
3909
4015
  function resolveDevOverride(dev) {
3910
- if (dev === false) return null;
4016
+ if (dev === false) return { state: "disabled" };
3911
4017
  const proc = getProcess();
3912
- if (dev !== true && isProduction(proc)) return null;
3913
- return resolveFromEnv(proc) ?? resolveFromFile(proc);
4018
+ if (dev !== true && isProduction(proc)) return { state: "disabled" };
4019
+ const now = Date.now();
4020
+ const fromEnv = resolveFromEnv(proc, now);
4021
+ if (fromEnv.state !== "absent") return fromEnv;
4022
+ return resolveFromFile(proc, now);
3914
4023
  }
3915
4024
  __name(resolveDevOverride, "resolveDevOverride");
3916
4025
 
@@ -3993,16 +4102,26 @@ function mergeConfig(userConfig) {
3993
4102
  ...userConfig.debug
3994
4103
  }
3995
4104
  };
3996
- const devOverride = resolveDevOverride(userConfig.dev);
3997
- if (devOverride != null) {
3998
- merged.apiKey = devOverride.apiKey;
3999
- merged.dataset = devOverride.dataset;
4105
+ const dev = resolveDevOverride(userConfig.dev);
4106
+ if (dev.state === "active") {
4107
+ merged.apiKey = dev.override.apiKey;
4108
+ merged.dataset = dev.override.dataset;
4000
4109
  if (!devOverrideNotified) {
4001
4110
  devOverrideNotified = true;
4002
4111
  console.info(
4003
- `[RelyIO] Sandbox dev mode active (${devOverride.source}) \u2014 targeting dataset "${devOverride.dataset}" with a scoped preview key.`
4112
+ `[RelyIO] Sandbox dev mode active (${dev.override.source}) \u2014 targeting dataset "${dev.override.dataset}" with a scoped preview key.`
4004
4113
  );
4005
4114
  }
4115
+ } else if (dev.state === "expired" && !devOverrideNotified) {
4116
+ devOverrideNotified = true;
4117
+ console.warn(
4118
+ `[RelyIO] Your sandbox's .relyio/dev.json expired at ${dev.expiredAt} \u2014 ignoring it and using the configured dataset "${merged.dataset}". Run \`relyio dev\` to refresh it.`
4119
+ );
4120
+ } else if (dev.state === "unreadable" && !devOverrideNotified) {
4121
+ devOverrideNotified = true;
4122
+ console.warn(
4123
+ `[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.`
4124
+ );
4006
4125
  }
4007
4126
  return merged;
4008
4127
  }
@@ -4371,5 +4490,5 @@ function createClient(config) {
4371
4490
  __name(createClient, "createClient");
4372
4491
 
4373
4492
  export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthenticationError, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidFieldTypeError, InvalidPayloadError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, RequiredFieldError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SchemaValidationError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, entityTagOf, isAssetEntry, isResourceNotFound, validateFile };
4374
- //# sourceMappingURL=chunk-RJBIJ2ZK.js.map
4375
- //# sourceMappingURL=chunk-RJBIJ2ZK.js.map
4493
+ //# sourceMappingURL=chunk-QIZOBT5F.js.map
4494
+ //# sourceMappingURL=chunk-QIZOBT5F.js.map
@@ -1,17 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var chunk7W4MJXQ4_cjs = require('../chunk-7W4MJXQ4.cjs');
3
+ var chunk54WP2PWG_cjs = require('../chunk-54WP2PWG.cjs');
4
+ require('../chunk-LSRPMNPT.cjs');
4
5
  require('../chunk-MWMSFIWN.cjs');
5
6
 
6
7
 
7
8
 
8
9
  Object.defineProperty(exports, "TypedRelyIOClient", {
9
10
  enumerable: true,
10
- get: function () { return chunk7W4MJXQ4_cjs.TypedRelyIOClient; }
11
+ get: function () { return chunk54WP2PWG_cjs.TypedRelyIOClient; }
11
12
  });
12
13
  Object.defineProperty(exports, "createClient", {
13
14
  enumerable: true,
14
- get: function () { return chunk7W4MJXQ4_cjs.createClient; }
15
+ get: function () { return chunk54WP2PWG_cjs.createClient; }
15
16
  });
16
17
  //# sourceMappingURL=index.cjs.map
17
18
  //# sourceMappingURL=index.cjs.map
@@ -1,3 +1,4 @@
1
- export { C as ClientSchema, a as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-DGWaawHt.cjs';
2
- import '../index-BsUqCAu8.cjs';
3
- import '../define-schema-DHvUCKwj.cjs';
1
+ export { C as ClientSchema, a as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-BDpar3FO.cjs';
2
+ import '../index-ulOrcfPa.cjs';
3
+ import '../define-content-type-CBfnTWSS.cjs';
4
+ import '../define-schema-BfXeR6K8.cjs';
@@ -1,3 +1,4 @@
1
- export { C as ClientSchema, a as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-B-KiFHbx.js';
2
- import '../index-BsUqCAu8.js';
3
- import '../define-schema-DHvUCKwj.js';
1
+ export { C as ClientSchema, a as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-Dx01iwaf.js';
2
+ import '../index-DuEhsGdE.js';
3
+ import '../define-content-type-CBfnTWSS.js';
4
+ import '../define-schema-BD6HSPnG.js';
@@ -1,4 +1,5 @@
1
- export { TypedRelyIOClient, createClient } from '../chunk-RJBIJ2ZK.js';
1
+ export { TypedRelyIOClient, createClient } from '../chunk-QIZOBT5F.js';
2
+ import '../chunk-BBUB7C2Z.js';
2
3
  import '../chunk-XQ4QHWZE.js';
3
4
  //# sourceMappingURL=index.js.map
4
5
  //# sourceMappingURL=index.js.map