@coinlist-co/react 0.12.2-rc.7b430dd → 0.12.2-rc.8a0d02a

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 (31) hide show
  1. package/dist/{chunk-DCW7NQXH.js → chunk-3WW5FLT7.js} +52 -19
  2. package/dist/chunk-3WW5FLT7.js.map +1 -0
  3. package/dist/{chunk-MOE5S6CE.js → chunk-C6GF7MDF.js} +915 -458
  4. package/dist/chunk-C6GF7MDF.js.map +1 -0
  5. package/dist/{chunk-VH34YC3Q.js → chunk-IZJ4JSSC.js} +78 -4
  6. package/dist/chunk-IZJ4JSSC.js.map +1 -0
  7. package/dist/client/index.cjs +12103 -8452
  8. package/dist/client/index.cjs.map +1 -1
  9. package/dist/client/index.d.cts +1640 -37
  10. package/dist/client/index.d.ts +1640 -37
  11. package/dist/client/index.js +7923 -4800
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/server/index.cjs +789 -142
  14. package/dist/server/index.cjs.map +1 -1
  15. package/dist/server/index.d.cts +69 -41
  16. package/dist/server/index.d.ts +69 -41
  17. package/dist/server/index.js +323 -65
  18. package/dist/server/index.js.map +1 -1
  19. package/dist/{tokens-namespace-CIWBtgt2.d.cts → time-CVZpAkGY.d.cts} +878 -192
  20. package/dist/{tokens-namespace-CIWBtgt2.d.ts → time-CVZpAkGY.d.ts} +878 -192
  21. package/dist/{token-registry-snapshot-BNBNuDu1.d.ts → token-registry-snapshot-BkwA8KmD.d.ts} +74 -8
  22. package/dist/{token-registry-snapshot-CqI6dXM_.d.cts → token-registry-snapshot-bR14QehS.d.cts} +74 -8
  23. package/dist/universal/index.cjs +982 -448
  24. package/dist/universal/index.cjs.map +1 -1
  25. package/dist/universal/index.d.cts +91 -5
  26. package/dist/universal/index.d.ts +91 -5
  27. package/dist/universal/index.js +44 -2
  28. package/package.json +1 -1
  29. package/dist/chunk-DCW7NQXH.js.map +0 -1
  30. package/dist/chunk-MOE5S6CE.js.map +0 -1
  31. package/dist/chunk-VH34YC3Q.js.map +0 -1
@@ -20,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/server/index.ts
21
21
  var server_exports = {};
