@pooflabs/core 0.0.38 → 0.0.39

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,10 +1,29 @@
1
+ import { AuthProvider } from '../types';
1
2
  import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
3
+ /** Internal overrides for per-request auth and headers. */
4
+ export type RequestOverrides = {
5
+ headers?: Record<string, string>;
6
+ authProvider?: AuthProvider;
7
+ _getAuthHeaders?: () => Promise<Record<string, string>>;
8
+ _clearAuth?: () => Promise<void>;
9
+ _walletAddress?: string;
10
+ };
2
11
  export type SetOptions = {
3
12
  shouldSubmitTx?: boolean;
4
- _overrides?: {
5
- headers?: Record<string, string>;
6
- };
13
+ _overrides?: RequestOverrides;
7
14
  };
15
+ /**
16
+ * Thrown when a user's wallet doesn't have enough SOL to cover the transaction.
17
+ * Apps can catch this to trigger an onramp/funding flow.
18
+ */
19
+ export declare class InsufficientBalanceError extends Error {
20
+ address: string;
21
+ balanceLamports: number;
22
+ estimatedCostLamports: number;
23
+ deficitLamports: number;
24
+ deficitSol: number;
25
+ constructor(address: string, balanceLamports: number, estimatedCostLamports: number, deficitLamports: number, deficitSol: number);
26
+ }
8
27
  /**
9
28
  * Options for the get function.
10
29
  */
@@ -21,15 +40,10 @@ export type GetOptions = {
21
40
  limit?: number;
22
41
  /** Opaque cursor for cursor-based pagination (used with limit) */
23
42
  cursor?: string;
24
- /** Internal overrides for headers */
25
- _overrides?: {
26
- headers?: Record<string, string>;
27
- };
43
+ _overrides?: RequestOverrides;
28
44
  };
29
45
  export type RunQueryOptions = {
30
- _overrides?: {
31
- headers?: Record<string, string>;
32
- };
46
+ _overrides?: RequestOverrides;
33
47
  };
34
48
  /**
35
49
  * Supported aggregate operations for count/aggregate queries.
@@ -47,10 +61,7 @@ export type AggregateResult = {
47
61
  export type CountOptions = {
48
62
  /** Natural language filter prompt (e.g., "posts created in the last 7 days") */
49
63
  prompt?: string;
50
- /** Internal overrides for headers */
51
- _overrides?: {
52
- headers?: Record<string, string>;
53
- };
64
+ _overrides?: RequestOverrides;
54
65
  };
55
66
  /**
56
67
  * Options for the aggregate function.
@@ -60,10 +71,7 @@ export type AggregateOptions = {
60
71
  prompt?: string;
61
72
  /** Field name to aggregate on (required for sum, avg, min, max) */
62
73
  field?: string;
63
- /** Internal overrides for headers */
64
- _overrides?: {
65
- headers?: Record<string, string>;
66
- };
74
+ _overrides?: RequestOverrides;
67
75
  };
