@dynamic-labs-wallet/node 1.0.104 → 1.0.106

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/index.cjs CHANGED
@@ -2256,6 +2256,106 @@ const revokeDelegation = async (client, { walletId })=>{
2256
2256
  }
2257
2257
  };
2258
2258
 
2259
+ const ERROR_MISSING_AUTHENTICATE_SCOPE = 'Environment API token is missing the waas.authenticate scope, which delegated gas sponsorship requires.';
2260
+ const ERROR_MISSING_SERVER_AUTH_JWT = 'waas/authenticate returned no JWT';
2261
+ const ERROR_SERVER_AUTH_EXCHANGE_FAILED = 'Server-auth token exchange failed';
2262
+ // Keyed by client instance, not environmentId, so a process serving several
2263
+ // environments never hands one environment's JWT to another's client. A WeakMap
2264
+ // rather than a field keeps DelegatedWalletClient's public type unchanged and
2265
+ // lets the entry die with the client. The value is the in-flight promise, not
2266
+ // the resolved client, so concurrent first calls share a single exchange.
2267
+ const serverAuthClients = new WeakMap();
2268
+ const statusOf = (error)=>{
2269
+ var _candidate_response;
2270
+ const candidate = error;
2271
+ var _candidate_response_status;
2272
+ return (_candidate_response_status = candidate == null ? void 0 : (_candidate_response = candidate.response) == null ? void 0 : _candidate_response.status) != null ? _candidate_response_status : candidate == null ? void 0 : candidate.status;
2273
+ };
2274
+ // Server body if there is one, transport message ("connect ECONNREFUSED") if there isn't.
2275
+ const detailOf = (error)=>{
2276
+ var _error_response;
2277
+ const data = error == null ? void 0 : (_error_response = error.response) == null ? void 0 : _error_response.data;
2278
+ var _error_message;
2279
+ const fallback = (_error_message = error == null ? void 0 : error.message) != null ? _error_message : 'Unknown error';
2280
+ if (typeof data === 'string') {
2281
+ return data || fallback;
2282
+ }
2283
+ var _data_error, _ref;
2284
+ return (_ref = (_data_error = data == null ? void 0 : data.error) != null ? _data_error : data == null ? void 0 : data.message) != null ? _ref : fallback;
2285
+ };
2286
+ const mint = async (client)=>{
2287
+ var _response_data_encodedJwts, _response_data;
2288
+ let response;
2289
+ try {
2290
+ response = await client.createApiClient().authenticateApiToken({
2291
+ environmentId: client.environmentId
2292
+ });
2293
+ } catch (error) {
2294
+ // The axios error never escapes, on any status — its config carries the
2295
+ // bearer token. Only status and the server's message are re-thrown.
2296
+ // 403 gets a named scope: redcoast only says "Insufficient scope permissions".
2297
+ const status = statusOf(error);
2298
+ if (status === 403) {
2299
+ throw new Error(ERROR_MISSING_AUTHENTICATE_SCOPE);
2300
+ }
2301
+ const statusStr = status ? ` (${status})` : '';
2302
+ const message = `${ERROR_SERVER_AUTH_EXCHANGE_FAILED}${statusStr}: ${detailOf(error)}`;
2303
+ throw Object.assign(new Error(message), {
2304
+ status
2305
+ });
2306
+ }
2307
+ const jwt = response == null ? void 0 : (_response_data = response.data) == null ? void 0 : (_response_data_encodedJwts = _response_data.encodedJwts) == null ? void 0 : _response_data_encodedJwts.minifiedJwt;
2308
+ if (!jwt) {
2309
+ throw new Error(ERROR_MISSING_SERVER_AUTH_JWT);
2310
+ }
2311
+ return client.createApiClient({
2312
+ authToken: jwt
2313
+ });
2314
+ };
2315
+ const authenticate = (client)=>{
2316
+ const cached = serverAuthClients.get(client);
2317
+ if (cached) {
2318
+ return cached;
2319
+ }
2320
+ const pending = mint(client);
2321
+ serverAuthClients.set(client, pending);
2322
+ // A rejected exchange must not stay cached, or every later call replays the
2323
+ // same failure instead of retrying. Callers await `pending` themselves, so
2324
+ // this handler exists only to evict.
2325
+ void pending.catch(()=>{
2326
+ if (serverAuthClients.get(client) === pending) {
2327
+ serverAuthClients.delete(client);
2328
+ }
2329
+ });
2330
+ return pending;
2331
+ };
2332
+ /**
2333
+ * Runs `fn` against an API client authenticated as a server-auth principal for
2334
+ * this environment, exchanging the delegated client's environment API token at
2335
+ * `waas/authenticate` on first use and caching the result per client instance.
2336
+ *
2337
+ * `fn` may be invoked twice: the JWT expires and can be revoked server-side, so
2338
+ * rather than tracking its lifetime the first call that comes back 401 re-mints
2339
+ * and retries once. Pass a `fn` that tolerates that retry.
2340
+ */ const withDelegatedServerAuth = async (client, fn)=>{
2341
+ const pending = authenticate(client);
2342
+ const apiClient = await pending;
2343
+ try {
2344
+ return await fn(apiClient);
2345
+ } catch (error) {
2346
+ if (statusOf(error) !== 401) {
2347
+ throw error;
2348
+ }
2349
+ // Only evict the entry this call actually used. A concurrent 401 may have
2350
+ // already replaced it, and dropping that fresh one would start yet another
2351
+ // exchange for every caller in the burst.
2352
+ if (serverAuthClients.get(client) === pending) {
2353
+ serverAuthClients.delete(client);
2354
+ }
2355
+ return fn(await authenticate(client));
2356
+ }
2357
+ };
2358
+
2259
2359
  function decryptAesGcm(key, ivB64, ctB64, tagB64) {
2260
2360
  const iv = Buffer.from(ivB64, 'base64url');
2261
2361
  const ciphertext = Buffer.from(ctB64, 'base64url');
@@ -2565,6 +2665,7 @@ exports.revokeDelegation = revokeDelegation;
2565
2665
  exports.signSessionMessage = signSessionMessage;
2566
2666
  exports.stringToBytes = stringToBytes;
2567
2667
  exports.stripHexPrefix = stripHexPrefix;
2668
+ exports.withDelegatedServerAuth = withDelegatedServerAuth;
2568
2669
  Object.keys(core).forEach(function (k) {
2569
2670
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
2570
2671
  enumerable: true,
package/index.esm.js CHANGED
@@ -2255,6 +2255,106 @@ const revokeDelegation = async (client, { walletId })=>{
2255
2255
  }
2256
2256
  };
2257
2257
 
2258
+ const ERROR_MISSING_AUTHENTICATE_SCOPE = 'Environment API token is missing the waas.authenticate scope, which delegated gas sponsorship requires.';
2259
+ const ERROR_MISSING_SERVER_AUTH_JWT = 'waas/authenticate returned no JWT';
2260
+ const ERROR_SERVER_AUTH_EXCHANGE_FAILED = 'Server-auth token exchange failed';
2261
+ // Keyed by client instance, not environmentId, so a process serving several
2262
+ // environments never hands one environment's JWT to another's client. A WeakMap
2263
+ // rather than a field keeps DelegatedWalletClient's public type unchanged and
2264
+ // lets the entry die with the client. The value is the in-flight promise, not
2265
+ // the resolved client, so concurrent first calls share a single exchange.
2266
+ const serverAuthClients = new WeakMap();
2267
+ const statusOf = (error)=>{
2268
+ var _candidate_response;
2269
+ const candidate = error;
2270
+ var _candidate_response_status;
2271
+ return (_candidate_response_status = candidate == null ? void 0 : (_candidate_response = candidate.response) == null ? void 0 : _candidate_response.status) != null ? _candidate_response_status : candidate == null ? void 0 : candidate.status;
2272
+ };
2273
+ // Server body if there is one, transport message ("connect ECONNREFUSED") if there isn't.
2274
+ const detailOf = (error)=>{
2275
+ var _error_response;
2276
+ const data = error == null ? void 0 : (_error_response = error.response) == null ? void 0 : _error_response.data;
2277
+ var _error_message;
2278
+ const fallback = (_error_message = error == null ? void 0 : error.message) != null ? _error_message : 'Unknown error';
2279
+ if (typeof data === 'string') {
2280
+ return data || fallback;
2281
+ }
2282
+ var _data_error, _ref;
2283
+ return (_ref = (_data_error = data == null ? void 0 : data.error) != null ? _data_error : data == null ? void 0 : data.message) != null ? _ref : fallback;
2284
+ };
2285
+ const mint = async (client)=>{
2286
+ var _response_data_encodedJwts, _response_data;
2287
+ let response;
2288
+ try {
2289
+ response = await client.createApiClient().authenticateApiToken({
2290
+ environmentId: client.environmentId
2291
+ });
2292
+ } catch (error) {
2293
+ // The axios error never escapes, on any status — its config carries the
2294
+ // bearer token. Only status and the server's message are re-thrown.
2295
+ // 403 gets a named scope: redcoast only says "Insufficient scope permissions".
2296
+ const status = statusOf(error);
2297
+ if (status === 403) {
2298
+ throw new Error(ERROR_MISSING_AUTHENTICATE_SCOPE);
2299
+ }
2300
+ const statusStr = status ? ` (${status})` : '';
2301
+ const message = `${ERROR_SERVER_AUTH_EXCHANGE_FAILED}${statusStr}: ${detailOf(error)}`;
2302
+ throw Object.assign(new Error(message), {
2303
+ status
2304
+ });
2305
+ }
2306
+ const jwt = response == null ? void 0 : (_response_data = response.data) == null ? void 0 : (_response_data_encodedJwts = _response_data.encodedJwts) == null ? void 0 : _response_data_encodedJwts.minifiedJwt;
2307
+ if (!jwt) {
2308
+ throw new Error(ERROR_MISSING_SERVER_AUTH_JWT);
2309
+ }
2310
+ return client.createApiClient({
2311
+ authToken: jwt
2312
+ });
2313
+ };
2314
+ const authenticate = (client)=>{
2315
+ const cached = serverAuthClients.get(client);
2316
+ if (cached) {
2317
+ return cached;
2318
+ }
2319
+ const pending = mint(client);
2320
+ serverAuthClients.set(client, pending);
2321
+ // A rejected exchange must not stay cached, or every later call replays the
2322
+ // same failure instead of retrying. Callers await `pending` themselves, so
2323
+ // this handler exists only to evict.
2324
+ void pending.catch(()=>{
2325
+ if (serverAuthClients.get(client) === pending) {
2326
+ serverAuthClients.delete(client);
2327
+ }
2328
+ });
2329
+ return pending;
2330
+ };
2331
+ /**
2332
+ * Runs `fn` against an API client authenticated as a server-auth principal for
2333
+ * this environment, exchanging the delegated client's environment API token at
2334
+ * `waas/authenticate` on first use and caching the result per client instance.
2335
+ *
2336
+ * `fn` may be invoked twice: the JWT expires and can be revoked server-side, so
2337
+ * rather than tracking its lifetime the first call that comes back 401 re-mints
2338
+ * and retries once. Pass a `fn` that tolerates that retry.
2339
+ */ const withDelegatedServerAuth = async (client, fn)=>{
2340
+ const pending = authenticate(client);
2341
+ const apiClient = await pending;
2342
+ try {
2343
+ return await fn(apiClient);
2344
+ } catch (error) {
2345
+ if (statusOf(error) !== 401) {
2346
+ throw error;
2347
+ }
2348
+ // Only evict the entry this call actually used. A concurrent 401 may have
2349
+ // already replaced it, and dropping that fresh one would start yet another
2350
+ // exchange for every caller in the burst.
2351
+ if (serverAuthClients.get(client) === pending) {
2352
+ serverAuthClients.delete(client);
2353
+ }
2354
+ return fn(await authenticate(client));
2355
+ }
2356
+ };
2357
+
2258
2358
  function decryptAesGcm(key, ivB64, ctB64, tagB64) {
2259
2359
  const iv = Buffer.from(ivB64, 'base64url');
2260
2360
  const ciphertext = Buffer.from(ctB64, 'base64url');
@@ -2524,4 +2624,4 @@ const asAuthError = async (error, operation)=>{
2524
2624
  };
2525
2625
  }
2526
2626
 
2527
- export { DynamicWalletClient, base64ToBytes, bytesToBase64, createAuthClient, createDelegatedWalletClient, createLogError, decryptDelegatedWebhookData, delegatedSignMessage, ensureBase64Padding, formatEvmMessage, formatMessage, generateSessionKeyPair, getExternalServerKeyShareBackupInfo, getMPCSignatureScheme, getMPCSigner, isHexString, logError, mergeUniqueKeyShares, parseIndexMapDerivationPath, retryPromise, revokeDelegation, signSessionMessage, stringToBytes, stripHexPrefix };
2627
+ export { DynamicWalletClient, base64ToBytes, bytesToBase64, createAuthClient, createDelegatedWalletClient, createLogError, decryptDelegatedWebhookData, delegatedSignMessage, ensureBase64Padding, formatEvmMessage, formatMessage, generateSessionKeyPair, getExternalServerKeyShareBackupInfo, getMPCSignatureScheme, getMPCSigner, isHexString, logError, mergeUniqueKeyShares, parseIndexMapDerivationPath, retryPromise, revokeDelegation, signSessionMessage, stringToBytes, stripHexPrefix, withDelegatedServerAuth };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/node",
3
- "version": "1.0.104",
3
+ "version": "1.0.106",
4
4
  "license": "Licensed under the Dynamic Labs, Inc. Terms Of Service (https://www.dynamic.xyz/terms-conditions)",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@dynamic-labs-wallet/core": "1.0.104",
7
+ "@dynamic-labs-wallet/core": "1.0.106",
8
8
  "@dynamic-labs-wallet/forward-mpc-client": "1.0.1",
9
- "@dynamic-labs-wallet/primitives": "1.0.104",
9
+ "@dynamic-labs-wallet/primitives": "1.0.106",
10
10
  "@dynamic-labs/logger": "^5.0.0",
11
11
  "@dynamic-labs/sdk-api-core": "^0.0.1093",
12
12
  "uuid": "11.1.0",
@@ -2,6 +2,7 @@ export { createDelegatedWalletClient } from './createDelegatedClient.js';
2
2
  export type { DelegatedWalletClient, DelegatedClientConfig } from './createDelegatedClient.js';
3
3
  export { delegatedSignMessage } from './modules/sign.js';
4
4
  export { revokeDelegation } from './modules/revokeDelegation.js';
5
+ export { withDelegatedServerAuth } from './modules/serverAuth.js';
5
6
  export { decryptDelegatedWebhookData } from './modules/decryptWebhookData.js';
6
7
  export type { EncryptedDelegatedPayload } from './modules/decryptWebhookData.js';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delegatedClient/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAG/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delegatedClient/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAG/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { DynamicApiClient } from '@dynamic-labs-wallet/core';
2
+ import type { DelegatedWalletClient } from '../createDelegatedClient.js';
3
+ export declare const ERROR_MISSING_AUTHENTICATE_SCOPE = "Environment API token is missing the waas.authenticate scope, which delegated gas sponsorship requires.";
4
+ export declare const ERROR_MISSING_SERVER_AUTH_JWT = "waas/authenticate returned no JWT";
5
+ export declare const ERROR_SERVER_AUTH_EXCHANGE_FAILED = "Server-auth token exchange failed";
6
+ /**
7
+ * Runs `fn` against an API client authenticated as a server-auth principal for
8
+ * this environment, exchanging the delegated client's environment API token at
9
+ * `waas/authenticate` on first use and caching the result per client instance.
10
+ *
11
+ * `fn` may be invoked twice: the JWT expires and can be revoked server-side, so
12
+ * rather than tracking its lifetime the first call that comes back 401 re-mints
13
+ * and retries once. Pass a `fn` that tolerates that retry.
14
+ */
15
+ export declare const withDelegatedServerAuth: <T>(client: DelegatedWalletClient, fn: (apiClient: DynamicApiClient) => Promise<T>) => Promise<T>;
16
+ //# sourceMappingURL=serverAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serverAuth.d.ts","sourceRoot":"","sources":["../../../src/delegatedClient/modules/serverAuth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE,eAAO,MAAM,gCAAgC,4GAC8D,CAAC;AAE5G,eAAO,MAAM,6BAA6B,sCAAsC,CAAC;AAEjF,eAAO,MAAM,iCAAiC,sCAAsC,CAAC;AA6ErF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,GAAU,CAAC,UACrC,qBAAqB,MACzB,CAAC,SAAS,EAAE,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,KAC9C,OAAO,CAAC,CAAC,CAoBX,CAAC"}
package/src/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export * from './types.js';
9
9
  export * from './utils.js';
10
10
  export { generateSessionKeyPair, signSessionMessage } from './sessionKeys.js';
11
11
  export * from './mpc/index.js';
12
- export { createDelegatedWalletClient, delegatedSignMessage, revokeDelegation, decryptDelegatedWebhookData, } from './delegatedClient/index.js';
12
+ export { createDelegatedWalletClient, delegatedSignMessage, revokeDelegation, decryptDelegatedWebhookData, withDelegatedServerAuth, } from './delegatedClient/index.js';
13
13
  export type { DelegatedWalletClient, DelegatedClientConfig, EncryptedDelegatedPayload, } from './delegatedClient/index.js';
14
14
  export { createAuthClient } from './authClient.js';
15
15
  export type { AuthResult, CreateAuthClientOptions, DynamicAuthClient } from './authClient.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG/F,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACrE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG1F,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,gBAAgB,EAChB,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG/F,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACrE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG1F,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,gBAAgB,EAChB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}