@pooflabs/core 0.0.46 → 0.0.47-rc1

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/dist/index.mjs CHANGED
@@ -376,6 +376,28 @@ class WebSessionManager {
376
376
  static async storeSession(address, accessToken, idToken, refreshToken) {
377
377
  if (typeof window === "undefined")
378
378
  return;
379
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
380
+ // to a different wallet than `address`. Prevents races that would otherwise
381
+ // leave localStorage with mismatched address/token state.
382
+ try {
383
+ const payloadB64 = idToken.split(".")[1];
384
+ if (payloadB64) {
385
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
386
+ const tokenWallet = payload["custom:walletAddress"];
387
+ if (tokenWallet && tokenWallet !== address) {
388
+ throw new Error(`[WebSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
389
+ }
390
+ if (!tokenWallet) {
391
+ console.warn("[WebSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
392
+ }
393
+ }
394
+ }
395
+ catch (err) {
396
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
397
+ throw err;
398
+ }
399
+ console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
400
+ }
379
401
  const config = await getConfig();
380
402
  const currentAppId = config.appId;
381
403
  localStorage.setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -3166,12 +3188,6 @@ async function genSolanaMessage(address, nonce) {
3166
3188
  // Serialization Helpers
3167
3189
  // ─────────────────────────────────────────────────────────────
3168
3190
  function isHexString(value) {
3169
- // Only strings can be hex-encoded. Numbers, BNs, and other shapes coming back
3170
- // from the API for u64Val/i64Val should fall through to `new BN(value)` which
3171
- // accepts those shapes natively. Without this guard, calling .startsWith on a
3172
- // non-string blows up with TypeError.
3173
- if (typeof value !== "string")
3174
- return false;
3175
3191
  // Matches strings containing only 0-9, a-f, or A-F (optionally prefixed with 0x)
3176
3192
  let testValue = value;
3177
3193
  // Handle negative values
@@ -3267,11 +3283,8 @@ async function buildSetDocumentsTransaction(connection, idl, anchorProvider, pay
3267
3283
  }
3268
3284
  else if (idl.address === "poof4b5pk1L9tmThvBmaABjcyjfhFGbMbQP5BXk2QZp") {
3269
3285
  const program = new Program(idl, anchorProvider);
3270
- // Targets `set_documents_v2` (Vec<u8> ra_indices). The on-chain program
3271
- // also exposes the legacy `set_documents` (Vec<u64>) so SDKs already on npm
3272
- // continue to work — but new releases of this SDK speak v2 only.
3273
3286
  tx = await program.methods
3274
- .setDocumentsV2(args.app_id, prepareAnchorArgs(args.documents), args.delete_paths, args.txData, simulate)
3287
+ .setDocuments(args.app_id, prepareAnchorArgs(args.documents), args.delete_paths, args.txData, simulate)
3275
3288
  .preInstructions(instructions)
3276
3289
  .accounts({
3277
3290
  payer: payerPublicKey
@@ -3626,17 +3639,11 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
3626
3639
  if (_overrides === null || _overrides === void 0 ? void 0 : _overrides.headers) {
3627
3640
  Object.assign(headers, _overrides.headers);
3628
3641
  }
3629
- // Writes (PUT/POST/DELETE) can take significantly longer than reads —
3630
- // server-side they may trigger ad-hoc LUT creation (create + extend +
3631
- // wait-for-finalization, ~15-30s on mainnet). Use a larger default for
3632
- // non-GET so the SDK doesn't time out before client-api responds.
3633
- const isRead = method.toUpperCase() === "GET";
3634
- const defaultTimeout = isRead ? 30000 : 90000;
3635
3642
  const requestConfig = {
3636
3643
  method,
3637
3644
  url: `${config.apiUrl}${urlPath.startsWith("/") ? urlPath : `/${urlPath}`}`,
3638
3645
  headers,
3639
- timeout: (_a = _overrides === null || _overrides === void 0 ? void 0 : _overrides.timeout) !== null && _a !== void 0 ? _a : defaultTimeout,
3646
+ timeout: (_a = _overrides === null || _overrides === void 0 ? void 0 : _overrides.timeout) !== null && _a !== void 0 ? _a : 30000,
3640
3647
  };
3641
3648
  if (method !== "GET" && method !== "get") {
3642
3649
  requestConfig.data = data ? JSON.stringify(data) : {};
@@ -4281,38 +4288,21 @@ async function setMany(many, options) {
4281
4288
  setDocumentData: tx.transactionArgs.setDocumentData,
4282
4289
  deletePaths: tx.transactionArgs.deletePaths,
4283
4290
  idl: tx.idl,
4284
- txData: (_b = (_a = tx.txData) === null || _a === void 0 ? void 0 : _a.map((txData) => ({
4285
- pluginFunctionKey: txData.pluginFunctionKey,
4286
- txData: bufferExports.Buffer.from(txData.txData),
4287
- // raIndices is Vec<u8> on-chain (serialized as Buffer/bytes). The server may send
4288
- // it as a Buffer, a number[], a Uint8Array, or — over JSON — as Node's serialized
4289
- // Buffer shape {type: "Buffer", data: number[]} (the default `JSON.stringify(buf)`
4290
- // output). Normalise all of those to Buffer here. Each value must fit in u8 (matches
4291
- // Solana's instruction-level account indexing); throw clearly if anything is out of range.
4292
- raIndices: (() => {
4293
- const raw = txData.raIndices;
4294
- if (raw == null)
4295
- return bufferExports.Buffer.alloc(0);
4296
- if (bufferExports.Buffer.isBuffer(raw))
4297
- return raw;
4298
- if (raw instanceof Uint8Array)
4299
- return bufferExports.Buffer.from(raw);
4300
- // Node's JSON-serialised Buffer: {type: "Buffer", data: number[]}
4301
- const arrayLike = Array.isArray(raw)
4302
- ? raw
4303
- : (raw && typeof raw === 'object' && Array.isArray(raw.data))
4304
- ? raw.data
4305
- : (() => { throw new Error(`raIndices has unexpected shape: ${typeof raw}`); })();
4306
- const bytes = arrayLike.map((raIndex) => {
4307
- const n = isHexString(raIndex) ? parseInt(raIndex, 16) : Number(raIndex);
4308
- if (!Number.isInteger(n) || n < 0 || n > 255) {
4309
- throw new Error(`raIndex ${raIndex} is not a valid u8 (must be integer in 0..255)`);
4291
+ txData: (_b = (_a = tx.txData) === null || _a === void 0 ? void 0 : _a.map((txData) => {
4292
+ var _a;
4293
+ return ({
4294
+ pluginFunctionKey: txData.pluginFunctionKey,
4295
+ txData: bufferExports.Buffer.from(txData.txData),
4296
+ raIndices: (_a = txData.raIndices) === null || _a === void 0 ? void 0 : _a.map((raIndex) => {
4297
+ if (isHexString(raIndex)) {
4298
+ return new BN(raIndex, "hex");
4310
4299
  }
4311
- return n;
4312
- });
4313
- return bufferExports.Buffer.from(bytes);
4314
- })(),
4315
- }))) !== null && _b !== void 0 ? _b : [],
4300
+ else {
4301
+ return new BN(raIndex);
4302
+ }
4303
+ }),
4304
+ });
4305
+ })) !== null && _b !== void 0 ? _b : [],
4316
4306
  };
4317
4307
  const config = await getConfig();
4318
4308
  const solTransaction = {
@@ -5294,6 +5284,28 @@ class ReactNativeSessionManager {
5294
5284
  /* STORE */
5295
5285
  /* ------------------------------------------------------------------ */
5296
5286
  static async storeSession(address, accessToken, idToken, refreshToken) {
5287
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
5288
+ // to a different wallet than `address`. Prevents races that would otherwise
5289
+ // leave storage with mismatched address/token state.
5290
+ try {
5291
+ const payloadB64 = idToken.split(".")[1];
5292
+ if (payloadB64) {
5293
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
5294
+ const tokenWallet = payload["custom:walletAddress"];
5295
+ if (tokenWallet && tokenWallet !== address) {
5296
+ throw new Error(`[ReactNativeSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
5297
+ }
5298
+ if (!tokenWallet) {
5299
+ console.warn("[ReactNativeSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
5300
+ }
5301
+ }
5302
+ }
5303
+ catch (err) {
5304
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
5305
+ throw err;
5306
+ }
5307
+ console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
5308
+ }
5297
5309
  const config = await getConfig();
5298
5310
  const currentAppId = config.appId;
5299
5311
  this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({