68
76
  /**
69
77
  * Count items in a collection path. Returns a numeric result.
@@ -107,9 +115,7 @@ export declare function aggregate(path: string, operation: AggregateOperation, o
107
115
  export declare function get(path: string, opts?: GetOptions): Promise<any>;
108
116
  export type RunExpressionOptions = {
109
117
  returnType?: 'Bool' | 'String' | 'Int' | 'UInt';
110
- _overrides?: {
111
- headers?: Record<string, string>;
112
- };
118
+ _overrides?: RequestOverrides;
113
119
  };
114
120
  export type RunExpressionResult = {
115
121
  result: any;
@@ -131,9 +137,7 @@ export declare function runExpressionMany(many: {
131
137
  expression: string;
132
138
  queryArgs: any;
133
139
  returnType?: 'Bool' | 'String' | 'Int' | 'UInt';
134
- _overrides?: {
135
- headers?: Record<string, string>;
136
- };
140
+ _overrides?: RequestOverrides;
137
141
  }[]): Promise<RunExpressionResult[]>;
138
142
  export declare function set(path: string, document: any, options?: SetOptions): Promise<any>;
139
143
  export declare function setMany(many: {
@@ -144,14 +148,10 @@ export declare function clearCache(path?: string, opts?: {
144
148
  prompt?: string;
145
149
  }): void;
146
150
  export declare function getFiles(path: string, options?: {
147
- _overrides?: {
148
- headers?: Record<string, string>;
149
- };
151
+ _overrides?: RequestOverrides;
150
152
  }): Promise<any>;
151
153
  export declare function setFile(path: string, file: File | null, options?: {
152
- _overrides?: {
153
- headers?: Record<string, string>;
154
- };
154
+ _overrides?: RequestOverrides;
155
155
  }): Promise<boolean>;
156
156
  export declare function signMessage(message: string): Promise<string>;
157
157
  export declare function signTransaction(transaction: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { init } from './client/config';
2
2
  export { getConfig, ClientConfig } from './client/config';
3
- export { get, set, setMany, setFile, getFiles, runQuery, runQueryMany, runExpression, runExpressionMany, signMessage, signTransaction, signAndSubmitTransaction, count, aggregate, SetOptions, GetOptions, CountOptions, AggregateOptions, AggregateOperation, AggregateResult, RunExpressionOptions, RunExpressionResult } from './client/operations';
3
+ export { get, set, setMany, setFile, getFiles, runQuery, runQueryMany, runExpression, runExpressionMany, signMessage, signTransaction, signAndSubmitTransaction, count, aggregate, RequestOverrides, SetOptions, GetOptions, RunQueryOptions, CountOptions, AggregateOptions, AggregateOperation, AggregateResult, RunExpressionOptions, RunExpressionResult, InsufficientBalanceError } from './client/operations';
4
4
  export { subscribe, closeAllSubscriptions, clearCache, getCachedData, reconnectWithNewAuth } from './client/subscription';
5
5
  export * from './types';
6
6
  export { getIdToken } from './utils/utils';
package/dist/index.js CHANGED
@@ -3047,31 +3047,39 @@ function loadKeypairFromEnv() {
3047
3047
  }
3048
3048
  }
3049
3049
  /* ------------------------------------------------------------------ */
3050
- /* REAL createSession() */
3051
- /* ------------------------------------------------------------------ */
3052
- async function createSession() {
3053
- const kp = loadKeypairFromEnv();
3054
- const address = kp.publicKey.toBase58();
3055
- /* fetch nonce from auth API */
3056
- const nonce = await genAuthNonce();
3057
- const message = await genSolanaMessage(address, nonce);
3058
- /* sign the message */
3059
- const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), kp.secretKey);
3060
- const signature = bufferExports.Buffer.from(sigBytes).toString("base64");
3061
- /* call auth API */
3062
- const { accessToken, idToken, refreshToken, } = await createSessionWithSignature(address, message, signature);
3063
- return { address, accessToken, idToken, refreshToken };
3064
- }
3065
- /* ------------------------------------------------------------------ */
3066
- /* SINGLETON */
3050
+ /* SESSION MANAGER */
3067
3051
  /* ------------------------------------------------------------------ */
3068
3052
  class ServerSessionManager {
3069
- /* Private constructor prevents external `new` */
3070
- constructor() {
3071
- /* Private cache (lives for the life of the process) */
3053
+ constructor(keypair) {
3054
+ /* Private cache (lives for the life of the instance) */
3072
3055
  this.session = null;
3073
3056
  /* Coalesce concurrent getSession() calls into a single in-flight request */
3074
3057
  this.pendingSession = null;
3058
+ this.keypair = keypair !== null && keypair !== void 0 ? keypair : null;
3059
+ }
3060
+ /**
3061
+ * Create a session manager for a specific keypair.
3062
+ * Each instance has its own independent session cache.
3063
+ */
3064
+ static forKeypair(keypair) {
3065
+ return new ServerSessionManager(keypair);
3066
+ }
3067
+ /* ---------------------------------------------- *
3068
+ * Session creation (instance method)
3069
+ * ---------------------------------------------- */
3070
+ async createSession() {
3071
+ var _a;
3072
+ const kp = (_a = this.keypair) !== null && _a !== void 0 ? _a : loadKeypairFromEnv();
3073
+ const address = kp.publicKey.toBase58();
3074
+ /* fetch nonce from auth API */
3075
+ const nonce = await genAuthNonce();
3076
+ const message = await genSolanaMessage(address, nonce);
3077
+ /* sign the message */
3078
+ const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), kp.secretKey);
3079
+ const signature = bufferExports.Buffer.from(sigBytes).toString("base64");
3080
+ /* call auth API */
3081
+ const { accessToken, idToken, refreshToken, } = await createSessionWithSignature(address, message, signature);
3082
+ return { address, accessToken, idToken, refreshToken };
3075
3083
  }
