@coinlist-co/react 0.12.2-rc.e1f6c82 → 0.12.2

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.
@@ -1,19 +1,20 @@
1
1
  import {
2
+ API_VERSION,
2
3
  AuthenticatedApiClient,
3
- NABU_BASE_URL,
4
4
  PINO_LEVEL,
5
5
  SDK_LOGGER_NAME,
6
+ baseUrls,
7
+ createNabuApiClient,
6
8
  loggerOverPino,
7
9
  notifySessionExpired,
8
10
  publicClients,
9
11
  systemTime
10
- } from "../chunk-EKLUJZ7T.js";
12
+ } from "../chunk-OQ2ANYUF.js";
11
13
  import {
12
14
  ClientCredentialsOAuth,
13
15
  OAuthSession
14
- } from "../chunk-MJ6YXZWH.js";
16
+ } from "../chunk-IWQ6A52U.js";
15
17
  import {
16
- API_VERSION,
17
18
  Attributes,
18
19
  CentrifugeNamespaceImpl,
19
20
  CoinListTokenSaleNamespaceImpl,
@@ -22,8 +23,8 @@ import {
22
23
  HttpError,
23
24
  Millis,
24
25
  NotAuthenticatedError,
26
+ OffersNamespaceImpl,
25
27
  OndoNamespaceImpl,
26
- PUBLIC_API_BASE_URL,
27
28
  RequirementsNamespaceImpl,
28
29
  Seconds,
29
30
  SuperstateSwapNamespaceImpl,
@@ -37,24 +38,84 @@ import {
37
38
  internalLogger,
38
39
  isExpired,
39
40
  isRejectedToken
40
- } from "../chunk-GIE4UWB3.js";
41
+ } from "../chunk-2FZAXGVH.js";
41
42
 
42
- // src/server/core/api/api-client.ts
43
- var ApiClient = class {
44
- constructor(config, fetchAccessToken, logger = null) {
45
- this.client = new AuthenticatedApiClient(
46
- config,
47
- fetchAccessToken,
48
- [],
49
- logger
50
- );
51
- }
52
- async send(request) {
53
- return this.client.send(request);
43
+ // src/server/core/auth/errors.ts
44
+ var WritableSessionStoreRequiredError = class extends Error {
45
+ constructor(message = "This operation requires a writable SessionStore. Provide a `setSession` implementation in your SessionStore to persist or clear OAuth sessions.") {
46
+ super(message);
47
+ this.name = "WritableSessionStoreRequiredError";
54
48
  }
55
49
  };
56
50
 
57
- // src/server/core/session-refresh.ts
51
+ // src/server/core/auth/server-access-token.ts
52
+ function classifyAccessToken({
53
+ session,
54
+ store,
55
+ trigger,
56
+ now,
57
+ buffer
58
+ }) {
59
+ if (session === null) {
60
+ return { type: "no-session" };
61
+ }
62
+ const token = session.accessToken;
63
+ const stale = isExpired({
64
+ expiresAt: EpochMillis.fromDate(token.expiresAt),
65
+ now,
66
+ buffer
67
+ });
68
+ switch (store.type) {
69
+ case "read-only":
70
+ return classifyReadOnly(token, trigger, stale);
71
+ case "writable": {
72
+ if (!needsRefresh(token, trigger, stale)) {
73
+ return { type: "serve", token };
74
+ }
75
+ const fallback = fallbackToken(token, trigger, now);
76
+ return session.refreshToken === void 0 && fallback !== null ? { type: "serve", token: fallback } : {
77
+ type: "refresh",
78
+ session,
79
+ setSession: store.setSession,
80
+ fallback
81
+ };
82
+ }
83
+ }
84
+ }
85
+ function classifyReadOnly(token, trigger, stale) {
86
+ switch (trigger.type) {
87
+ case "after-401":
88
+ return isRejectedToken(token, trigger.rejected) ? { type: "refuse" } : { type: "serve", token };
89
+ case "before-request":
90
+ return stale ? { type: "serve-stale", token } : { type: "serve", token };
91
+ }
92
+ }
93
+ function sessionStoreAccess(sessionStore) {
94
+ const setSession = sessionStore.setSession?.bind(sessionStore);
95
+ return setSession === void 0 ? { type: "read-only" } : { type: "writable", setSession };
96
+ }
97
+ function needsRefresh(token, trigger, stale) {
98
+ switch (trigger.type) {
99
+ case "before-request":
100
+ return stale;
101
+ case "after-401":
102
+ return trigger.rejected.type === "no-user-token" || isRejectedToken(token, trigger.rejected) || stale;
103
+ }
104
+ }
105
+ function fallbackToken(token, trigger, now) {
106
+ const unexpired = !isExpired({
107
+ expiresAt: EpochMillis.fromDate(token.expiresAt),
108
+ now
109
+ });
110
+ switch (trigger.type) {
111
+ case "after-401":
112
+ return unexpired && !isRejectedToken(token, trigger.rejected) ? token : null;
113
+ case "before-request":
114
+ return unexpired ? token : null;
115
+ }
116
+ }
117
+
118
+ // src/server/core/auth/session-refresh.ts
58
119
  var VERDICT_MIN_GAP = Millis.of(5e3);
59
120
  var REJECTION_MEMORY = Millis.of(6e4);
60
121
  var RefreshKey = {
@@ -155,38 +216,91 @@ function rejectedAt(rejection) {
155
216
  }
156
217
  var processRefreshCoordinator = new RefreshCoordinator();
157
218
 
158
- // src/server/shared/errors.ts
159
- var WritableSessionStoreRequiredError = class extends Error {
160
- constructor(message = "This operation requires a writable SessionStore. Provide a `setSession` implementation in your SessionStore to persist or clear OAuth sessions.") {
161
- super(message);
162
- this.name = "WritableSessionStoreRequiredError";
219
+ // src/universal/api/frontline/oauth.ts
220
+ async function exchangeAuthorizationCode(api, params) {
221
+ const dto = await api.send({
222
+ method: "POST",
223
+ url: "/oauth/token",
224
+ body: {
225
+ grant_type: "authorization_code",
226
+ code: params.code,
227
+ redirect_uri: params.redirectUri,
228
+ client_id: params.clientId,
229
+ client_secret: params.clientSecret,
230
+ code_verifier: params.codeVerifier
231
+ },
232
+ attributes: Attributes.notRetryable()
233
+ });
234
+ return OAuthSession.fromDto(dto);
235
+ }
236
+ async function refreshOAuthSession(api, params) {
237
+ try {
238
+ const dto = await api.send({
239
+ method: "POST",
240
+ url: "/oauth/token",
241
+ body: {
242
+ grant_type: "refresh_token",
243
+ refresh_token: params.refreshToken,
244
+ client_id: params.clientId,
245
+ client_secret: params.clientSecret
246
+ },
247
+ attributes: Attributes.notRetryable()
248
+ });
249
+ return { type: "renewed", session: OAuthSession.fromDto(dto) };
250
+ } catch (error) {
251
+ if (isInvalidGrant(error)) {
252
+ return { type: "invalid-grant" };
253
+ }
254
+ throw error;
163
255
  }
164
- };
256
+ }
257
+ async function requestClientCredentials(api, params) {
258
+ const dto = await api.send({
259
+ method: "POST",
260
+ url: "/oauth/token",
261
+ body: {
262
+ grant_type: "client_credentials",
263
+ client_id: params.clientId,
264
+ client_secret: params.clientSecret
265
+ }
266
+ });
267
+ return ClientCredentialsOAuth(OAuthSession.fromDto(dto).accessToken);
268
+ }
269
+ async function revokeOAuthToken(api, params) {
270
+ await api.send({
271
+ method: "POST",
272
+ url: "/oauth/revoke",
273
+ body: {
274
+ token: params.token.value,
275
+ client_id: params.clientId,
276
+ client_secret: params.clientSecret
277
+ }
278
+ });
279
+ }
280
+ function isInvalidGrant(error) {
281
+ if (!(error instanceof HttpError) || error.response.status !== 400) {
282
+ return false;
283
+ }
284
+ const body = error.response.body;
285
+ return typeof body === "object" && body !== null && "error" in body && body.error === "invalid_grant";
286
+ }
165
287
 
166
- // src/server/core/server-auth-namespace-impl.ts
288
+ // src/server/core/auth/auth-namespace.ts
167
289
  var ServerAuthNamespaceImpl = class {
168
290
  constructor(api, config) {
169
291
  this.api = api;
170
292
  this.config = config;
171
293
  this.log = internalLogger(config.logger ?? null, "AUTH");
172
294
  }
173
- async completeOAuth(params) {
295
+ async completeOAuth(grant) {
174
296
  return this.log.wrap("completeOAuth", void 0, async () => {
175
297
  const setSession = this.writableSessionStore();
176
- const sessionDto = await this.api.send({
177
- method: "POST",
178
- url: `/oauth/token`,
179
- body: {
180
- grant_type: "authorization_code",
181
- code: params.code,
182
- redirect_uri: this.config.redirectUri,
183
- client_id: this.config.clientId,
184
- client_secret: this.config.clientSecret,
185
- code_verifier: params.codeVerifier
186
- },
187
- attributes: Attributes.notRetryable()
298
+ const session = await exchangeAuthorizationCode(this.api, {
299
+ ...this.oauthClient(),
300
+ code: grant.code,
301
+ codeVerifier: grant.codeVerifier,
302
+ redirectUri: this.config.redirectUri
188
303
  });
189
- const session = OAuthSession.fromDto(sessionDto);
190
304
  await setSession(session);
191
305
  return session;
192
306
  });
@@ -294,48 +408,34 @@ var ServerAuthNamespaceImpl = class {
294
408
  }
295
409
  }
296
410
  /**
297
- * One `POST /oauth/token`, total: every failure comes back as a value, so
411
+ * One refresh-token grant, total: every failure comes back as a value, so
298
412
  * the coordinator can judge it once for everyone who joined.
299
- *
300
- * Never retried. The refresh token is single-use, so a retry of an attempt
301
- * that reached the server would present a token already rotated away, and
302
- * its `invalid_grant` would be judged as a rejection of the session.
303
413
  */
304
414
  async exchange(refreshToken) {
305
415
  if (refreshToken === void 0) {
306
416
  return { type: "unrenewable" };
307
417
  }
308
418
  try {
309
- const sessionDto = await this.api.send({
310
- method: "POST",
311
- url: `/oauth/token`,
312
- body: {
313
- grant_type: "refresh_token",
314
- refresh_token: refreshToken,
315
- client_id: this.config.clientId,
316
- client_secret: this.config.clientSecret
317
- },
318
- attributes: Attributes.notRetryable()
419
+ const grant = await refreshOAuthSession(this.api, {
420
+ ...this.oauthClient(),
421
+ refreshToken
319
422
  });
320
- return { type: "renewed", session: OAuthSession.fromDto(sessionDto) };
423
+ switch (grant.type) {
424
+ case "renewed":
425
+ return { type: "renewed", session: grant.session };
426
+ case "invalid-grant":
427
+ return { type: "rejected" };
428
+ }
321
429
  } catch (error) {
322
- return isInvalidGrant(error) ? { type: "rejected" } : { type: "unknown", error };
430
+ return { type: "unknown", error };
323
431
  }
324
432
  }
325
433
  async clientCredentials() {
326
- return this.log.wrap("clientCredentials", void 0, async () => {
327
- const sessionDto = await this.api.send({
328
- method: "POST",
329
- url: `/oauth/token`,
330
- body: {
331
- grant_type: "client_credentials",
332
- client_id: this.config.clientId,
333
- client_secret: this.config.clientSecret
334
- }
335
- });
336
- const session = OAuthSession.fromDto(sessionDto);
337
- return ClientCredentialsOAuth(session.accessToken);
338
- });
434
+ return this.log.wrap(
435
+ "clientCredentials",
436
+ void 0,
437
+ () => requestClientCredentials(this.api, this.oauthClient())
438
+ );
339
439
  }
340
440
  async logout() {
341
441
  return this.log.wrap("logout", void 0, () => this.revokeAndClear());
@@ -345,14 +445,9 @@ var ServerAuthNamespaceImpl = class {
345
445
  const session = await this.config.sessionStore.getSession();
346
446
  if (session == null) return;
347
447
  try {
348
- await this.api.send({
349
- method: "POST",
350
- url: `/oauth/revoke`,
351
- body: {
352
- token: session.accessToken.value,
353
- client_id: this.config.clientId,
354
- client_secret: this.config.clientSecret
355
- }
448
+ await revokeOAuthToken(this.api, {
449
+ ...this.oauthClient(),
450
+ token: session.accessToken
356
451
  });
357
452
  } catch (err) {
358
453
  if (this.config.strict) {
@@ -365,6 +460,12 @@ var ServerAuthNamespaceImpl = class {
365
460
  }
366
461
  await setSession(null);
367
462
  }
463
+ oauthClient() {
464
+ return {
465
+ clientId: this.config.clientId,
466
+ clientSecret: this.config.clientSecret
467
+ };
468
+ }
368
469
  /**
369
470
  * Returns the store's `setSession`, or throws - the guard every
370
471
  * session-writing operation shares.
@@ -379,85 +480,29 @@ var ServerAuthNamespaceImpl = class {
379
480
  }
380
481
  }
381
482
  };
382
- function classifyAccessToken({
383
- session,
384
- store,
385
- trigger,
386
- now,
387
- buffer
388
- }) {
389
- if (session === null) {
390
- return { type: "no-session" };
391
- }
392
- const token = session.accessToken;
393
- const stale = isExpired({
394
- expiresAt: EpochMillis.fromDate(token.expiresAt),
395
- now,
396
- buffer
397
- });
398
- switch (store.type) {
399
- case "read-only":
400
- return classifyReadOnly(token, trigger, stale);
401
- case "writable": {
402
- if (!needsRefresh(token, trigger, stale)) {
403
- return { type: "serve", token };
404
- }
405
- const fallback = fallbackToken(token, trigger, now);
406
- return session.refreshToken === void 0 && fallback !== null ? { type: "serve", token: fallback } : {
407
- type: "refresh",
408
- session,
409
- setSession: store.setSession,
410
- fallback
411
- };
412
- }
413
- }
414
- }
415
- function classifyReadOnly(token, trigger, stale) {
416
- switch (trigger.type) {
417
- case "after-401":
418
- return isRejectedToken(token, trigger.rejected) ? { type: "refuse" } : { type: "serve", token };
419
- case "before-request":
420
- return stale ? { type: "serve-stale", token } : { type: "serve", token };
421
- }
422
- }
423
- function sessionStoreAccess(sessionStore) {
424
- const setSession = sessionStore.setSession?.bind(sessionStore);
425
- return setSession === void 0 ? { type: "read-only" } : { type: "writable", setSession };
426
- }
427
- function needsRefresh(token, trigger, stale) {
428
- switch (trigger.type) {
429
- case "before-request":
430
- return stale;
431
- case "after-401":
432
- return trigger.rejected.type === "no-user-token" || isRejectedToken(token, trigger.rejected) || stale;
433
- }
483
+
484
+ // src/server/core/auth/session-store.ts
485
+ function emptySessionStore() {
486
+ return { getSession: async () => null };
434
487
  }
435
- function fallbackToken(token, trigger, now) {
436
- const unexpired = !isExpired({
437
- expiresAt: EpochMillis.fromDate(token.expiresAt),
438
- now
439
- });
440
- switch (trigger.type) {
441
- case "after-401":
442
- return unexpired && !isRejectedToken(token, trigger.rejected) ? token : null;
443
- case "before-request":
444
- return unexpired ? token : null;
488
+
489
+ // src/server/core/api/api-client.ts
490
+ var ApiClient = class {
491
+ constructor(config, fetchAccessToken, logger = null) {
492
+ this.client = new AuthenticatedApiClient(
493
+ config,
494
+ fetchAccessToken,
495
+ [],
496
+ logger
497
+ );
445
498
  }
446
- }
447
- function isInvalidGrant(error) {
448
- if (!(error instanceof HttpError) || error.response.status !== 400) {
449
- return false;
499
+ async send(request) {
500
+ return this.client.send(request);
450
501
  }
451
- const body = error.response.body;
452
- return typeof body === "object" && body !== null && "error" in body && body.error === "invalid_grant";
453
- }
502
+ };
454
503
 
455
- // src/server/core/server-offers-namespace.ts
456
- var ServerOffersNamespaceImpl = class {
457
- constructor(ctx) {
458
- this.ctx = ctx;
459
- this.log = internalLogger(ctx.logger, "OFFERS");
460
- }
504
+ // src/server/core/offers/server-offers-namespace.ts
505
+ var ServerOffersNamespaceImpl = class extends OffersNamespaceImpl {
461
506
  async list(clientCreds) {
462
507
  return this.log.wrap("list", clientCreds, async () => {
463
508
  await this.ctx.ensureAuthenticated(clientCreds);
@@ -478,17 +523,13 @@ var ServerOffersNamespaceImpl = class {
478
523
  }
479
524
  };
480
525
 
481
- // src/server/core/server-requirements-namespace.ts
526
+ // src/server/core/requirements/server-requirements-namespace.ts
482
527
  var ServerRequirementsNamespaceImpl = class extends RequirementsNamespaceImpl {
483
- constructor(serverCtx) {
484
- super(serverCtx);
485
- this.serverCtx = serverCtx;
486
- }
487
528
  async forOffer(offerId, clientCreds) {
488
529
  return this.log.wrap("forOffer", { offerId, clientCreds }, async () => {
489
- await this.serverCtx.ensureAuthenticated(clientCreds);
530
+ await this.ctx.ensureAuthenticated(clientCreds);
490
531
  return fetchOfferRequirements(
491
- this.serverCtx.api,
532
+ this.ctx.api,
492
533
  offerId,
493
534
  clientCreds
494
535
  );
@@ -501,9 +542,10 @@ var ACCESS_TOKEN_EXPIRY_BUFFER = Seconds.of(60);
501
542
  var CoinListServerImpl = class {
502
543
  constructor(_config) {
503
544
  const logger = _config.logger ?? null;
545
+ const urls = baseUrls(_config);
504
546
  this.api = new ApiClient(
505
547
  {
506
- baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
548
+ baseUrl: urls.api,
507
549
  xApiVersion: API_VERSION
508
550
  },
509
551
  (trigger) => auth.tokenFor(trigger),
@@ -532,10 +574,10 @@ var CoinListServerImpl = class {
532
574
  this.superstate = new SuperstateSwapNamespaceImpl(ctx);
533
575
  this.ondo = new OndoNamespaceImpl(ctx);
534
576
  this.centrifuge = new CentrifugeNamespaceImpl(ctx);
535
- this.tokens = new TokensNamespaceImpl(
536
- _config.tokensBaseUrl ?? NABU_BASE_URL,
577
+ this.tokens = new TokensNamespaceImpl({
578
+ nabu: createNabuApiClient(urls.tokens, logger),
537
579
  logger
538
- );
580
+ });
539
581
  }
540
582
  /**
541
583
  * An app-level token authenticates a request on its own; without one the
@@ -553,7 +595,7 @@ function createCoinListServer(config) {
553
595
  return new CoinListServerImpl(config);
554
596
  }
555
597
 
556
- // src/server/core/observability/pino-server-logger.ts
598
+ // src/server/core/shared/observability/pino-server-logger.ts
557
599
  import { pino } from "pino";
558
600
  function pinoServerLogger(options) {
559
601
  return loggerOverPino(
@@ -567,12 +609,8 @@ function pinoServerLogger(options) {
567
609
  options.level
568
610
  );
569
611
  }
570
-
571
- // src/server/core/server-auth-namespace.ts
572
- function emptySessionStore() {
573
- return { getSession: async () => null };
574
- }
575
612
  export {
613
+ ServerAuthNamespaceImpl,
576
614
  ServerOffersNamespaceImpl,
577
615
  ServerRequirementsNamespaceImpl,
578
616
  WritableSessionStoreRequiredError,