@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.js CHANGED
@@ -396,6 +396,28 @@ class WebSessionManager {
396
396
  static async storeSession(address, accessToken, idToken, refreshToken) {
397
397
  if (typeof window === "undefined")
398
398
  return;
399
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
400
+ // to a different wallet than `address`. Prevents races that would otherwise
401
+ // leave localStorage with mismatched address/token state.
402
+ try {
403
+ const payloadB64 = idToken.split(".")[1];
404
+ if (payloadB64) {
405
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
406
+ const tokenWallet = payload["custom:walletAddress"];
407
+ if (tokenWallet && tokenWallet !== address) {
408
+ throw new Error(`[WebSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
409
+ }
410
+ if (!tokenWallet) {
411
+ console.warn("[WebSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
412
+ }
413
+ }
414
+ }
415
+ catch (err) {
416
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
417
+ throw err;
418
+ }
419
+ console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
420
+ }
399
421
  const config = await getConfig();
400
422
  const currentAppId = config.appId;
401
423
  localStorage.setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
@@ -3186,12 +3208,6 @@ async function genSolanaMessage(address, nonce) {
3186
3208
  // Serialization Helpers
3187
3209
  // ─────────────────────────────────────────────────────────────
3188
3210
  function isHexString(value) {
3189
- // Only strings can be hex-encoded. Numbers, BNs, and other shapes coming back
3190
- // from the API for u64Val/i64Val should fall through to `new BN(value)` which
3191
- // accepts those shapes natively. Without this guard, calling .startsWith on a
3192
- // non-string blows up with TypeError.
3193
- if (typeof value !== "string")
3194
- return false;
3195
3211
  // Matches strings containing only 0-9, a-f, or A-F (optionally prefixed with 0x)
3196
3212
  let testValue = value;
3197
3213
  // Handle negative values
@@ -3287,11 +3303,8 @@ async function buildSetDocumentsTransaction(connection, idl, anchorProvider, pay
3287
3303
  }
3288
3304
  else if (idl.address === "poof4b5pk1L9tmThvBmaABjcyjfhFGbMbQP5BXk2QZp") {
3289
3305
  const program = new anchor.Program(idl, anchorProvider);
3290
- // Targets `set_documents_v2` (Vec<u8> ra_indices). The on-chain program
3291
- // also exposes the legacy `set_documents` (Vec<u64>) so SDKs already on npm
3292
- // continue to work — but new releases of this SDK speak v2 only.
3293
3306
  tx = await program.methods
3294
- .setDocumentsV2(args.app_id, prepareAnchorArgs(args.documents), args.delete_paths, args.txData, simulate)
3307
+ .setDocuments(args.app_id, prepareAnchorArgs(args.documents), args.delete_paths, args.txData, simulate)
3295
3308
  .preInstructions(instructions)
3296
3309
  .accounts({
3297
3310
  payer: payerPublicKey
@@ -3646,17 +3659,11 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
3646
3659
  if (_overrides === null || _overrides === void 0 ? void 0 : _overrides.headers) {
3647
3660
  Object.assign(headers, _overrides.headers);
3648
3661
  }
3649
- // Writes (PUT/POST/DELETE) can take significantly longer than reads —
3650
- // server-side they may trigger ad-hoc LUT creation (create + extend +
3651
- // wait-for-finalization, ~15-30s on mainnet). Use a larger default for
3652
- // non-GET so the SDK doesn't time out before client-api responds.
3653
- const isRead = method.toUpperCase() === "GET";
3654
- const defaultTimeout = isRead ? 30000 : 90000;
3655
3662
  const requestConfig = {
3656
3663
  method,
3657
3664
  url: `${config.apiUrl}${urlPath.startsWith("/") ? urlPath : `/${urlPath}`}`,
3658
3665
  headers,
3659
- timeout: (_a = _overrides === null || _overrides === void 0 ? void 0 : _overrides.timeout) !== null && _a !== void 0 ? _a : defaultTimeout,
3666
+ timeout: (_a = _overrides === null || _overrides === void 0 ? void 0 : _overrides.timeout) !== null && _a !== void 0 ? _a : 30000,
3660
3667
  };
3661
3668
  if (method !== "GET" && method !== "get") {
3662
3669
  requestConfig.data = data ? JSON.stringify(data) : {};
@@ -4301,38 +4308,21 @@ async function setMany(many, options) {
4301
4308
  setDocumentData: tx.transactionArgs.setDocumentData,
4302
4309
  deletePaths: tx.transactionArgs.deletePaths,
4303
4310
  idl: tx.idl,
4304
- txData: (_b = (_a = tx.txData) === null || _a === void 0 ? void 0 : _a.map((txData) => ({
4305
- pluginFunctionKey: txData.pluginFunctionKey,
4306
- txData: bufferExports.Buffer.from(txData.txData),
4307
- // raIndices is Vec<u8> on-chain (serialized as Buffer/bytes). The server may send
4308
- // it as a Buffer, a number[], a Uint8Array, or — over JSON — as Node's serialized
4309
- // Buffer shape {type: "Buffer", data: number[]} (the default `JSON.stringify(buf)`
4310
- // output). Normalise all of those to Buffer here. Each value must fit in u8 (matches
4311
- // Solana's instruction-level account indexing); throw clearly if anything is out of range.
4312
- raIndices: (() => {
4313
- const raw = txData.raIndices;
4314
- if (raw == null)
4315
- return bufferExports.Buffer.alloc(0);
4316
- if (bufferExports.Buffer.isBuffer(raw))
4317
- return raw;
4318
- if (raw instanceof Uint8Array)
4319
- return bufferExports.Buffer.from(raw);
4320
- // Node's JSON-serialised Buffer: {type: "Buffer", data: number[]}
4321
- const arrayLike = Array.isArray(raw)
4322
- ? raw
4323
- : (raw && typeof raw === 'object' && Array.isArray(raw.data))
4324
- ? raw.data
4325
- : (() => { throw new Error(`raIndices has unexpected shape: ${typeof raw}`); })();
4326
- const bytes = arrayLike.map((raIndex) => {
4327
- const n = isHexString(raIndex) ? parseInt(raIndex, 16) : Number(raIndex);
4328
- if (!Number.isInteger(n) || n < 0 || n > 255) {
4329
- throw new Error(`raIndex ${raIndex} is not a valid u8 (must be integer in 0..255)`);
4311
+ txData: (_b = (_a = tx.txData) === null || _a === void 0 ? void 0 : _a.map((txData) => {
4312
+ var _a;
4313
+ return ({
4314
+ pluginFunctionKey: txData.pluginFunctionKey,
4315
+ txData: bufferExports.Buffer.from(txData.txData),
4316
+ raIndices: (_a = txData.raIndices) === null || _a === void 0 ? void 0 : _a.map((raIndex) => {
4317
+ if (isHexString(raIndex)) {
4318
+ return new BN(raIndex, "hex");
4330
4319
  }
4331
- return n;
4332
- });
4333
- return bufferExports.Buffer.from(bytes);
4334
- })(),
4335
- }))) !== null && _b !== void 0 ? _b : [],
4320
+ else {
4321
+ return new BN(raIndex);
4322
+ }
4323
+ }),
4324
+ });
4325
+ })) !== null && _b !== void 0 ? _b : [],
4336
4326
  };
4337
4327
  const config = await getConfig();
4338
4328
  const solTransaction = {
@@ -5314,6 +5304,28 @@ class ReactNativeSessionManager {
5314
5304
  /* STORE */
5315
5305
  /* ------------------------------------------------------------------ */
5316
5306
  static async storeSession(address, accessToken, idToken, refreshToken) {
5307
+ // JWT-wallet binding: refuse to store a session whose idToken is bound
5308
+ // to a different wallet than `address`. Prevents races that would otherwise
5309
+ // leave storage with mismatched address/token state.
5310
+ try {
5311
+ const payloadB64 = idToken.split(".")[1];
5312
+ if (payloadB64) {
5313
+ const payload = JSON.parse(this.decodeBase64Url(payloadB64));
5314
+ const tokenWallet = payload["custom:walletAddress"];
5315
+ if (tokenWallet && tokenWallet !== address) {
5316
+ throw new Error(`[ReactNativeSessionManager] Refusing to store session: address (${address}) does not match idToken custom:walletAddress (${tokenWallet})`);
5317
+ }
5318
+ if (!tokenWallet) {
5319
+ console.warn("[ReactNativeSessionManager] storeSession: idToken has no custom:walletAddress claim — writing without validation");
5320
+ }
5321
+ }
5322
+ }
5323
+ catch (err) {
5324
+ if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
5325
+ throw err;
5326
+ }
5327
+ console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
5328
+ }
5317
5329
  const config = await getConfig();
5318
5330
  const currentAppId = config.appId;
5319
5331
  this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({