@bounded-sh/core 0.0.49 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/{index-D6xrWKP7.js → index-BaSw33ec.js} +131 -19
  2. package/dist/index-BaSw33ec.js.map +1 -0
  3. package/dist/{index-CXyMnWgK.mjs → index-DpfaeNTQ.mjs} +130 -20
  4. package/dist/index-DpfaeNTQ.mjs.map +1 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +3 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +1 -1
  9. package/dist/{realtime-store-Djb_Dm-M.mjs → realtime-store-CBdRkQfZ.mjs} +2 -2
  10. package/dist/{realtime-store-Djb_Dm-M.mjs.map → realtime-store-CBdRkQfZ.mjs.map} +1 -1
  11. package/dist/{realtime-store-HkfnxBu3.js → realtime-store-PVPxsvPr.js} +2 -2
  12. package/dist/{realtime-store-HkfnxBu3.js.map → realtime-store-PVPxsvPr.js.map} +1 -1
  13. package/dist/{solana-message-CTUg0Tqd.js → solana-message-BVJWVB6C.js} +2 -2
  14. package/dist/{solana-message-CTUg0Tqd.js.map → solana-message-BVJWVB6C.js.map} +1 -1
  15. package/dist/{solana-message-l5OZo1j2.mjs → solana-message-kTeT43eQ.mjs} +2 -2
  16. package/dist/{solana-message-l5OZo1j2.mjs.map → solana-message-kTeT43eQ.mjs.map} +1 -1
  17. package/dist/{solana-operations-TSE5Tbgo.mjs → solana-operations-B8UyHL26.mjs} +2 -2
  18. package/dist/{solana-operations-TSE5Tbgo.mjs.map → solana-operations-B8UyHL26.mjs.map} +1 -1
  19. package/dist/{solana-operations-CSh2uF_0.js → solana-operations-bXuuPlov.js} +2 -2
  20. package/dist/{solana-operations-CSh2uF_0.js.map → solana-operations-bXuuPlov.js.map} +1 -1
  21. package/dist/utils/api.d.ts +12 -0
  22. package/package.json +2 -2
  23. package/dist/index-CXyMnWgK.mjs.map +0 -1
  24. package/dist/index-D6xrWKP7.js.map +0 -1
@@ -3408,7 +3408,7 @@ class ServerSessionManager {
3408
3408
  const address = kp.publicKey.toBase58();
3409
3409
  /* fetch nonce from auth API */
3410
3410
  const nonce = await genAuthNonce();
3411
- const { genSolanaMessage } = await import('./solana-message-l5OZo1j2.mjs');
3411
+ const { genSolanaMessage } = await import('./solana-message-kTeT43eQ.mjs');
3412
3412
  const message = await genSolanaMessage(address, nonce);
3413
3413
  /* sign the message */
3414
3414
  const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), kp.secretKey);