22
22
  __export(server_exports, {
23
- ServerAuthNamespaceImpl: () => ServerAuthNamespaceImpl,
24
23
  ServerOffersNamespaceImpl: () => ServerOffersNamespaceImpl,
25
24
  ServerRequirementsNamespaceImpl: () => ServerRequirementsNamespaceImpl,
26
25
  WritableSessionStoreRequiredError: () => WritableSessionStoreRequiredError,
@@ -30,6 +29,30 @@ __export(server_exports, {
30
29
  });
31
30
  module.exports = __toCommonJS(server_exports);
32
31
 
32
+ // src/universal/api/internal-access-token-source.ts
33
+ var SentWith = {
34
+ userToken: (token) => ({
35
+ type: "user-token",
36
+ token
37
+ }),
38
+ noUserToken: { type: "no-user-token" }
39
+ };
40
+ var TokenTrigger = {
41
+ beforeRequest: { type: "before-request" },
42
+ after401: (rejected) => ({
43
+ type: "after-401",
44
+ rejected
45
+ })
46
+ };
47
+ function isRejectedToken(token, rejected) {
48
+ switch (rejected.type) {
49
+ case "user-token":
50
+ return rejected.token.value === token.value;
51
+ case "no-user-token":
52
+ return false;
53
+ }
54
+ }
55
+
33
56
  // src/universal/api/http-attributes.ts
34
57
  var empty = {};
35
58
  var concat = (left, right) => ({
@@ -57,6 +80,10 @@ var retryAttempt = (attempt) => ({
57
80
  var renewAttempted = (value) => ({
58
81
  renewAttempted: value
59
82
  });
83
+ var notRetryable = () => ({ retryable: false });
84
+ var sentWith = (token) => ({
85
+ sentWith: token
86
+ });
60
87
  var requestId = (id) => ({ requestId: id });
61
88
  var getRequestId = (attrs) => attrs?.requestId ?? null;
62
89
  var isProtected = (attrs) => attrs?.protected === true;
@@ -64,6 +91,8 @@ var needUserAgent = (attrs) => attrs?.userAgent === true;
64
91
  var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
65
92
  var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
66
93
  var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
94
+ var isRetryable = (attrs) => attrs?.retryable !== false;
95
+ var getSentWith = (attrs) => attrs?.sentWith === void 0 ? SentWith.noUserToken : SentWith.userToken(attrs.sentWith);
67
96
  var getClientCredentials = (attrs) => attrs?.clientCredentials;
68
97
  var Attributes = {
69
98
  empty,
@@ -79,6 +108,10 @@ var Attributes = {
79
108
  getRetryAttempt,
80
109
  renewAttempted,
81
110
  wasRenewAttempted,
111
+ notRetryable,
112
+ isRetryable,
113
+ sentWith,
114
+ getSentWith,
82
115
  clientCredentials,
83
116
  getClientCredentials,
84
117
  requestId,
@@ -448,11 +481,18 @@ var HttpClient = class {
448
481
  );
449
482
  let response = await this.executeRequest(preparedRequest);
450
483
  for (const middleware of this.middleware.afterRequest ?? []) {
484
+ let retried = false;
451
485
  response = await middleware({
452
486
  request: preparedRequest,
453
487
  response,
454
- retry: (nextRequest = preparedRequest) => this.runRequestWithAfterMiddleware(nextRequest)
488
+ retry: (nextRequest = preparedRequest) => {
489
+ retried = true;
490
+ return this.runRequestWithAfterMiddleware(nextRequest);
491
+ }
455
492
  });
493
+ if (retried) {
494
+ return response;
495
+ }
456
496
  }
457
497
  return response;
458
498
  }
@@ -585,23 +625,33 @@ function attachSessionMiddleware(fetchAccessToken) {
585
625
  if (!Attributes.isProtected(request.attributes)) {
586
626
  return request;
587
627
  }
588
- let accessToken = await fetchAccessToken(false);
589
- if (!accessToken) {
590
- const clientCreds = Attributes.getClientCredentials(request.attributes);
591
- if (clientCreds) {
592
- accessToken = clientCreds;
593
- }
628
+ const userToken = await fetchAccessToken(TokenTrigger.beforeRequest);
629
+ if (userToken !== null) {
630
+ return withBearer(
631
+ {
632
+ ...request,
633
+ attributes: Attributes.concat(
634
+ request.attributes ?? Attributes.empty,
635
+ Attributes.sentWith(userToken)
636
+ )
637
+ },
638
+ userToken.value
639
+ );
594
640
  }
595
- if (accessToken === null) {
596
- return request;
641
+ const clientCreds = Attributes.getClientCredentials(request.attributes);
642
+ if (clientCreds) {
643
+ return withBearer(request, clientCreds.value);
644
+ }
645
+ return request;
646
+ };
647
+ }
648
+ function withBearer(request, token) {
649
+ return {
650
+ ...request,
651
+ headers: {
652
+ ...request.headers ?? {},
653
+ Authorization: `Bearer ${token}`
597
654
  }
598
- return {
599
- ...request,
600
- headers: {
601
- ...request.headers ?? {},
602
- Authorization: `Bearer ${accessToken.value}`
603
- }
604
- };
605
655
  };
606
656
  }
607
657
 
@@ -660,7 +710,7 @@ function getRetryDelayMs(attempt) {
660
710
  function createRequestRetryMiddleware(options = {}) {
661
711
  const delayFn = options.delayFn ?? defaultDelay;
662
712
  return async ({ request, response, retry }) => {
663
- if (!isRetryableStatus(response.status)) {
713
+ if (!isRetryableStatus(response.status) || !Attributes.isRetryable(request.attributes)) {
664
714
  return response;
665
715
  }
666
716
  const currentAttempt = Attributes.getRetryAttempt(request.attributes);
@@ -693,7 +743,9 @@ function renewSessionMiddleware(fetchAccessToken) {
693
743
  if (Attributes.wasRenewAttempted(request.attributes)) {
694
744
  return response;
695
745
  }
696
- const newToken = await fetchAccessToken(true);
746
+ const newToken = await fetchAccessToken(
747
+ TokenTrigger.after401(Attributes.getSentWith(request.attributes))
748
+ );
697
749
  if (newToken) {
698
750
  const nextRequest = Request.concatAttributes(
699
751
  request,
@@ -750,6 +802,158 @@ var ApiClient = class {
750
802
  }
751
803
  };
752
804
 
805
+ // src/universal/types/time.ts
806
+ var MAX_EPOCH_MILLIS = 864e13;
807
+ var EpochMillis = {
808
+ /**
809
+ * @throws {@link ValidationError} unless `value` is an integer a `Date` can
810
+ * represent: at most {@link MAX_EPOCH_MILLIS} either side of the epoch.
811
+ */
812
+ of: (value) => {
813
+ if (!Number.isInteger(value) || Math.abs(value) > MAX_EPOCH_MILLIS) {
814
+ throw new ValidationError(
815
+ `EpochMillis must be an integer within \xB1${MAX_EPOCH_MILLIS}, got ${value}`
816
+ );
817
+ }
818
+ return value;
819
+ },
820
+ /** The wall clock. Code that needs the time takes a `TimeEff` instead. */
821
+ now: () => EpochMillis.of(Date.now()),
822
+ /** @throws {@link ValidationError} for an invalid `Date`. */
823
+ fromDate: (date) => EpochMillis.of(date.getTime()),
824
+ /** How long after `from` the instant `to` is; negative if it is before. */
825
+ elapsed: (from, to) => Millis.of(to - from),
826
+ plus: (at, duration) => EpochMillis.of(at + duration)
827
+ };
828
+ var Millis = {
829
+ of: (value) => value
830
+ };
831
+ var Seconds = {
832
+ /**
833
+ * @throws {@link ValidationError} unless `value` is a non-negative integer.
834
+ */
835
+ of: (value) => {
836
+ if (!Number.isInteger(value) || value < 0) {
837
+ throw new ValidationError(
838
+ `Seconds must be a non-negative integer, got ${value}`
839
+ );
840
+ }
841
+ return value;
842
+ },
843
+ toMillis: (value) => Millis.of(value * 1e3)
844
+ };
845
+ function isExpired({
846
+ expiresAt,
847
+ now,
848
+ buffer = Millis.of(0)
849
+ }) {
850
+ return now >= expiresAt - buffer;
851
+ }
852
+
853
+ // src/universal/core/shared/effects.ts
854
+ var systemTime = { time: { now: EpochMillis.now } };
855
+
856
+ // src/server/core/session-refresh.ts
857
+ var VERDICT_MIN_GAP = Millis.of(5e3);
858
+ var REJECTION_MEMORY = Millis.of(6e4);
859
+ var RefreshKey = {
860
+ of: ({
861
+ clientId,
862
+ session
863
+ }) => {
864
+ const identity = session.refreshToken === void 0 ? ["access", session.accessToken.value] : ["refresh", session.refreshToken];
865
+ return JSON.stringify([clientId, ...identity]);
866
+ }
867
+ };
868
+ var RefreshCoordinator = class {
869
+ constructor(env = systemTime) {
870
+ this.env = env;
871
+ this.inFlight = /* @__PURE__ */ new Map();
872
+ this.rejections = /* @__PURE__ */ new Map();
873
+ }
874
+ /**
875
+ * Runs `exchange` for `key` unless one is already in flight, in which case
876
+ * the caller joins it. `joined` tells the caller whether it led: only the
877
+ * leader reports the outcome, so a burst of N produces one verdict, one log
878
+ * line and one `onSessionExpired`.
879
+ */
880
+ refresh(key, exchange) {
881
+ const existing = this.inFlight.get(key);
882
+ if (existing !== void 0) {
883
+ return { outcome: existing, joined: true };
884
+ }
885
+ const outcome = this.run(key, exchange).finally(() => {
886
+ this.inFlight.delete(key);
887
+ });
888
+ this.inFlight.set(key, outcome);
889
+ return { outcome, joined: false };
890
+ }
891
+ async run(key, exchange) {
892
+ this.forgetStale(this.env.time.now());
893
+ if (this.rejections.get(key)?.type === "expired") {
894
+ return { type: "already-expired" };
895
+ }
896
+ const result = await exchange();
897
+ switch (result.type) {
898
+ case "renewed":
899
+ case "unknown":
900
+ return result;
901
+ case "rejected":
902
+ case "unrenewable": {
903
+ const judged = judge({
904
+ result: result.type,
905
+ prior: this.rejections.get(key),
906
+ now: this.env.time.now()
907
+ });
908
+ this.rejections.set(key, judged.memory);
909
+ return { type: judged.outcome };
910
+ }
911
+ }
912
+ }
913
+ forgetStale(now) {
914
+ for (const [key, rejection] of this.rejections) {
915
+ if (EpochMillis.elapsed(rejectedAt(rejection), now) > REJECTION_MEMORY) {
916
+ this.rejections.delete(key);
917
+ }
918
+ }
919
+ }
920
+ };
921
+ function judge({
922
+ result,
923
+ prior,
924
+ now
925
+ }) {
926
+ const verdict = {
927
+ outcome: "expired",
928
+ memory: { type: "expired", at: now }
929
+ };
930
+ switch (result) {
931
+ case "unrenewable":
932
+ return verdict;
933
+ case "rejected":
934
+ switch (prior?.type) {
935
+ case void 0:
936
+ return {
937
+ outcome: "suspected",
938
+ memory: { type: "suspected", since: now }
939
+ };
940
+ case "suspected":
941
+ return EpochMillis.elapsed(prior.since, now) >= VERDICT_MIN_GAP ? verdict : { outcome: "suspected", memory: prior };
942
+ case "expired":
943
+ return { outcome: "expired", memory: prior };
944
+ }
945
+ }
946
+ }
947
+ function rejectedAt(rejection) {
948
+ switch (rejection.type) {
949
+ case "suspected":
950
+ return rejection.since;
951
+ case "expired":
952
+ return rejection.at;
953
+ }
954
+ }
955
+ var processRefreshCoordinator = new RefreshCoordinator();
956
+
753
957
  // src/server/shared/errors.ts
754
958
  var WritableSessionStoreRequiredError = class extends Error {
755
959
  constructor(message = "This operation requires a writable SessionStore. Provide a `setSession` implementation in your SessionStore to persist or clear OAuth sessions.") {
@@ -758,6 +962,16 @@ var WritableSessionStoreRequiredError = class extends Error {
758
962
  }
759
963
  };
760
964
 
965
+ // src/universal/core/auth/session-expired.ts
966
+ function notifySessionExpired(onSessionExpired, log) {
967
+ if (onSessionExpired === void 0) {
968
+ return;
969
+ }
970
+ Promise.resolve().then(onSessionExpired).catch(
971
+ (error) => log.failure(() => ({ msg: "onSessionExpired threw" }), error)
972
+ );
973
+ }
974
+
761
975
  // src/universal/types/oauth-session.ts
762
976
  var ClientCredentialsOAuth = (value) => value;
763
977
  var OAuthRefreshToken = (value) => value;
@@ -774,10 +988,7 @@ var OAuthSession = {
774
988
  }
775
989
  };
776
990
 
777
- // src/server/core/server-auth-namespace.ts
778
- function emptySessionStore() {
779
- return { getSession: async () => null };
780
- }
991
+ // src/server/core/server-auth-namespace-impl.ts
781
992
  var ServerAuthNamespaceImpl = class {
782
993
  constructor(api, config) {
783
994
  this.api = api;
@@ -797,7 +1008,8 @@ var ServerAuthNamespaceImpl = class {
797
1008
  client_id: this.config.clientId,
798
1009
  client_secret: this.config.clientSecret,
799
1010
  code_verifier: params.codeVerifier
800
- }
1011
+ },
1012
+ attributes: Attributes.notRetryable()
801
1013
  });
802
1014
  const session = OAuthSession.fromDto(sessionDto);
803
1015
  await setSession(session);
@@ -805,39 +1017,118 @@ var ServerAuthNamespaceImpl = class {
805
1017
  });
806
1018
  }
807
1019
  async getAccessToken() {
1020
+ return this.tokenFor(TokenTrigger.beforeRequest);
1021
+ }
1022
+ /**
1023
+ * {@link getAccessToken} with the reason the SDK is asking, which is what
1024
+ * the authenticated HTTP pipeline calls: after a 401 the token's own expiry
1025
+ * no longer matters, because the API has answered for it.
1026
+ */
1027
+ async tokenFor(trigger) {
808
1028
  return this.log.wrap(
809
1029
  "getAccessToken",
810
1030
  void 0,
811
- () => this.readAccessToken()
1031
+ () => this.readAccessToken(trigger)
812
1032
  );
813
1033
  }
814
- async readAccessToken() {
1034
+ async readAccessToken(trigger) {
815
1035
  const sessionStore = this.config.sessionStore;
816
- const session = await sessionStore.getSession();
817
- if (session == null) return null;
818
- const now = Date.now();
819
- const expiresAt = session.accessToken.expiresAt.getTime();
820
- const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1e3;
821
- if (expiresAt > now + bufferMs) {
822
- return session.accessToken;
823
- }
824
- const setSession = sessionStore.setSession?.bind(sessionStore);
825
- if (!setSession) {
826
- this.log.child({ op: "getAccessToken" }).warn(() => ({
827
- msg: "serving an expired token: the session store is read-only, so it cannot be refreshed"
828
- }));
829
- return session.accessToken;
1036
+ const classification = classifyAccessToken({
1037
+ session: await sessionStore.getSession(),
1038
+ store: sessionStoreAccess(sessionStore),
1039
+ trigger,
1040
+ now: this.config.time.now(),
1041
+ buffer: Seconds.toMillis(this.config.accessTokenExpiryBufferSeconds)
1042
+ });
1043
+ switch (classification.type) {
1044
+ case "no-session":
1045
+ case "refuse":
1046
+ return null;
1047
+ case "serve":
1048
+ return classification.token;
1049
+ case "serve-stale":
1050
+ this.log.child({ op: "getAccessToken" }).warn(() => ({
1051
+ msg: "serving an expired token: the session store is read-only, so it cannot be refreshed"
1052
+ }));
1053
+ return classification.token;
1054
+ case "refresh":
1055
+ return this.refresh(classification);
830
1056
  }
831
- return this.refreshSession(session.refreshToken, setSession);
832
1057
  }
833
- async refreshSession(refreshToken, setSession) {
1058
+ /**
1059
+ * Refreshes through the process-wide coordinator, then acts on the outcome
1060
+ * for this caller's own store. The store is written before anything is
1061
+ * logged or the host is notified, so `onSessionExpired` always finds it
1062
+ * cleared.
1063
+ */
1064
+ async refresh({
1065
+ session,
1066
+ setSession,
1067
+ fallback
1068
+ }) {
834
1069
  const log = this.log.child({ op: "refresh" });
835
- if (!refreshToken) {
836
- log.warn(() => ({
837
- msg: "clearing the session: it carries no refresh token"
838
- }));
839
- await setSession(null);
840
- return null;
1070
+ const key = RefreshKey.of({ clientId: this.config.clientId, session });
1071
+ const { outcome, joined } = this.config.refreshes.refresh(
1072
+ key,
1073
+ () => this.exchange(session.refreshToken)
1074
+ );
1075
+ if (joined) {
1076
+ log.debug(() => ({ msg: "joined a refresh already in flight" }));
1077
+ }
1078
+ const result = await outcome;
1079
+ switch (result.type) {
1080
+ case "renewed":
1081
+ await setSession(result.session);
1082
+ if (!joined) {
1083
+ log.info(() => ({ msg: "session renewed" }));
1084
+ }
1085
+ return result.session.accessToken;
1086
+ case "suspected":
1087
+ if (!joined) {
1088
+ log.warn(() => ({
1089
+ msg: "refresh rejected; not clearing until it is confirmed"
1090
+ }));
1091
+ }
1092
+ return fallback;
1093
+ case "expired":
1094
+ await setSession(null);
1095
+ if (!joined) {
1096
+ log.info(() => ({
1097
+ msg: "session expired",
1098
+ fields: {
1099
+ reason: session.refreshToken === void 0 ? "no-refresh-token" : "refresh-rejected"
1100
+ }
1101
+ }));
1102
+ notifySessionExpired(this.config.onSessionExpired, log);
1103
+ }
1104
+ return null;
1105
+ case "already-expired":
1106
+ await setSession(null);
1107
+ return null;
1108
+ case "unknown":
1109
+ if (fallback === null) {
1110
+ throw result.error;
1111
+ }
1112
+ if (!joined) {
1113
+ log.warning(
1114
+ () => ({ msg: "refresh failed; serving the current token" }),
1115
+ result.error
1116
+ );
1117
+ }
1118
+ return fallback;
1119
+ }
1120
+ }
1121
+ /**
1122
+ * One `POST /oauth/token`, total: every failure comes back as a value, so
1123
+ * the coordinator can judge it once for everyone who joined.
1124
+ *
1125
+ * Never retried. The refresh token is single-use, so a retry of an attempt
1126
+ * that reached the server would present a token already rotated away, and
1127
+ * its `invalid_grant` would be judged as a rejection of the session.
1128
+ */
1129
+ async exchange(refreshToken) {
1130
+ if (refreshToken === void 0) {
1131
+ return { type: "unrenewable" };
841
1132
  }
842
1133
  try {
843
1134
  const sessionDto = await this.api.send({
@@ -848,19 +1139,12 @@ var ServerAuthNamespaceImpl = class {
848
1139
  refresh_token: refreshToken,
849
1140
  client_id: this.config.clientId,
850
1141
  client_secret: this.config.clientSecret
851
- }
1142
+ },
1143
+ attributes: Attributes.notRetryable()
852
1144
  });
853
- const newSession = OAuthSession.fromDto(sessionDto);
854
- await setSession(newSession);
855
- log.info(() => ({ msg: "session renewed" }));
856
- return newSession.accessToken;
1145
+ return { type: "renewed", session: OAuthSession.fromDto(sessionDto) };
857
1146
  } catch (error) {
858
- log.failure(
859
- () => ({ msg: "refresh failed; clearing the session" }),
860
- error
861
- );
862
- await setSession(null);
863
- return null;
1147
+ return isInvalidGrant(error) ? { type: "rejected" } : { type: "unknown", error };
864
1148
  }
865
1149
  }
866
1150
  async clientCredentials() {
@@ -896,28 +1180,102 @@ var ServerAuthNamespaceImpl = class {
896
1180
  }
897
1181
  });
898
1182
  } catch (err) {
899
- if (!(err instanceof HttpError) || this.config.strict) {
1183
+ if (this.config.strict) {
900
1184
  throw err;
901
1185
  }
902
- this.log.child({ op: "logout" }).warn(() => ({
903
- msg: "the token was not revoked upstream; the local session is cleared regardless"
904
- }));
1186
+ this.log.child({ op: "logout" }).warning(
1187
+ () => ({ msg: "revoke failed; local session cleared regardless" }),
1188
+ err
1189
+ );
905
1190
  }
906
1191
  await setSession(null);
907
1192
  }
908
1193
  /**
909
- * Returns the store's `setSession`, or throws — the guard every
1194
+ * Returns the store's `setSession`, or throws - the guard every
910
1195
  * session-writing operation shares.
911
1196
  */
912
1197
  writableSessionStore() {
913
- const sessionStore = this.config.sessionStore;
914
- const setSession = sessionStore.setSession?.bind(sessionStore);
915
- if (!setSession) {
916
- throw new WritableSessionStoreRequiredError();
1198
+ const store = sessionStoreAccess(this.config.sessionStore);
1199
+ switch (store.type) {
1200
+ case "writable":
1201
+ return store.setSession;
1202
+ case "read-only":
1203
+ throw new WritableSessionStoreRequiredError();
917
1204
  }
918
- return setSession;
919
1205
  }
920
1206
  };
1207
+ function classifyAccessToken({
1208
+ session,
1209
+ store,
1210
+ trigger,
1211
+ now,
1212
+ buffer
1213
+ }) {
1214
+ if (session === null) {
1215
+ return { type: "no-session" };
1216
+ }
1217
+ const token = session.accessToken;
1218
+ const stale = isExpired({
1219
+ expiresAt: EpochMillis.fromDate(token.expiresAt),
1220
+ now,
1221
+ buffer
1222
+ });
1223
+ switch (store.type) {
1224
+ case "read-only":
1225
+ return classifyReadOnly(token, trigger, stale);
1226
+ case "writable": {
1227
+ if (!needsRefresh(token, trigger, stale)) {
1228
+ return { type: "serve", token };
1229
+ }
1230
+ const fallback = fallbackToken(token, trigger, now);
1231
+ return session.refreshToken === void 0 && fallback !== null ? { type: "serve", token: fallback } : {
1232
+ type: "refresh",
1233
+ session,
1234
+ setSession: store.setSession,
1235
+ fallback
1236
+ };
1237
+ }
1238
+ }
1239
+ }
1240
+ function classifyReadOnly(token, trigger, stale) {
1241
+ switch (trigger.type) {
1242
+ case "after-401":
1243
+ return isRejectedToken(token, trigger.rejected) ? { type: "refuse" } : { type: "serve", token };
1244
+ case "before-request":
1245
+ return stale ? { type: "serve-stale", token } : { type: "serve", token };
1246
+ }
1247
+ }
1248
+ function sessionStoreAccess(sessionStore) {
1249
+ const setSession = sessionStore.setSession?.bind(sessionStore);
1250
+ return setSession === void 0 ? { type: "read-only" } : { type: "writable", setSession };
1251
+ }
1252
+ function needsRefresh(token, trigger, stale) {
1253
+ switch (trigger.type) {
1254
+ case "before-request":
1255
+ return stale;
1256
+ case "after-401":
1257
+ return trigger.rejected.type === "no-user-token" || isRejectedToken(token, trigger.rejected) || stale;
1258
+ }
1259
+ }
1260
+ function fallbackToken(token, trigger, now) {
1261
+ const unexpired = !isExpired({
1262
+ expiresAt: EpochMillis.fromDate(token.expiresAt),
1263
+ now
1264
+ });
1265
+ switch (trigger.type) {
1266
+ case "after-401":
1267
+ return unexpired && !isRejectedToken(token, trigger.rejected) ? token : null;
1268
+ case "before-request":
1269
+ return unexpired ? token : null;
1270
+ }
1271
+ }
1272
+ function isInvalidGrant(error) {
1273
+ if (!(error instanceof HttpError) || error.response.status !== 400) {
1274
+ return false;
1275
+ }
1276
+ const body = error.response.body;
1277
+ return typeof body === "object" && body !== null && "error" in body && body.error === "invalid_grant";
1278
+ }
921
1279
 
922
1280
  // src/universal/api/pagination.ts
923
1281
  async function fetchAllPages(fetchPage, baseParams) {
@@ -935,40 +1293,6 @@ async function fetchAllPages(fetchPage, baseParams) {
935
1293
  return items;
936
1294
  }
937
1295
 
938
- // src/universal/core/shared/utils/wire.ts
939
- function unknownTypeError(dto, model) {
940
- const type = dto.type;
941
- throw new ValidationError(
942
- `${model}.type: unknown type ${JSON.stringify(type)}`
943
- );
944
- }
945
- function requiredString(value, field) {
946
- const text = notBlankStringOrNull(value);
947
- if (text === null) {
948
- throw new ValidationError(
949
- `${field}: expected a non-blank string, got ${typeof value === "string" ? "a blank string" : String(value)}`
950
- );
951
- }
952
- return text;
953
- }
954
- function requiredDate(value, field) {
955
- const date = typeof value === "string" ? new Date(value) : null;
956
- if (date === null || Number.isNaN(date.getTime())) {
957
- throw new ValidationError(
958
- `${field}: expected a date, got ${JSON.stringify(value)}`
959
- );
960
- }
961
- return date;
962
- }
963
- function requiredArray(value, field) {
964
- if (!Array.isArray(value)) {
965
- throw new ValidationError(
966
- `${field}: expected an array, got ${typeof value}`
967
- );
968
- }
969
- return value;
970
- }
971
-
972
1296
  // src/universal/types/blockchain/core.ts
973
1297
  var ETHEREUM_CHAINS = {
974
1298
  ethereum_mainnet: true,
@@ -1057,13 +1381,54 @@ function combineAmounts(a, b, op) {
1057
1381
  }
1058
1382
  var AssetSymbol = (value) => value;
1059
1383
 
1384
+ // src/universal/core/shared/utils/wire.ts
1385
+ function unknownTypeError(dto, model) {
1386
+ const type = dto.type;
1387
+ throw new ValidationError(
1388
+ `${model}.type: unknown type ${JSON.stringify(type)}`
1389
+ );
1390
+ }
1391
+ function requiredString(value, field) {
1392
+ const text = notBlankStringOrNull(value);
1393
+ if (text === null) {
1394
+ throw new ValidationError(
1395
+ `${field}: expected a non-blank string, got ${typeof value === "string" ? "a blank string" : String(value)}`
1396
+ );
1397
+ }
1398
+ return text;
1399
+ }
1400
+ function requiredDate(value, field) {
1401
+ const date = typeof value === "string" ? new Date(value) : null;
1402
+ if (date === null || Number.isNaN(date.getTime())) {
1403
+ throw new ValidationError(
1404
+ `${field}: expected a date, got ${JSON.stringify(value)}`
1405
+ );
1406
+ }
1407
+ return date;
1408
+ }
1409
+ function dateOrNull(value, field) {
1410
+ return value === null ? null : requiredDate(value, field);
1411
+ }
1412
+ function decimalOrNull(value) {
1413
+ return value === null ? null : DecimalString(value);
1414
+ }
1415
+ function requiredArray(value, field) {
1416
+ if (!Array.isArray(value)) {
1417
+ throw new ValidationError(
1418
+ `${field}: expected an array, got ${typeof value}`
1419
+ );
1420
+ }
1421
+ return value;
1422
+ }
1423
+
1060
1424
  // src/universal/types/offer.ts
1061
1425
  var OfferId = (value) => value;
1062
1426
  var OfferSlug = (value) => value;
1063
1427
  var OFFER_TYPES = {
1064
1428
  "coinlist::token_sale": true,
1065
1429
  "superstate::swap": true,
1066
- "ondo::swap": true
1430
+ "ondo::swap": true,
1431
+ "centrifuge::vault": true
1067
1432
  };
1068
1433
  var isOfferType = (value) => Object.keys(OFFER_TYPES).includes(value);
1069
1434
  var OfferEditorial = {
@@ -1105,6 +1470,7 @@ var Offer = {
1105
1470
  // on the wire: copying them would hand every consumer a `startsAt` that
1106
1471
  // is 1970 for one variant and a date for the others.
1107
1472
  case "ondo::swap":
1473
+ case "centrifuge::vault":
1108
1474
  return {
1109
1475
  ...base2,
1110
1476
  type: dto.type,
@@ -1169,6 +1535,19 @@ var OfferSwapContract = {
1169
1535
  address: EvmContractAddress(dto.address)
1170
1536
  })
1171
1537
  };
1538
+ var OfferVaultContract = {
1539
+ fromDto: (dto) => ({
1540
+ chain: Chain(dto.chain),
1541
+ address: EvmContractAddress(dto.address)
1542
+ }),
1543
+ /**
1544
+ * Drops every proxy on a chain this SDK does not name, as
1545
+ * `OfferToken.listFromDto` does: frontline publishes the full offer-token
1546
+ * chain list, which runs ahead of {@link Chain}, and one unmodelled chain
1547
+ * should not throw away the proxies the SDK can use.
1548
+ */
1549
+ listFromDto: (dtos) => dtos.filter((dto) => isChain(dto.chain)).map(OfferVaultContract.fromDto)
1550
+ };
1172
1551
  var OfferDetail = {
1173
1552
  fromDto: (dto) => {
1174
1553
  const fundingAssets = requiredArray(
@@ -1231,6 +1610,18 @@ var OfferDetail = {
1231
1610
  "OfferDetail.swap_contracts"
1232
1611
  ).map(OfferSwapContract.fromDto)
1233
1612
  };
1613
+ // No editorial, as for Ondo. `[]` is fine and a missing key is not, for
1614
+ // the same reason as `swap_contracts`: this is the spender a user
1615
+ // approves.
1616
+ case "centrifuge::vault":
1617
+ return {
1618
+ ...base2,
1619
+ type: dto.type,
1620
+ logoUrl: notBlankStringOrNull(dto.logo_url),
1621
+ vaultContracts: OfferVaultContract.listFromDto(
1622
+ requiredArray(dto.vault_contracts, "OfferDetail.vault_contracts")
1623
+ )
1624
+ };
1234
1625
  default:
1235
1626
  return unknownTypeError(dto, "OfferDetail");
1236
1627
  }
@@ -1702,6 +2093,282 @@ function transportFor(api, override, chain, logger) {
1702
2093
  return typeof override === "string" ? (0, import_viem3.http)(override) : override;
1703
2094
  }
1704
2095
 
2096
+ // src/universal/core/shared/blockchain/math.ts
2097
+ var import_viem4 = require("viem");
2098
+ function blockchainAmountFromRawOrThrow({
2099
+ label,
2100
+ raw,
2101
+ decimals
2102
+ }) {
2103
+ const trimmed = raw.trim();
2104
+ if (trimmed === "") {
2105
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
2106
+ }
2107
+ let value;
2108
+ try {
2109
+ value = BigInt(trimmed);
2110
+ } catch {
2111
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
2112
+ }
2113
+ try {
2114
+ return BlockchainAmount({ raw: assertUint256(value), decimals });
2115
+ } catch {
2116
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
2117
+ }
2118
+ }
2119
+
2120
+ // src/universal/types/providers/centrifuge/centrifuge.ts
2121
+ var CentrifugeVaultStatus = {
2122
+ fromDto: (dto) => ({
2123
+ chain: EthereumChain(dto.chain),
2124
+ symbol: AssetSymbol(dto.symbol),
2125
+ vaultAddress: EvmContractAddress(dto.vault_address),
2126
+ linked: dto.linked,
2127
+ permissioned: dto.permissioned,
2128
+ membershipValidUntil: dateOrNull(
2129
+ dto.membership_valid_until,
2130
+ "CentrifugeVaultStatus.membership_valid_until"
2131
+ ),
2132
+ halted: dto.halted,
2133
+ priceUpdatedAt: dateOrNull(
2134
+ dto.price_updated_at,
2135
+ "CentrifugeVaultStatus.price_updated_at"
2136
+ ),
2137
+ orderability: parseOrderability(
2138
+ dto.can_order,
2139
+ dto.reasons,
2140
+ "CentrifugeVaultStatus"
2141
+ ),
2142
+ asOf: requiredDate(dto.as_of, "CentrifugeVaultStatus.as_of")
2143
+ })
2144
+ };
2145
+ var CentrifugeVaultBuyTransaction = {
2146
+ fromDto: (dto) => {
2147
+ const spendInputAmount = blockchainAmountFromRawOrThrow({
2148
+ label: "spend_input_amount",
2149
+ raw: dto.spend_input_amount,
2150
+ decimals: AssetDecimals(dto.spend_input_decimals)
2151
+ });
2152
+ if (spendInputAmount.raw <= 0n) {
2153
+ throw new ValidationError(
2154
+ `spend_input_amount: must be greater than zero ("${dto.spend_input_amount}") - a deposit of nothing is not a request`
2155
+ );
2156
+ }
2157
+ return {
2158
+ ...parseTransactionCore(dto, "CentrifugeVaultBuyTransaction"),
2159
+ spendInputAmount
2160
+ };
2161
+ }
2162
+ };
2163
+ var CentrifugeVaultClaimTransaction = {
2164
+ fromDto: (dto) => ({
2165
+ ...parseTransactionCore(dto, "CentrifugeVaultClaimTransaction"),
2166
+ claimableShares: blockchainAmountFromRawOrThrow({
2167
+ label: "claimable_shares",
2168
+ raw: dto.claimable_shares,
2169
+ decimals: AssetDecimals(dto.share_decimals)
2170
+ })
2171
+ })
2172
+ };
2173
+ var CentrifugeVaultPosition = {
2174
+ fromDto: (dto) => {
2175
+ const assetDecimals = AssetDecimals(dto.asset_decimals);
2176
+ const shareDecimals = AssetDecimals(dto.share_decimals);
2177
+ const asset = (label, raw) => blockchainAmountFromRawOrThrow({ label, raw, decimals: assetDecimals });
2178
+ const shares = (label, raw) => blockchainAmountFromRawOrThrow({ label, raw, decimals: shareDecimals });
2179
+ return {
2180
+ chain: EthereumChain(dto.chain),
2181
+ symbol: AssetSymbol(dto.symbol),
2182
+ walletAddress: EvmWalletAddress(dto.wallet_address),
2183
+ status: dto.status,
2184
+ requested: asset("requested", dto.requested),
2185
+ pending: asset("pending", dto.pending),
2186
+ filledAssets: asset("filled_assets", dto.filled_assets),
2187
+ earnedShares: shares("earned_shares", dto.earned_shares),
2188
+ claimedShares: shares("claimed_shares", dto.claimed_shares),
2189
+ claimableShares: shares("claimable_shares", dto.claimable_shares),
2190
+ shareBalance: shares("share_balance", dto.share_balance),
2191
+ averagePrice: decimalOrNull(dto.average_price),
2192
+ frozen: dto.frozen,
2193
+ asOf: requiredDate(dto.as_of, "CentrifugeVaultPosition.as_of")
2194
+ };
2195
+ }
2196
+ };
2197
+ var CentrifugeVaultRedeemPosition = {
2198
+ fromDto: (dto) => ({
2199
+ chain: EthereumChain(dto.chain),
2200
+ symbol: AssetSymbol(dto.symbol),
2201
+ walletAddress: EvmWalletAddress(dto.wallet_address),
2202
+ status: dto.status,
2203
+ pending: blockchainAmountFromRawOrThrow({
2204
+ label: "pending",
2205
+ raw: dto.pending,
2206
+ decimals: AssetDecimals(dto.share_decimals)
2207
+ }),
2208
+ claimableAssets: blockchainAmountFromRawOrThrow({
2209
+ label: "claimable_assets",
2210
+ raw: dto.claimable_assets,
2211
+ decimals: AssetDecimals(dto.asset_decimals)
2212
+ }),
2213
+ frozen: dto.frozen,
2214
+ asOf: requiredDate(dto.as_of, "CentrifugeVaultRedeemPosition.as_of")
2215
+ })
2216
+ };
2217
+ var CentrifugeVaultClaimProceedsTransaction = {
2218
+ fromDto: (dto) => ({
2219
+ ...parseTransactionCore(dto, "CentrifugeVaultClaimProceedsTransaction"),
2220
+ claimableAssets: blockchainAmountFromRawOrThrow({
2221
+ label: "claimable_assets",
2222
+ raw: dto.claimable_assets,
2223
+ decimals: AssetDecimals(dto.asset_decimals)
2224
+ })
2225
+ })
2226
+ };
2227
+ function parseOrderability(canOrder, reasons, model) {
2228
+ const [first, ...rest] = reasons;
2229
+ if (canOrder) {
2230
+ if (first !== void 0) {
2231
+ throw new ValidationError(
2232
+ `${model}.reasons: expected none when can_order is true, got ${JSON.stringify(reasons)}`
2233
+ );
2234
+ }
2235
+ return { type: "orderable" };
2236
+ }
2237
+ if (first === void 0) {
2238
+ throw new ValidationError(
2239
+ `${model}.reasons: expected at least one when can_order is false`
2240
+ );
2241
+ }
2242
+ return { type: "blocked", reasons: [first, ...rest] };
2243
+ }
2244
+ function parseTransactionCore(dto, model) {
2245
+ return {
2246
+ tx: {
2247
+ to: EvmContractAddress(dto.to),
2248
+ data: HexEncodedTransactionData(dto.data)
2249
+ },
2250
+ expiresAt: dateOrNull(dto.expires_at, `${model}.expires_at`)
2251
+ };
2252
+ }
2253
+
2254
+ // src/universal/api/frontline/providers/centrifuge/centrifuge.ts
2255
+ async function getCentrifugeVaultStatus(api, params) {
2256
+ const dto = await api.send({
2257
+ method: "GET",
2258
+ url: "/v1/centrifuge/vault/status",
2259
+ queryParams: {
2260
+ symbol: params.symbol,
2261
+ chain: params.chain
2262
+ },
2263
+ attributes: Attributes.protected()
2264
+ });
2265
+ return CentrifugeVaultStatus.fromDto(dto);
2266
+ }
2267
+ async function buildCentrifugeVaultBuy(api, params) {
2268
+ const dto = await api.send({
2269
+ method: "POST",
2270
+ url: "/v1/centrifuge/vault/invest",
2271
+ body: {
2272
+ ...walletFields(params),
2273
+ amount: params.amount.raw.toString()
2274
+ },
2275
+ attributes: Attributes.protected()
2276
+ });
2277
+ if (dto.spend_input_decimals !== params.amount.decimals) {
2278
+ throw new ValidationError(
2279
+ `spend_input_decimals: the request was priced in ${dto.spend_input_decimals} decimals but the deposit was sized in ${params.amount.decimals}`
2280
+ );
2281
+ }
2282
+ return CentrifugeVaultBuyTransaction.fromDto(dto);
2283
+ }
2284
+ async function getCentrifugeVaultPosition(api, params) {
2285
+ const dto = await api.send({
2286
+ method: "GET",
2287
+ url: "/v1/centrifuge/vault/position",
2288
+ queryParams: walletFields(params),
2289
+ attributes: Attributes.protected()
2290
+ });
2291
+ return CentrifugeVaultPosition.fromDto(dto);
2292
+ }
2293
+ async function getCentrifugeVaultRedeemPosition(api, params) {
2294
+ const dto = await api.send({
2295
+ method: "GET",
2296
+ url: "/v1/centrifuge/vault/redeem-position",
2297
+ queryParams: walletFields(params),
2298
+ attributes: Attributes.protected()
2299
+ });
2300
+ return CentrifugeVaultRedeemPosition.fromDto(dto);
2301
+ }
2302
+ async function createCentrifugeVaultClaim(api, params) {
2303
+ const dto = await api.send({
2304
+ method: "POST",
2305
+ url: "/v1/centrifuge/vault/claim",
2306
+ body: walletFields(params),
2307
+ attributes: Attributes.protected()
2308
+ });
2309
+ return CentrifugeVaultClaimTransaction.fromDto(dto);
2310
+ }
2311
+ async function createCentrifugeVaultClaimProceeds(api, params) {
2312
+ const dto = await api.send({
2313
+ method: "POST",
2314
+ url: "/v1/centrifuge/vault/claim-proceeds",
2315
+ body: walletFields(params),
2316
+ attributes: Attributes.protected()
2317
+ });
2318
+ return CentrifugeVaultClaimProceedsTransaction.fromDto(dto);
2319
+ }
2320
+ function walletFields(params) {
2321
+ return {
2322
+ symbol: params.symbol,
2323
+ chain: params.chain,
2324
+ wallet_address: params.walletAddress
2325
+ };
2326
+ }
2327
+
2328
+ // src/universal/core/checkout/centrifuge/centrifuge-namespace.ts
2329
+ var CentrifugeNamespaceImpl = class {
2330
+ constructor(ctx) {
2331
+ this.ctx = ctx;
2332
+ this.log = internalLogger(ctx.logger, "CENTRIFUGE");
2333
+ }
2334
+ async getVaultStatus(params) {
2335
+ return this.log.wrap("getVaultStatus", params, async () => {
2336
+ await this.ctx.ensureUserAuthenticated();
2337
+ return getCentrifugeVaultStatus(this.ctx.api, params);
2338
+ });
2339
+ }
2340
+ async getPosition(params) {
2341
+ return this.log.wrap("getPosition", params, async () => {
2342
+ await this.ctx.ensureUserAuthenticated();
2343
+ return getCentrifugeVaultPosition(this.ctx.api, params);
2344
+ });
2345
+ }
2346
+ async getRedeemPosition(params) {
2347
+ return this.log.wrap("getRedeemPosition", params, async () => {
2348
+ await this.ctx.ensureUserAuthenticated();
2349
+ return getCentrifugeVaultRedeemPosition(this.ctx.api, params);
2350
+ });
2351
+ }
2352
+ async createClaim(params) {
2353
+ return this.log.wrap("createClaim", params, async () => {
2354
+ await this.ctx.ensureUserAuthenticated();
2355
+ return createCentrifugeVaultClaim(this.ctx.api, params);
2356
+ });
2357
+ }
2358
+ async createClaimProceeds(params) {
2359
+ return this.log.wrap("createClaimProceeds", params, async () => {
2360
+ await this.ctx.ensureUserAuthenticated();
2361
+ return createCentrifugeVaultClaimProceeds(this.ctx.api, params);
2362
+ });
2363
+ }
2364
+ async buildBuyTransaction(params) {
2365
+ return this.log.wrap("buildBuyTransaction", params, async () => {
2366
+ await this.ctx.ensureUserAuthenticated();
2367
+ return buildCentrifugeVaultBuy(this.ctx.api, params);
2368
+ });
2369
+ }
2370
+ };
2371
+
1705
2372
  // src/universal/types/providers/coin-list/token-sale.ts
1706
2373
  var ParticipationId = (value) => value;
1707
2374
  var Blockchain = (value) => value;
@@ -1816,37 +2483,15 @@ var CoinListTokenSaleNamespaceImpl = class {
1816
2483
  };
1817
2484
 
1818
2485
  // src/universal/core/shared/blockchain/formatters.ts
1819
- var import_viem4 = require("viem");
2486
+ var import_viem5 = require("viem");
1820
2487
  function formatRawAmount(amount) {
1821
- return (0, import_viem4.formatUnits)(amount.raw, amount.decimals);
2488
+ return (0, import_viem5.formatUnits)(amount.raw, amount.decimals);
1822
2489
  }
1823
2490
  var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
2491
+ var SHARE_MAX_FRACTION_DIGITS = AssetDecimals(6);
2492
+ var SHARE_MIN_FRACTION_DIGITS = AssetDecimals(2);
1824
2493
  var USD_FRACTION_DIGITS = AssetDecimals(2);
1825
2494
 
1826
- // src/universal/core/shared/blockchain/math.ts
1827
- var import_viem5 = require("viem");
1828
- function blockchainAmountFromRawOrThrow({
1829
- label,
1830
- raw,
1831
- decimals
1832
- }) {
1833
- const trimmed = raw.trim();
1834
- if (trimmed === "") {
1835
- throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1836
- }
1837
- let value;
1838
- try {
1839
- value = BigInt(trimmed);
1840
- } catch {
1841
- throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1842
- }
1843
- try {
1844
- return BlockchainAmount({ raw: assertUint256(value), decimals });
1845
- } catch {
1846
- throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1847
- }
1848
- }
1849
-
1850
2495
  // src/universal/types/providers/ondo/ondo.ts
1851
2496
  var OndoTradingStatus = {
1852
2497
  fromDto: (dto) => {
@@ -1862,7 +2507,6 @@ var OndoTradingStatus = {
1862
2507
  };
1863
2508
  }
1864
2509
  };
1865
- var decimalOrNull = (value) => value === null ? null : DecimalString(value);
1866
2510
  var OndoQuote = {
1867
2511
  fromDto: (dto) => {
1868
2512
  const assetDecimals = AssetDecimals(dto.asset_decimals);
@@ -3666,28 +4310,26 @@ var WalletsNamespaceImpl = class {
3666
4310
  };
3667
4311
 
3668
4312
  // src/server/core/coinlist-server.ts
3669
- var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
4313
+ var ACCESS_TOKEN_EXPIRY_BUFFER = Seconds.of(60);
3670
4314
  var CoinListServerImpl = class {
3671
4315
  constructor(_config) {
3672
- this._config = _config;
3673
4316
  const logger = _config.logger ?? null;
3674
4317
  this.api = new ApiClient(
3675
4318
  {
3676
4319
  baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
3677
4320
  xApiVersion: API_VERSION
3678
4321
  },
3679
- // When refresh=true the renewal middleware has received a 401 and wants a
3680
- // fresh token. A read-only store cannot persist a new session, so return
3681
- // null immediately — this tells the middleware to skip the retry rather
3682
- // than re-sending with the same expired token and wasting a round-trip.
3683
- (refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.auth.getAccessToken(),
4322
+ (trigger) => auth.tokenFor(trigger),
3684
4323
  logger
3685
4324
  );
3686
- this.auth = new ServerAuthNamespaceImpl(this.api, {
4325
+ const auth = new ServerAuthNamespaceImpl(this.api, {
3687
4326
  ..._config,
3688
- accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,
3689
- strict: _config.strict ?? false
4327
+ accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER,
4328
+ strict: _config.strict ?? false,
4329
+ refreshes: processRefreshCoordinator,
4330
+ ...systemTime
3690
4331
  });
4332
+ this.auth = auth;
3691
4333
  const ctx = {
3692
4334
  api: this.api,
3693
4335
  rpc: publicClients(this.api, _config.rpc, _config.logger ?? null),
@@ -3702,6 +4344,7 @@ var CoinListServerImpl = class {
3702
4344
  this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);
3703
4345
  this.superstate = new SuperstateSwapNamespaceImpl(ctx);
3704
4346
  this.ondo = new OndoNamespaceImpl(ctx);
4347
+ this.centrifuge = new CentrifugeNamespaceImpl(ctx);
3705
4348
  this.tokens = new TokensNamespaceImpl(
3706
4349
  _config.tokensBaseUrl ?? NABU_BASE_URL,
3707
4350
  logger
@@ -3865,9 +4508,13 @@ function pinoServerLogger(options) {
3865
4508
  options.level
3866
4509
  );
3867
4510
  }
4511
+
4512
+ // src/server/core/server-auth-namespace.ts
4513
+ function emptySessionStore() {
4514
+ return { getSession: async () => null };
4515
+ }
3868
4516
  // Annotate the CommonJS export names for ESM import in node:
3869
4517
  0 && (module.exports = {
3870
- ServerAuthNamespaceImpl,
3871
4518
  ServerOffersNamespaceImpl,
3872
4519
  ServerRequirementsNamespaceImpl,
3873
4520
  WritableSessionStoreRequiredError,