3076
3084
  /* ---------------------------------------------- *
3077
3085
  * GET (lazy-fetch)
@@ -3085,7 +3093,7 @@ class ServerSessionManager {
3085
3093
  if (this.pendingSession !== null) {
3086
3094
  return this.pendingSession;
3087
3095
  }
3088
- this.pendingSession = createSession()
3096
+ this.pendingSession = this.createSession()
3089
3097
  .then((session) => {
3090
3098
  this.session = session;
3091
3099
  return session;
@@ -3102,7 +3110,7 @@ class ServerSessionManager {
3102
3110
  this.session = session;
3103
3111
  }
3104
3112
  /* ---------------------------------------------- *
3105
- * CLEAR (e.g. after logout)
3113
+ * CLEAR (e.g. after logout or 401 retry)
3106
3114
  * ---------------------------------------------- */
3107
3115
  clearSession() {
3108
3116
  this.session = null;
@@ -3123,7 +3131,7 @@ class ServerSessionManager {
3123
3131
  return (_b = (_a = this.session) === null || _a === void 0 ? void 0 : _a.refreshToken) !== null && _b !== void 0 ? _b : null;
3124
3132
  }
3125
3133
  }
3126
- /* The single, shared instance */
3134
+ /* The default singleton instance (reads keypair from env) */
3127
3135
  ServerSessionManager.instance = new ServerSessionManager();
3128
3136
 