@@ -3884,30 +3884,101 @@ class BoundedDeclineError extends Error {
3884
3884
 
3885
3885
  const apiClient = axios.create();
3886
3886
  const TRANSIENT_GET_STATUSES = new Set([500, 502, 503, 504]);
3887
+ const RATE_LIMIT_RETRY_BASE_DELAY_MS = 100;
3888
+ /** The window event emitted when the API responds with HTTP 429. */
3889
+ const RATE_LIMIT_EVENT_NAME = 'bounded:ratelimit';
3890
+ /** Dispatch a rate-limit event without affecting request error handling. */
3891
+ function dispatchRateLimitEvent(detail) {
3892
+ try {
3893
+ if (typeof window === 'undefined')
3894
+ return;
3895
+ const Ctor = globalThis.CustomEvent;
3896
+ if (typeof Ctor !== 'function')
3897
+ return;
3898
+ window.dispatchEvent(new Ctor(RATE_LIMIT_EVENT_NAME, {
3899
+ detail: Object.assign(Object.assign({}, detail), { at: Date.now() }),
3900
+ }));
3901
+ }
3902
+ catch (_a) {
3903
+ // Fire-and-forget: event consumers must never delay or mask the request.
3904
+ }
3905
+ }
3906
+ function getRateLimitEventDetail(error, attempt, willRetry) {
3907
+ var _a, _b;
3908
+ const endpoint = typeof ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url) === 'string' ? error.config.url : '';
3909
+ let path = endpoint;
3910
+ try {
3911
+ const parsed = new URL(endpoint);
3912
+ path = `${parsed.pathname}${parsed.search}`;
3913
+ }
3914
+ catch (_c) {
3915
+ // Keep a relative or otherwise non-standard endpoint as-is.
3916
+ }
3917
+ const responseBody = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data;
3918
+ const body = responseBody && typeof responseBody === 'object' && !Array.isArray(responseBody)
3919
+ ? responseBody
3920
+ : responseBody == null
3921
+ ? {}
3922
+ : { message: String(responseBody) };
3923
+ return Object.assign(Object.assign({}, body), { endpoint,
3924
+ path, status: 429, attempt,
3925
+ willRetry });
3926
+ }
3927
+ function getRateLimitAttempt(error) {
3928
+ var _a, _b;
3929
+ const retryCount = (_b = (_a = error.config) === null || _a === void 0 ? void 0 : _a['axios-retry']) === null || _b === void 0 ? void 0 : _b.retryCount;
3930
+ return typeof retryCount === 'number' ? retryCount + 1 : 1;
3931
+ }
3887
3932
  axiosRetry(apiClient, {
3888
3933
  retries: 2,
3889
3934
  retryCondition: (error) => {
3890
- var _a, _b, _c, _d, _e, _f;
3935
+ var _a, _b, _c, _d, _e, _f, _g, _h;
3891
3936
  // A caller cancellation is final. In particular, never turn a route
3892
3937
  // unmount into a fresh GET after its AbortSignal has fired.
3893
- if (axios.isCancel(error) || error.code === 'ERR_CANCELED' || ((_b = (_a = error.config) === null || _a === void 0 ? void 0 : _a.signal) === null || _b === void 0 ? void 0 : _b.aborted)) {
3938
+ const canceled = axios.isCancel(error)
3939
+ || error.code === 'ERR_CANCELED'
3940
+ || ((_b = (_a = error.config) === null || _a === void 0 ? void 0 : _a.signal) === null || _b === void 0 ? void 0 : _b.aborted);
3941
+ if (canceled) {
3942
+ if (((_c = error.response) === null || _c === void 0 ? void 0 : _c.status) === 429) {
3943
+ dispatchRateLimitEvent(getRateLimitEventDetail(error, getRateLimitAttempt(error), false));
3944
+ }
3894
3945
  return false;
3895
3946
  }
3947
+ // A 429 means the server did not execute the request, so retrying is
3948
+ // safe for every method, including POST requests to the queries API.
3949
+ if (((_d = error.response) === null || _d === void 0 ? void 0 : _d.status) === 429)
3950
+ return true;
3896
3951
  // Only retry idempotent GETs. Network failures and the small set of
3897
3952
  // conventional transient gateway/runtime statuses get two bounded
3898
- // retries; auth, policy, invariant, and usage-cap responses stay final.
3953
+ // retries; auth, policy, invariant, and other terminal responses stay final.
3899
3954
  // Writes are never retried because the server may already have applied
3900
3955
  // them before the response was lost.
3901
- if (((_d = (_c = error.config) === null || _c === void 0 ? void 0 : _c.method) === null || _d === void 0 ? void 0 : _d.toLowerCase()) !== 'get')
3956
+ if (((_f = (_e = error.config) === null || _e === void 0 ? void 0 : _e.method) === null || _f === void 0 ? void 0 : _f.toLowerCase()) !== 'get')
3902
3957
  return false;
3903
3958
  return axiosRetry.isNetworkError(error)
3904
- || TRANSIENT_GET_STATUSES.has((_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.status) !== null && _f !== void 0 ? _f : 0);
3959
+ || TRANSIENT_GET_STATUSES.has((_h = (_g = error.response) === null || _g === void 0 ? void 0 : _g.status) !== null && _h !== void 0 ? _h : 0);
3960
+ },
3961
+ retryDelay: (retryCount, error) => {
3962
+ var _a;
3963
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
3964
+ const exponentialCap = RATE_LIMIT_RETRY_BASE_DELAY_MS * (2 ** retryCount);
3965
+ return Math.floor(Math.random() * exponentialCap);
3966
+ }
3967
+ return axiosRetry.exponentialDelay(retryCount, error);
3905
3968
  },
3906
- retryDelay: axiosRetry.exponentialDelay,
3907
3969
  shouldResetTimeout: true,
3908
3970
  onRetry: (retryCount, error, requestConfig) => {
3971
+ var _a, _b, _c;
3972
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
3973
+ dispatchRateLimitEvent(getRateLimitEventDetail(error, retryCount, !((_b = requestConfig.signal) === null || _b === void 0 ? void 0 : _b.aborted)));
3974
+ }
3975
+ console.warn(`[bounded-sdk] retry ${retryCount} for ${(_c = requestConfig.method) === null || _c === void 0 ? void 0 : _c.toUpperCase()} ${requestConfig.url} - ${error.code || error.message}`);
3976
+ },
3977
+ onMaxRetryTimesExceeded: (error, retryCount) => {
3909
3978
  var _a;
3910
- console.warn(`[bounded-sdk] retry ${retryCount} for ${(_a = requestConfig.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()} ${requestConfig.url} — ${error.code || error.message}`);
3979
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
3980
+ dispatchRateLimitEvent(getRateLimitEventDetail(error, retryCount + 1, false));
3981
+ }
3911
3982
  },
