@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.
- package/dist/{chunk-DCW7NQXH.js → chunk-3WW5FLT7.js} +52 -19
- package/dist/chunk-3WW5FLT7.js.map +1 -0
- package/dist/{chunk-MOE5S6CE.js → chunk-C6GF7MDF.js} +915 -458
- package/dist/chunk-C6GF7MDF.js.map +1 -0
- package/dist/{chunk-VH34YC3Q.js → chunk-IZJ4JSSC.js} +78 -4
- package/dist/chunk-IZJ4JSSC.js.map +1 -0
- package/dist/client/index.cjs +12103 -8452
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +1640 -37
- package/dist/client/index.d.ts +1640 -37
- package/dist/client/index.js +7923 -4800
- package/dist/client/index.js.map +1 -1
- package/dist/server/index.cjs +789 -142
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +69 -41
- package/dist/server/index.d.ts +69 -41
- package/dist/server/index.js +323 -65
- package/dist/server/index.js.map +1 -1
- package/dist/{tokens-namespace-CIWBtgt2.d.cts → time-CVZpAkGY.d.cts} +878 -192
- package/dist/{tokens-namespace-CIWBtgt2.d.ts → time-CVZpAkGY.d.ts} +878 -192
- package/dist/{token-registry-snapshot-BNBNuDu1.d.ts → token-registry-snapshot-BkwA8KmD.d.ts} +74 -8
- package/dist/{token-registry-snapshot-CqI6dXM_.d.cts → token-registry-snapshot-bR14QehS.d.cts} +74 -8
- package/dist/universal/index.cjs +982 -448
- package/dist/universal/index.cjs.map +1 -1
- package/dist/universal/index.d.cts +91 -5
- package/dist/universal/index.d.ts +91 -5
- package/dist/universal/index.js +44 -2
- package/package.json +1 -1
- package/dist/chunk-DCW7NQXH.js.map +0 -1
- package/dist/chunk-MOE5S6CE.js.map +0 -1
- package/dist/chunk-VH34YC3Q.js.map +0 -1
package/dist/server/index.cjs
CHANGED
|
@@ -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) =>
|
|
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
|
-
|
|
589
|
-
if (
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
-
|
|
596
|
-
|
|
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(
|
|
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
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
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
|
-
|
|
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
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
1183
|
+
if (this.config.strict) {
|
|
900
1184
|
throw err;
|
|
901
1185
|
}
|
|
902
|
-
this.log.child({ op: "logout" }).
|
|
903
|
-
msg: "
|
|
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
|
|
1194
|
+
* Returns the store's `setSession`, or throws - the guard every
|
|
910
1195
|
* session-writing operation shares.
|
|
911
1196
|
*/
|
|
912
1197
|
writableSessionStore() {
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
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
|
|
2486
|
+
var import_viem5 = require("viem");
|
|
1820
2487
|
function formatRawAmount(amount) {
|
|
1821
|
-
return (0,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
4325
|
+
const auth = new ServerAuthNamespaceImpl(this.api, {
|
|
3687
4326
|
..._config,
|
|
3688
|
-
accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ??
|
|
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,
|