@coinbase/cdp-api-client 0.0.116 → 0.0.118

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,2 +1,2 @@
1
- import { __require as r } from "./index17.js";
1
+ import { __require as r } from "./index12.js";
2
2
  r();
@@ -1,4 +1,4 @@
1
- const o = "0.0.116";
1
+ const o = "0.0.118";
2
2
  export {
3
3
  o as VERSION
4
4
  };
@@ -1,94 +1,94 @@
1
- import { Analytics as o } from "./index2.js";
1
+ import { Analytics as i } from "./index2.js";
2
2
  import "./index3.js";
3
- import c from "axios";
3
+ import p from "axios";
4
4
  import { ERROR_DOCS_PAGE_URL as h } from "./index9.js";
5
- import { UnknownApiError as R, HttpErrorType as u, isOpenAPIError as A, APIError as d, UnknownError as k } from "./index7.js";
6
- const w = () => typeof window < "u" && typeof document < "u";
7
- let a = c.create({
5
+ import { UnknownApiError as g, HttpErrorType as d, isOpenAPIError as y, APIError as l, UnknownError as T } from "./index7.js";
6
+ const v = () => typeof window < "u" && typeof document < "u";
7
+ let n = p.create({
8
8
  baseURL: "https://api.cdp.coinbase.com/platform"
9
- }), i = null;
10
- const O = (t) => {
11
- if (a = c.create({
9
+ }), c = null;
10
+ const N = (t) => {
11
+ if (n = p.create({
12
12
  baseURL: t.basePath || "https://api.cdp.coinbase.com/platform",
13
13
  // Only enable cookies in browser environments where they're supported
14
- withCredentials: w()
15
- }), a.interceptors.request.use(async (r) => {
16
- const e = U(r), s = f(r);
17
- if (!i || v(s.pathname) || _(s.pathname) && !await i.isSignedIn() || !I(s.pathname))
14
+ withCredentials: v()
15
+ }), n.interceptors.request.use(async (r) => {
16
+ const e = C(r), s = w(r);
17
+ if (!c || _(s.pathname) || A(s.pathname) && !await c.isSignedIn() || !O(s.pathname))
18
18
  return r;
19
- const n = await i.getXWalletAuth({
19
+ const a = await c.getXWalletAuth({
20
20
  requestMethod: e,
21
21
  requestHost: s.host,
22
22
  requestPath: s.pathname,
23
23
  requestData: r.data
24
24
  });
25
- return n && (r.headers["X-Wallet-Auth"] = n), r;
26
- }), a.interceptors.request.use(async (r) => {
27
- const e = f(r);
28
- if (!i || v(e.pathname) || _(e.pathname) && !await i.isSignedIn())
25
+ return a && (r.headers["X-Wallet-Auth"] = a), r;
26
+ }), n.interceptors.request.use(async (r) => {
27
+ const e = w(r);
28
+ if (!c || _(e.pathname) || A(e.pathname) && !await c.isSignedIn())
29
29
  return r;
30
- const s = await i.getToken();
30
+ const s = await c.getToken();
31
31
  return s && s !== "" && (r.headers.Authorization = `Bearer ${s}`), r;
32
- }), !w()) {
32
+ }), !v()) {
33
33
  const r = t.platform ? `CDP/reactnative/${t.platform}` : "CDP/reactnative";
34
- a.interceptors.request.use(async (e) => {
34
+ n.interceptors.request.use(async (e) => {
35
35
  let s = e.headers["User-Agent"];
36
36
  return s = s ? `${s} ${r}` : r, e.headers["User-Agent"] = s, e;
37
37
  });
38
38
  }
39
- t.refreshTokenStorage && P(t.refreshTokenStorage), t.appAttestation && y(t.appAttestation, t.platform), t.debugging && (a.interceptors.request.use((r) => (console.log("Request:", r), r)), a.interceptors.response.use((r) => (console.log("Response:", r), r)));
40
- }, D = (t) => {
41
- i = t;
42
- }, y = (t, r) => {
43
- a.interceptors.request.use(async (e) => {
44
- const s = f(e);
45
- if (!q(s.pathname) || !t.isEnabled())
39
+ t.refreshTokenStorage && U(t.refreshTokenStorage, t.retryTokenReads ?? !1), t.appAttestation && P(t.appAttestation, t.platform), t.debugging && (n.interceptors.request.use((r) => (console.log("Request:", r), r)), n.interceptors.response.use((r) => (console.log("Response:", r), r)));
40
+ }, z = (t) => {
41
+ c = t;
42
+ }, P = (t, r) => {
43
+ n.interceptors.request.use(async (e) => {
44
+ const s = w(e);
45
+ if (!x(s.pathname) || !t.isEnabled())
46
46
  return e;
47
47
  try {
48
48
  if (r === "ios") {
49
- const n = s.pathname.match(/\/projects\/([^/]+)\//);
50
- if (!n || !n[1])
49
+ const a = s.pathname.match(/\/projects\/([^/]+)\//);
50
+ if (!a || !a[1])
51
51
  return e;
52
- const g = `/v2/embedded-wallet-api/projects/${n[1]}/attestation/challenge`, l = (await a.post(g)).data.challenge;
53
- if (!l)
52
+ const u = `/v2/embedded-wallet-api/projects/${a[1]}/attestation/challenge`, m = (await n.post(u)).data.challenge;
53
+ if (!m)
54
54
  return console.warn("Failed to fetch assertion challenge"), e;
55
- const p = await t.generateAssertion(l);
56
- if (!p)
55
+ const f = await t.generateAssertion(m);
56
+ if (!f)
57
57
  return e;
58
- e.headers["X-App-Attestation-Assertion"] = p.assertion, e.headers["X-App-Attestation-Key-ID"] = p.keyId, e.headers["X-App-Attestation-Challenge"] = l;
58
+ e.headers["X-App-Attestation-Assertion"] = f.assertion, e.headers["X-App-Attestation-Key-ID"] = f.keyId, e.headers["X-App-Attestation-Challenge"] = m;
59
59
  } else {
60
- const n = await t.generateAssertion(JSON.stringify(e.data));
61
- if (!n)
60
+ const a = await t.generateAssertion(JSON.stringify(e.data));
61
+ if (!a)
62
62
  return e;
63
- e.headers["X-Integrity-Token"] = n.assertion, e.headers["X-Package-Name"] = t.appIdentifier;
63
+ e.headers["X-Integrity-Token"] = a.assertion, e.headers["X-Package-Name"] = t.appIdentifier;
64
64
  }
65
65
  return e;
66
- } catch (n) {
66
+ } catch (a) {
67
67
  throw new Error(
68
- `App attestation required but assertion generation failed: ${n instanceof Error ? n.message : String(n)}`
68
+ `App attestation required but assertion generation failed: ${a instanceof Error ? a.message : String(a)}`
69
69
  );
70
70
  }
71
71
  });
72
- }, E = (t, r) => ({
72
+ }, S = (t, r) => ({
73
73
  ...t,
74
74
  headers: {
75
75
  ...t.headers || {},
76
76
  "X-Idempotency-Key": r
77
77
  }
78
- }), z = async (t, r) => {
79
- $(t), r && r !== "" && (t = E(t, r));
78
+ }), H = async (t, r) => {
79
+ j(t), r && r !== "" && (t = S(t, r));
80
80
  try {
81
- return (await a(t)).data;
81
+ return (await n(t)).data;
82
82
  } catch (e) {
83
- if (c.isAxiosError(e) && !e.response)
84
- throw new R(
85
- u.unknown,
83
+ if (p.isAxiosError(e) && !e.response)
84
+ throw new g(
85
+ d.unknown,
86
86
  e.cause instanceof Error ? e.cause.message : e.message,
87
87
  e.cause
88
88
  );
89
- if (c.isAxiosError(e) && e.response) {
90
- if (A(e.response.data))
91
- throw new d(
89
+ if (p.isAxiosError(e) && e.response) {
90
+ if (y(e.response.data))
91
+ throw new l(
92
92
  e.response.status,
93
93
  e.response.data.errorType,
94
94
  e.response.data.errorMessage,
@@ -100,54 +100,54 @@ const O = (t) => {
100
100
  const s = e.response.status;
101
101
  switch (s) {
102
102
  case 401:
103
- throw new d(
103
+ throw new l(
104
104
  s,
105
- u.unauthorized,
105
+ d.unauthorized,
106
106
  "Unauthorized.",
107
107
  void 0,
108
108
  `${h}#unauthorized`,
109
109
  e.cause
110
110
  );
111
111
  case 404:
112
- throw new d(
112
+ throw new l(
113
113
  s,
114
- u.not_found,
114
+ d.not_found,
115
115
  "API not found.",
116
116
  void 0,
117
117
  `${h}#not_found`,
118
118
  e.cause
119
119
  );
120
120
  case 502:
121
- throw new d(
121
+ throw new l(
122
122
  s,
123
- u.bad_gateway,
123
+ d.bad_gateway,
124
124
  "Bad gateway.",
125
125
  void 0,
126
126
  `${h}`,
127
127
  e.cause
128
128
  );
129
129
  case 503:
130
- throw new d(
130
+ throw new l(
131
131
  s,
132
- u.service_unavailable,
132
+ d.service_unavailable,
133
133
  "Service unavailable. Please try again later.",
134
134
  void 0,
135
135
  `${h}`,
136
136
  e.cause
137
137
  );
138
138
  default: {
139
- let n = "";
139
+ let a = "";
140
140
  if (e.response.data)
141
141
  try {
142
- n = JSON.stringify(e.response.data);
142
+ a = JSON.stringify(e.response.data);
143
143
  } catch {
144
- n = String(e.response.data);
144
+ a = String(e.response.data);
145
145
  }
146
- const m = n ? `An unexpected error occurred: ${n}` : "An unexpected error occurred.";
147
- throw new d(
146
+ const o = a ? `An unexpected error occurred: ${a}` : "An unexpected error occurred.";
147
+ throw new l(
148
148
  s,
149
- u.unexpected_error,
150
- m,
149
+ d.unexpected_error,
150
+ o,
151
151
  void 0,
152
152
  `${h}`,
153
153
  e.cause
@@ -156,99 +156,124 @@ const O = (t) => {
156
156
  }
157
157
  }
158
158
  }
159
- throw new k("Something went wrong.", e instanceof Error ? e : void 0);
159
+ throw new T("Something went wrong.", e instanceof Error ? e : void 0);
160
160
  }
161
- }, P = (t) => {
162
- a.interceptors.response.use(
163
- async (r) => {
161
+ }, k = 4, b = [25, 50, 100], E = async (t) => {
162
+ if (t.getRefreshTokenWithOutcome) {
163
+ const { token: r, outcome: e, errorMessage: s } = await t.getRefreshTokenWithOutcome();
164
+ return { token: r, outcome: e, errorMessage: s };
165
+ }
166
+ return { token: await t.getRefreshToken() };
167
+ }, $ = async (t) => {
168
+ let r = null, e, s;
169
+ for (let a = 0; a < k; a++) {
170
+ const o = await E(t);
171
+ if (r = o.token, e = o.outcome, s = o.errorMessage, r)
172
+ return {
173
+ token: r,
174
+ attempt: a,
175
+ outcome: e,
176
+ errorMessage: s
177
+ };
178
+ const u = b[a];
179
+ u !== void 0 && await new Promise((R) => setTimeout(R, u));
180
+ }
181
+ return {
182
+ token: r,
183
+ attempt: k - 1,
184
+ outcome: e,
185
+ errorMessage: s
186
+ };
187
+ }, U = (t, r) => {
188
+ n.interceptors.response.use(
189
+ async (e) => {
164
190
  try {
165
- if (b(r)) {
166
- o.sendSessionRefreshEvent({
191
+ if (q(e)) {
192
+ i.sendSessionRefreshEvent({
167
193
  name: "refresh_token_response"
168
194
  });
169
- const e = r.data?.refreshToken;
170
- e && (o.sendSessionRefreshEvent({
195
+ const s = e.data?.refreshToken;
196
+ s && (i.sendSessionRefreshEvent({
171
197
  name: "refresh_token_received"
172
198
  }), await Promise.race([
173
- t.setRefreshToken(e),
199
+ t.setRefreshToken(s),
174
200
  new Promise(
175
- (s, n) => setTimeout(() => n(new Error("setRefreshToken timed out after 5000ms")), 5e3)
201
+ (a, o) => setTimeout(() => o(new Error("setRefreshToken timed out after 5000ms")), 5e3)
176
202
  )
177
- ]), o.sendSessionRefreshEvent({
203
+ ]), i.sendSessionRefreshEvent({
178
204
  name: "refresh_token_stored"
179
205
  }));
180
206
  }
181
- } catch (e) {
182
- const s = e instanceof Error ? e.message : String(e);
183
- o.sendSessionRefreshEvent({
207
+ } catch (s) {
208
+ const a = s instanceof Error ? s.message : String(s);
209
+ i.sendSessionRefreshEvent({
184
210
  name: "refresh_token_store_failed",
185
- error_message: s
186
- }), console.warn("Failed to store refresh token:", e);
211
+ error_message: a
212
+ }), console.warn("Failed to store refresh token:", s);
187
213
  }
188
- return r;
214
+ return e;
189
215
  },
190
- (r) => Promise.reject(r)
191
- ), a.interceptors.request.use(async (r) => {
216
+ (e) => Promise.reject(e)
217
+ ), n.interceptors.request.use(async (e) => {
192
218
  try {
193
- if (T(r.url)) {
194
- const e = await t.getRefreshToken();
195
- e || setTimeout(() => {
196
- t.getRefreshToken().then((s) => {
197
- s && o.sendSessionRefreshEvent({
198
- name: "refresh_token_received_after_missing"
199
- });
200
- }).catch((s) => {
201
- const n = s instanceof Error ? s.message : String(s);
202
- o.sendSessionRefreshEvent({
203
- name: "refresh_token_retrieve_failed_after_missing",
204
- error_message: n
205
- });
206
- });
207
- }, 10), e ? (o.sendSessionRefreshEvent({
208
- name: "refresh_token_retrieved"
209
- }), r.data = {
210
- ...r.data,
211
- refreshToken: e
212
- }) : o.sendSessionRefreshEvent({
213
- name: "refresh_token_missing"
219
+ if (M(e.url)) {
220
+ const {
221
+ token: s,
222
+ attempt: a,
223
+ outcome: o,
224
+ errorMessage: u
225
+ } = r ? await $(t) : { ...await E(t), attempt: 0 };
226
+ s ? (i.sendSessionRefreshEvent({
227
+ name: "refresh_token_retrieved",
228
+ attempt: a,
229
+ read_outcome: o,
230
+ error_message: u
231
+ }), e.data = {
232
+ ...e.data,
233
+ refreshToken: s
234
+ }) : i.sendSessionRefreshEvent({
235
+ name: "refresh_token_missing",
236
+ attempt: a,
237
+ read_outcome: o,
238
+ error_message: u
214
239
  });
215
240
  }
216
- S(r.url) && (o.sendSessionRefreshEvent({
241
+ I(e.url) && (i.sendSessionRefreshEvent({
217
242
  name: "refresh_token_removing_token"
218
243
  }), await t.removeRefreshToken());
219
- } catch (e) {
220
- const s = e instanceof Error ? e.message : String(e);
221
- o.sendSessionRefreshEvent({
244
+ } catch (s) {
245
+ const a = s instanceof Error ? s.message : String(s);
246
+ i.sendSessionRefreshEvent({
222
247
  name: "refresh_token_retrieve_failed",
223
- error_message: s
224
- }), console.warn("Failed to retrieve refresh token:", e);
248
+ error_message: a
249
+ }), console.warn("Failed to retrieve refresh token:", s);
225
250
  }
226
- return r;
251
+ return e;
227
252
  });
228
- }, S = (t) => t ? /^\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/logout$/.test(t) : !1, T = (t) => t ? /^\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(refresh|logout)$/.test(t) : !1, b = (t) => {
253
+ }, I = (t) => t ? /^\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/logout$/.test(t) : !1, M = (t) => t ? /^\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(refresh|logout)$/.test(t) : !1, q = (t) => {
229
254
  const r = t.config.url;
230
255
  return r ? /^\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(verify\/(email|sms|siwe|oauth\/.*)|refresh)$/.test(
231
256
  r
232
257
  ) : !1;
233
- }, $ = (t) => {
234
- if (!a.getUri() || a.getUri() === "")
258
+ }, j = (t) => {
259
+ if (!n.getUri() || n.getUri() === "")
235
260
  throw new Error("CDP client URI not configured. Call configure() first.");
236
261
  if (!t.url || t.url === "")
237
262
  throw new Error("AxiosRequestConfig URL is empty. This should never happen.");
238
263
  if (!t.method || t.method === "")
239
264
  throw new Error("AxiosRequestConfig method is empty. This should never happen.");
240
- }, U = (t) => t.method?.toString().toUpperCase() || "GET", f = (t) => {
265
+ }, C = (t) => t.method?.toString().toUpperCase() || "GET", w = (t) => {
241
266
  if (!t.url)
242
267
  throw new Error("URL is required for authentication");
243
- const r = a.getUri() + t.url;
268
+ const r = n.getUri() + t.url;
244
269
  return new URL(r);
245
- }, v = (t) => {
246
- const r = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(refresh|logout)$/, e = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(mfa)$/, s = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/config$/, n = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/attestation\/(challenge|register)$/;
247
- return r.test(t) || e.test(t) || s.test(t) || n.test(t);
248
- }, I = (t) => !/^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/custom\/authenticate$/.test(t), _ = (t) => {
270
+ }, _ = (t) => {
271
+ const r = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(refresh|logout)$/, e = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(mfa)$/, s = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/config$/, a = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/attestation\/(challenge|register)$/;
272
+ return r.test(t) || e.test(t) || s.test(t) || a.test(t);
273
+ }, O = (t) => !/^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/custom\/authenticate$/.test(t), A = (t) => {
249
274
  const r = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/(init)$/, e = /^\/platform\/v2\/embedded-wallet-api\/projects\/[^/]+\/auth\/verify\//;
250
275
  return r.test(t) || e.test(t);
251
- }, q = (t) => [
276
+ }, x = (t) => [
252
277
  // Auth flows: prevent account takeover on mobile clients
253
278
  /\/auth\/verify\//,
254
279
  // VerifyEmailAuthentication, VerifySmsAuthentication, VerifyOAuthCode, VerifyOAuthEndUserIdentity
@@ -256,7 +281,7 @@ const O = (t) => {
256
281
  // RefreshAccessToken
257
282
  ].some((e) => e.test(t));
258
283
  export {
259
- z as cdpApiClient,
260
- O as configureCdpApiClient,
261
- D as setAuthManager
284
+ H as cdpApiClient,
285
+ N as configureCdpApiClient,
286
+ z as setAuthManager
262
287
  };
@@ -203,6 +203,13 @@ export declare type CdpOptions = {
203
203
  * relying on HTTP cookies.
204
204
  */
205
205
  refreshTokenStorage?: RefreshTokenStorage;
206
+ /**
207
+ * Whether to retry reading the refresh token when the initial read is empty.
208
+ * Enable on native platforms whose secure storage can transiently return empty
209
+ * on the first read after a cold start or app resume; leave off for web, where
210
+ * reads are synchronous and have no such race. Defaults to false.
211
+ */
212
+ retryTokenReads?: boolean;
206
213
  /**
207
214
  * Optional app attestation for native mobile platforms.
208
215
  * When provided, adds assertion headers to sensitive API calls to prove app integrity.
@@ -2533,6 +2540,19 @@ export declare type RefreshAccessTokenResult = NonNullable<Awaited<ReturnType<ty
2533
2540
  export declare interface RefreshTokenStorage {
2534
2541
  /** Retrieves the stored refresh token. */
2535
2542
  getRefreshToken(): Promise<string | null>;
2543
+ /**
2544
+ * Retrieves the stored refresh token with read outcome metadata.
2545
+ *
2546
+ * @returns Promise that resolves to the stored token and read outcome.
2547
+ */
2548
+ getRefreshTokenWithOutcome?(): Promise<{
2549
+ /** The stored refresh token, or null if not found or on error. */
2550
+ token: string | null;
2551
+ /** The outcome of the read: found, not found, or error. */
2552
+ outcome: "found" | "not_found" | "error";
2553
+ /** The error message when the read failed. */
2554
+ errorMessage?: string;
2555
+ }>;
2536
2556
  /** Stores a refresh token securely. */
2537
2557
  setRefreshToken(token: string): Promise<void>;
2538
2558
  /** Removes the stored refresh token. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cdp-api-client",
3
- "version": "0.0.116",
3
+ "version": "0.0.118",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**",