3912
3983
  });
3913
3984
  const refreshInFlight = new Map();
@@ -5242,21 +5313,60 @@ async function getMany(paths, opts = {}) {
5242
5313
  }
5243
5314
  return results;
5244
5315
  }
5245
- async function runQuery(absolutePath, queryName, queryArgs, opts) {
5316
+ const MAX_RUN_QUERIES_PER_POST = 10;
5317
+ let pendingRunQueries = [];
5318
+ let runQueryFlushScheduled = false;
5319
+ function unwrapRunQueryRow(row, entry) {
5246
5320
  var _a;
5247
- const rows = await runQueryManyRows([{ absolutePath, queryName, queryArgs }], opts);
5248
- const row = rows[0];
5249
5321
  // The worker disambiguates a computed null from a failed/undeclared query
5250
- // with a per-row `error` string — surface it instead of returning undefined.
5322
+ // with a per-row `error` string, so surface it instead of returning undefined.
5251
5323
  if ((row === null || row === void 0 ? void 0 : row.error) != null) {
5252
5324
  const err = new Error(String(row.error));
5253
5325
  err.isQueryError = true;
5254
- err.queryName = queryName;
5255
- err.path = absolutePath;
5326
+ err.queryName = entry.queryName;
5327
+ err.path = entry.absolutePath;
5256
5328
  throw err;
5257
5329
  }
5258
5330
  return (_a = row === null || row === void 0 ? void 0 : row.result) !== null && _a !== void 0 ? _a : null;
5259
5331
  }
5332
+ function flushPendingRunQueries() {
5333
+ const pending = pendingRunQueries;
5334
+ pendingRunQueries = [];
5335
+ runQueryFlushScheduled = false;
5336
+ // Calls with any request overrides bypass this buffer, so every entry here
5337
+ // belongs to the same default-overrides identity bucket.
5338
+ for (let offset = 0; offset < pending.length; offset += MAX_RUN_QUERIES_PER_POST) {
5339
+ const chunk = pending.slice(offset, offset + MAX_RUN_QUERIES_PER_POST);
5340
+ void runQueryManyRows(chunk.map(({ entry }) => entry)).then((rows) => {
5341
+ chunk.forEach((caller, index) => {
5342
+ try {
5343
+ caller.resolve(unwrapRunQueryRow(rows[index], caller.entry));
5344
+ }
5345
+ catch (error) {
5346
+ caller.reject(error);
5347
+ }
5348
+ });
5349
+ }, (error) => {
5350
+ chunk.forEach(({ reject }) => reject(error));
5351
+ });
5352
+ }
5353
+ }
5354
+ async function runQuery(absolutePath, queryName, queryArgs, opts) {
5355
+ const entry = { absolutePath, queryName, queryArgs };
5356
+ // Auth, custom headers, timeout, and signal overrides must remain local to
5357
+ // one request, so any override-bearing call deliberately bypasses coalescing.
5358
+ if ((opts === null || opts === void 0 ? void 0 : opts._overrides) != null) {
5359
+ const rows = await runQueryManyRows([entry], opts);
5360
+ return unwrapRunQueryRow(rows[0], entry);
5361
+ }
5362
+ return new Promise((resolve, reject) => {
5363
+ pendingRunQueries.push({ entry, resolve, reject });
5364
+ if (!runQueryFlushScheduled) {
5365
+ runQueryFlushScheduled = true;
5366
+ queueMicrotask(flushPendingRunQueries);
5367
+ }
5368
+ });
5369
+ }
5260
5370
  async function runQueryMany(many, opts) {
5261
5371
  // Batch shape stays an array of result values (errored rows map to null) so
5262
5372
  // existing callers keep working; use runQuery for per-row error surfacing.
@@ -5445,11 +5555,11 @@ async function setMany(many, options) {
5445
5555
  transactionResult = await handleEvmTransaction(curTx.evmTransaction, authProvider, options);
5446
5556
  }
5447
5557
  else if (curTx.serializedTransaction) {
5448
- const { handlePreBuiltTransaction } = await import('./solana-operations-TSE5Tbgo.mjs');
5558
+ const { handlePreBuiltTransaction } = await import('./solana-operations-B8UyHL26.mjs');
5449
5559
  transactionResult = await handlePreBuiltTransaction(curTx, authProvider, options, expectedWritePaths);
5450
5560
  }
5451
5561
  else {
5452
- const { handleSolanaTransaction } = await import('./solana-operations-TSE5Tbgo.mjs');
5562
+ const { handleSolanaTransaction } = await import('./solana-operations-B8UyHL26.mjs');
5453
5563
  transactionResult = await handleSolanaTransaction(curTx, authProvider, options, expectedWritePaths);
5454
5564
  }
5455
5565
  // Sync items after all transactions are confirmed
@@ -7364,7 +7474,7 @@ async function doReconnectWithNewAuth() {
7364
7474
  console.warn('[WS v2] Failed to clear HTTP read cache on auth change:', error);
7365
7475
  }
7366
7476
  try {
7367
- const { reconnectRealtimeStoreWithNewAuth } = await import('./realtime-store-Djb_Dm-M.mjs');
7477
+ const { reconnectRealtimeStoreWithNewAuth } = await import('./realtime-store-CBdRkQfZ.mjs');
7368
7478
  await reconnectRealtimeStoreWithNewAuth();
7369
7479
  }
7370
7480
  catch (error) {
@@ -7709,7 +7819,7 @@ async function buildSetDocumentsTransaction(connection, idl, programProvider, pa
7709
7819
  }
7710
7820
  /** SIWS message creation is async already, so its onchain module can be lazy. */
7711
7821
  async function genSolanaMessage(address, nonce) {
7712
- const implementation = await import('./solana-message-l5OZo1j2.mjs');
7822
+ const implementation = await import('./solana-message-kTeT43eQ.mjs');
7713
7823
  return implementation.genSolanaMessage(address, nonce);
7714
7824
  }
7715
7825
  const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@@ -8241,5 +8351,5 @@ function defineLiveModule(mod) {
8241
8351
  return mod;
8242
8352
  }
8243
8353
 
8244
- export { normalizeEvmAddress as $, reconnectWithNewAuth as A, BoundedDeclineError as B, deriveDecline as C, dispatchDeclineEvent as D, DECLINE_EVENT_NAME as E, hasActiveConnection as F, increment as G, serverTimestamp as H, InsufficientBalanceError as I, now as J, toSeconds as K, toMillis as L, getIdToken as M, deriveUserIdentityFromIdToken as N, getActiveSessionManager as O, createSessionWithSignature as P, refreshSession as Q, ReactNativeSessionManager as R, ServerSessionManager as S, revokeSession as T, signSessionCreateMessage as U, genAuthNonce as V, WebSessionManager as W, buildSetDocumentsTransaction as X, convertRemainingAccounts as Y, genSolanaMessage as Z, genSiweMessage as _, getWebhookKeysUrl as a, toLowerEvmAddress as a0, assertCanonicalBoundedRuntimeWriteCalldata as a1, assertEvmTransactionMatchesWrite as a2, BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR as a3, BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR as a4, functions as a5, invoke as a6, FunctionInvokeError as a7, live as a8, intent as a9, status as aa, subscribeView as ab, LiveIntentError as ac, withEffects as ad, isEffectResult as ae, defineLiveModule as af, EFFECT_INTENT_ADDRESS as ag, bufferExports as b, get as c, getMany as d, docId as e, setMany as f, getConfig as g, setFile as h, init as i, getFiles as j, search as k, runQueryMany as l, runExpression as m, runExpressionMany as n, signMessage as o, signTransaction as p, queryAggregate as q, runQuery as r, set as s, signAndSubmitTransaction as t, count as u, aggregate as v, subscribe as w, closeAllSubscriptions as x, clearCache as y, getCachedData as z };
8245
- //# sourceMappingURL=index-CXyMnWgK.mjs.map
8354
+ export { genSolanaMessage as $, reconnectWithNewAuth as A, BoundedDeclineError as B, deriveDecline as C, dispatchDeclineEvent as D, DECLINE_EVENT_NAME as E, dispatchRateLimitEvent as F, hasActiveConnection as G, increment as H, InsufficientBalanceError as I, serverTimestamp as J, now as K, toSeconds as L, toMillis as M, getIdToken as N, deriveUserIdentityFromIdToken as O, ReactNativeSessionManager as P, getActiveSessionManager as Q, RATE_LIMIT_EVENT_NAME as R, ServerSessionManager as S, createSessionWithSignature as T, refreshSession as U, revokeSession as V, WebSessionManager as W, signSessionCreateMessage as X, genAuthNonce as Y, buildSetDocumentsTransaction as Z, convertRemainingAccounts as _, getWebhookKeysUrl as a, genSiweMessage as a0, normalizeEvmAddress as a1, toLowerEvmAddress as a2, assertCanonicalBoundedRuntimeWriteCalldata as a3, assertEvmTransactionMatchesWrite as a4, BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR as a5, BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR as a6, functions as a7, invoke as a8, FunctionInvokeError as a9, live as aa, intent as ab, status as ac, subscribeView as ad, LiveIntentError as ae, withEffects as af, isEffectResult as ag, defineLiveModule as ah, EFFECT_INTENT_ADDRESS as ai, bufferExports as b, get as c, getMany as d, docId as e, setMany as f, getConfig as g, setFile as h, init as i, getFiles as j, search as k, runQueryMany as l, runExpression as m, runExpressionMany as n, signMessage as o, signTransaction as p, queryAggregate as q, runQuery as r, set as s, signAndSubmitTransaction as t, count as u, aggregate as v, subscribe as w, closeAllSubscriptions as x, clearCache as y, getCachedData as z };
8355
+ //# sourceMappingURL=index-DpfaeNTQ.mjs.map