3129
3137
  var serverSessionManager = /*#__PURE__*/Object.freeze({
@@ -3238,7 +3246,11 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
3238
3246
  ServerSessionManager.instance.clearSession();
3239
3247
  };
3240
3248
  async function executeRequest() {
3241
- const authHeader = await createAuthHeader(config.isServer);
3249
+ // When _getAuthHeaders is provided (wallet client), use it as the sole auth source.
3250
+ // Otherwise use the global createAuthHeader (default path).
3251
+ const authHeader = (_overrides === null || _overrides === void 0 ? void 0 : _overrides._getAuthHeaders)
3252
+ ? await _overrides._getAuthHeaders()
3253
+ : await createAuthHeader(config.isServer);
3242
3254
  const headers = Object.assign({ "Content-Type": "application/json", "X-Public-App-Id": config.appId, "X-App-Id": config.appId }, authHeader);
3243
3255
  if (typeof window !== "undefined" &&
3244
3256
  window.CUSTOM_TAROBASE_APP_ID_HEADER) {
@@ -3267,6 +3279,13 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
3267
3279
  }
3268
3280
  catch (error) {
3269
3281
  if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
3282
+ // Wallet client path: use client-specific retry, skip global fallback entirely
3283
+ if (_overrides === null || _overrides === void 0 ? void 0 : _overrides._clearAuth) {
3284
+ await _overrides._clearAuth();
3285
+ return await executeRequest();
3286
+ // If this throws, let it propagate — do NOT clear global ServerSessionManager
3287
+ }
3288
+ // Default path (no wallet client): refresh global session
3270
3289
  try {
3271
3290
  const refreshed = await refreshAuthSessionOnce(config.appId, config.isServer);
3272
3291
  if (!refreshed) {
@@ -3275,8 +3294,7 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
3275
3294
  return await executeRequest();
3276
3295
  }
3277
3296
  catch (_refreshError) {
3278
- // Server-side fallback: clear cached session and retry once to force
3279
- // createSession() with a fresh Cognito session.
3297
+ // Server-side fallback: clear global session and retry once
3280
3298
  if (config.isServer && !hasRetriedAfterServerSessionReset) {
3281
3299
  hasRetriedAfterServerSessionReset = true;
3282
3300
  await clearServerSession();
@@ -3394,6 +3412,21 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
3394
3412
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
3395
3413
  };
3396
3414
 
3415
+ /**
3416
+ * Thrown when a user's wallet doesn't have enough SOL to cover the transaction.
3417
+ * Apps can catch this to trigger an onramp/funding flow.
3418
+ */
3419
+ class InsufficientBalanceError extends Error {
3420
+ constructor(address, balanceLamports, estimatedCostLamports, deficitLamports, deficitSol) {
3421
+ super(`Insufficient balance: wallet ${address} needs ~${deficitSol.toFixed(6)} SOL more to complete this transaction.`);
3422
+ this.name = 'InsufficientBalanceError';
3423
+ this.address = address;
3424
+ this.balanceLamports = balanceLamports;
3425
+ this.estimatedCostLamports = estimatedCostLamports;
3426
+ this.deficitLamports = deficitLamports;
3427
+ this.deficitSol = deficitSol;
3428
+ }
3429
+ }
3397
3430
  // Cache for get responses
3398
3431
  const getCache = {};
3399
3432
  // Track in-flight requests to coalesce multiple identical requests
@@ -3554,6 +3587,7 @@ async function aggregate(path, operation, opts = {}) {
3554
3587
  return { value: parseAggregateValue(result) };
3555
3588
  }
3556
3589
  async function get(path, opts = {}) {
3590
+ var _a;
3557
3591
  try {
3558
3592
  let normalizedPath = path.startsWith("/") ? path.slice(1) : path;
3559
3593
  // Remove last '*' if it exists in the path
@@ -3563,12 +3597,13 @@ async function get(path, opts = {}) {
3563
3597
  if (!normalizedPath || normalizedPath.length === 0) {
3564
3598
  return new Error("Invalid path provided.");
3565
3599
  }
3566
- // Create cache key combining path, prompt, includeSubPaths, shape, limit, and cursor
3600
+ // Create cache key combining path, prompt, includeSubPaths, shape, limit, cursor, and wallet
3567
3601
  const shapeKey = opts.shape ? JSON.stringify(opts.shape) : '';
3568
3602
  const includeSubPathsKey = opts.includeSubPaths ? ':subpaths' : '';
3569
3603
  const limitKey = opts.limit !== undefined ? `:l${opts.limit}` : '';
3570
3604
  const cursorKey = opts.cursor ? `:c${hashForKey$1(opts.cursor)}` : '';
3571
- const cacheKey = `${normalizedPath}:${opts.prompt || ''}${includeSubPathsKey}:${shapeKey}${limitKey}${cursorKey}`;
3605
+ const walletSuffix = ((_a = opts._overrides) === null || _a === void 0 ? void 0 : _a._walletAddress) ? `:w${opts._overrides._walletAddress}` : '';
3606
+ const cacheKey = `${normalizedPath}:${opts.prompt || ''}${includeSubPathsKey}:${shapeKey}${limitKey}${cursorKey}${walletSuffix}`;
3572
3607
  const now = Date.now();
3573
3608
  // Check for valid cache entry if not bypassing cache
3574
3609
  if (!opts.bypassCache && getCache[cacheKey] && now < getCache[cacheKey].expiresAt) {
@@ -3707,10 +3742,11 @@ async function set(path, document, options) {
3707
3742
  return result;
3708
3743
  }
3709
3744
  async function setMany(many, options) {
3745
+ var _a, _b, _c, _d, _e, _f, _g;
3710
3746
  // Returns the data that was set, or undefined if the document was already set.
3711
3747
  try {
3712
3748
  const config = await getConfig();
3713
- const authProvider = config.authProvider;
3749
+ const authProvider = (_b = (_a = options === null || options === void 0 ? void 0 : options._overrides) === null || _a === void 0 ? void 0 : _a.authProvider) !== null && _b !== void 0 ? _b : config.authProvider;
3714
3750
  if (!authProvider) {
3715
3751
  throw new Error('Auth provider not initialized');
3716
3752
  }
@@ -3741,7 +3777,18 @@ async function setMany(many, options) {
3741
3777
  }
3742
3778
  documents.push({ destinationPath, document });
3743
3779
  }
3744
- const setResponse = await makeApiRequest('PUT', `items`, { documents }, options === null || options === void 0 ? void 0 : options._overrides);
3780
+ let setResponse;
3781
+ try {
3782
+ setResponse = await makeApiRequest('PUT', `items`, { documents }, options === null || options === void 0 ? void 0 : options._overrides);
3783
+ }
3784
+ catch (error) {
3785
+ if ((error === null || error === void 0 ? void 0 : error.statusCode) === 402 && (error === null || error === void 0 ? void 0 : error.error) === 'INSUFFICIENT_BALANCE') {
3786
+ const deficitLamports = Number((_c = error.deficitLamports) !== null && _c !== void 0 ? _c : 0);
3787
+ const deficitSol = Number((_d = error.deficitSol) !== null && _d !== void 0 ? _d : deficitLamports / 1000000000);
3788
+ throw new InsufficientBalanceError(String((_e = error.address) !== null && _e !== void 0 ? _e : ''), Number((_f = error.balanceLamports) !== null && _f !== void 0 ? _f : 0), Number((_g = error.estimatedCostLamports) !== null && _g !== void 0 ? _g : 0), deficitLamports, deficitSol);
3789
+ }
3790
+ throw error;
3791
+ }
3745
3792
  // Invalidate caches and pending requests for affected paths
3746
3793
  pathsToInvalidate.forEach(path => {
3747
3794
  clearCacheByPrefix(path);
@@ -3782,7 +3829,7 @@ async function setMany(many, options) {
3782
3829
  else if (setResponse.data &&
3783
3830
  typeof setResponse.data === 'object' &&
3784
3831
  setResponse.data.success === true) {
3785
- const _a = setResponse.data, { success: _success } = _a, rest = __rest(_a, ["success"]);
3832
+ const _h = setResponse.data, { success: _success } = _h, rest = __rest(_h, ["success"]);
3786
3833
  return Object.assign(Object.assign(Object.assign({}, documents.map(d => d.document)), rest), { transactionId: null });
3787
3834
  }
3788
3835
  else {
@@ -3849,7 +3896,7 @@ async function setMany(many, options) {
3849
3896
  return transactionResult;
3850
3897
  }
3851
3898
  async function handleOffchainTransaction(tx, authProvider, options) {
3852
- var _a, _b, _c, _d, _e;
3899
+ var _a, _b, _c, _d, _e, _f;
3853
3900
  const config = await getConfig();
3854
3901
  // 1. Sign the transaction message using mock signing for offchain transactions
3855
3902
  // Use signMessageMock if available (OffchainAuthProvider), otherwise fall back to signMessage
@@ -3868,32 +3915,18 @@ async function setMany(many, options) {
3868
3915
  signedTransaction: bufferExports.Buffer.from(JSON.stringify(signedTx)).toString('base64')
3869
3916
  };
3870
3917
  }
3871
- // 4. Submit to RPC endpoint
3872
- // Use appId from headers if provided, otherwise fallback to config.appId
3918
+ // 4. Submit to RPC endpoint via makeApiRequest (gets auth headers + 401 retry)
3873
3919
  const appId = ((_b = (_a = options === null || options === void 0 ? void 0 : options._overrides) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b['x-app-id']) || ((_d = (_c = options === null || options === void 0 ? void 0 : options._overrides) === null || _c === void 0 ? void 0 : _c.headers) === null || _d === void 0 ? void 0 : _d['X-App-Id']) || config.appId;
3874
- const rpcUrl = `${config.apiUrl}/app/${appId}/rpc`;
3875
- // Build headers, applying overrides if provided
3876
- const headers = {
3877
- 'Content-Type': 'application/json',
3878
- };
3879
- if ((_e = options === null || options === void 0 ? void 0 : options._overrides) === null || _e === void 0 ? void 0 : _e.headers) {
3880
- Object.assign(headers, options._overrides.headers);
3881
- }
3882
- const rpcResponse = await fetch(rpcUrl, {
3883
- method: 'POST',
3884
- headers,
3885
- body: JSON.stringify({
3886
- jsonrpc: '2.0',
3887
- id: 1,
3888
- method: 'sendTransaction',
3889
- params: [bufferExports.Buffer.from(JSON.stringify(signedTx)).toString('base64')]
3890
- })
3891
- });
3892
- const result = await rpcResponse.json();
3893
- if (result.error) {
3894
- throw new Error(result.error.message);
3920
+ const rpcResponse = await makeApiRequest('POST', `/app/${appId}/rpc`, {
3921
+ jsonrpc: '2.0',
3922
+ id: 1,
3923
+ method: 'sendTransaction',
3924
+ params: [bufferExports.Buffer.from(JSON.stringify(signedTx)).toString('base64')]
3925
+ }, options === null || options === void 0 ? void 0 : options._overrides);
3926
+ if ((_e = rpcResponse.data) === null || _e === void 0 ? void 0 : _e.error) {
3927
+ throw new Error(rpcResponse.data.error.message);
3895
3928
  }
3896
- return { signature: result.result };
3929
+ return { signature: (_f = rpcResponse.data) === null || _f === void 0 ? void 0 : _f.result };
3897
3930
  }
3898
3931
  }
3899
3932
  // Helper to clear cache entries by prefix
@@ -4726,6 +4759,7 @@ async function reconnectWithNewAuth() {
4726
4759
  return reconnectWithNewAuthV2();
4727
4760
  }
4728
4761
 
4762
+ exports.InsufficientBalanceError = InsufficientBalanceError;
4729
4763
  exports.ServerSessionManager = ServerSessionManager;
4730
4764
  exports.WebSessionManager = WebSessionManager;
4731
4765
  exports.aggregate = aggregate;