@chipi-stack/chipi-react 14.15.1 → 14.17.0

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
@@ -1316,6 +1316,22 @@ function useSignTypedData() {
1316
1316
  reset: mutation.reset
1317
1317
  };
1318
1318
  }
1319
+ function useExternalSignerExecute() {
1320
+ const { chipiSDK } = useChipiContext();
1321
+ const mutation = useMutation({
1322
+ mutationFn: async (input) => chipiSDK.executeWithExternalSigner(input)
1323
+ });
1324
+ return {
1325
+ execute: mutation.mutate,
1326
+ executeAsync: mutation.mutateAsync,
1327
+ data: mutation.data,
1328
+ isLoading: mutation.isPending,
1329
+ isError: mutation.isError,
1330
+ error: mutation.error,
1331
+ isSuccess: mutation.isSuccess,
1332
+ reset: mutation.reset
1333
+ };
1334
+ }
1319
1335
 
1320
1336
  // ../node_modules/.pnpm/@starknet-io+types-js@0.9.2/node_modules/@starknet-io/types-js/dist/esm/index.js
1321
1337
  var esm_exports = {};
@@ -20394,6 +20410,41 @@ function hexEq(a, b) {
20394
20410
  return a === b;
20395
20411
  }
20396
20412
  }
20413
+ function parseCapAmount(value, field, token) {
20414
+ try {
20415
+ const v = typeof value === "bigint" ? value : BigInt(String(value).trim());
20416
+ if (v < 0n) throw new Error("negative");
20417
+ return v;
20418
+ } catch {
20419
+ throw new Error(
20420
+ `session_spend_cap_invalid: ${field} for token ${token} must be a non-negative integer in base units (got "${String(value)}")`
20421
+ );
20422
+ }
20423
+ }
20424
+ function toSpendingPolicies(caps, lifetimeSeconds) {
20425
+ return caps.map((cap) => {
20426
+ const policy = "maxPerWindow" in cap ? {
20427
+ token: cap.token,
20428
+ maxPerCall: parseCapAmount(cap.maxPerCall, "maxPerCall", cap.token),
20429
+ maxPerWindow: parseCapAmount(cap.maxPerWindow, "maxPerWindow", cap.token),
20430
+ windowSeconds: cap.windowSeconds
20431
+ } : (() => {
20432
+ const amount = parseCapAmount(cap.amount, "amount", cap.token);
20433
+ return {
20434
+ token: cap.token,
20435
+ maxPerCall: amount,
20436
+ maxPerWindow: amount,
20437
+ windowSeconds: Math.max(1, lifetimeSeconds)
20438
+ };
20439
+ })();
20440
+ if (policy.maxPerWindow === 0n) {
20441
+ throw new Error(
20442
+ `session_spend_cap_zero: the cap for token ${cap.token} resolves to maxPerWindow = 0, which means unlimited on-chain. Use a positive cap.`
20443
+ );
20444
+ }
20445
+ return policy;
20446
+ });
20447
+ }
20397
20448
  function sessionCovers(policy, calls) {
20398
20449
  if (!policy?.allowedCalls?.length) return false;
20399
20450
  return calls.every(
@@ -20408,6 +20459,10 @@ function useChipiWalletObject(config3) {
20408
20459
  const { signTypedDataAsync } = useSignTypedData();
20409
20460
  const { createSessionKeyAsync } = useCreateSessionKey();
20410
20461
  const { addSessionKeyToContractAsync } = useAddSessionKeyToContract();
20462
+ const { chipiSDK } = useChipiContext();
20463
+ const sdk = useRef(chipiSDK);
20464
+ sdk.current = chipiSDK;
20465
+ const warnedMissingApproval = useRef(false);
20411
20466
  const cfg = useRef(config3);
20412
20467
  cfg.current = config3;
20413
20468
  const requireWallet = () => {
@@ -20420,28 +20475,33 @@ function useChipiWalletObject(config3) {
20420
20475
  if (policy.validUntil <= nowSec()) throw new Error("session_policy_expired");
20421
20476
  const c = cfg.current;
20422
20477
  const wallet = requireWallet();
20478
+ const lifetimeSeconds = Math.max(1, policy.validUntil - nowSec());
20479
+ const spendingPolicies = policy.spendCaps?.length ? toSpendingPolicies(policy.spendCaps, lifetimeSeconds) : [];
20423
20480
  const encryptKey = await c.getEncryptKey();
20424
20481
  const session = await createSessionKeyAsync({
20425
20482
  encryptKey,
20426
- durationSeconds: Math.max(1, policy.validUntil - nowSec())
20483
+ durationSeconds: lifetimeSeconds
20427
20484
  });
20428
20485
  const bearerToken = await c.getBearerToken();
20429
- await addSessionKeyToContractAsync({
20430
- params: {
20431
- encryptKey,
20432
- wallet,
20433
- sessionConfig: {
20434
- sessionPublicKey: session.publicKey,
20435
- validUntil: policy.validUntil,
20436
- maxCalls: 1e3,
20437
- // selectors; empty = all entrypoints allowed
20438
- allowedEntrypoints: policy.allowedCalls.map(
20439
- (a) => hash_exports.getSelectorFromName(a.entrypoint)
20440
- )
20441
- }
20442
- },
20443
- bearerToken
20444
- });
20486
+ const params = {
20487
+ encryptKey,
20488
+ wallet,
20489
+ sessionConfig: {
20490
+ sessionPublicKey: session.publicKey,
20491
+ validUntil: policy.validUntil,
20492
+ maxCalls: 1e3,
20493
+ // Selectors; empty = all entrypoints allowed. On-chain this is a
20494
+ // per-selector whitelist, NOT scoped to allowedCalls' contracts.
20495
+ allowedEntrypoints: policy.allowedCalls.map(
20496
+ (a) => hash_exports.getSelectorFromName(a.entrypoint)
20497
+ )
20498
+ }
20499
+ };
20500
+ if (spendingPolicies.length > 0) {
20501
+ await sdk.current.sessions.setupSession({ ...params, spendingPolicies }, bearerToken);
20502
+ } else {
20503
+ await addSessionKeyToContractAsync({ params, bearerToken });
20504
+ }
20445
20505
  return session;
20446
20506
  },
20447
20507
  [createSessionKeyAsync, addSessionKeyToContractAsync]
@@ -20481,12 +20541,23 @@ function useChipiWalletObject(config3) {
20481
20541
  return signTypedDataAsync({ encryptKey, wallet, typedData });
20482
20542
  },
20483
20543
  getDeploymentData: async () => {
20484
- throw new Error("account_already_deployed");
20544
+ if (cfg.current.isDeployed === true) throw new Error("account_already_deployed");
20545
+ throw new Error("account_deployment_data_unavailable");
20485
20546
  },
20486
20547
  createSession: async (policy) => {
20487
20548
  await createSession(policy);
20488
20549
  },
20489
- requestApproval: (req) => cfg.current.requestApproval?.(req) ?? Promise.resolve(true)
20550
+ requestApproval: (req) => {
20551
+ const gate = cfg.current.requestApproval;
20552
+ if (gate) return gate(req);
20553
+ if (!warnedMissingApproval.current) {
20554
+ warnedMissingApproval.current = true;
20555
+ console.warn(
20556
+ "[ChipiSDK:Connect] No `requestApproval` was provided to useChipiWalletObject, so every approval (connect, execute, signTypedData, session) is denied. Pass `requestApproval` to show the user an approval UI and resolve true/false."
20557
+ );
20558
+ }
20559
+ return Promise.resolve(false);
20560
+ }
20490
20561
  }),
20491
20562
  [callAnyContractAsync, executeWithSessionAsync, signTypedDataAsync, createSession]
20492
20563
  );
@@ -21165,11 +21236,35 @@ var RpcError2 = class extends Error {
21165
21236
  var USER_REFUSED_OP = 113;
21166
21237
  var INVALID_REQUEST_PAYLOAD = 114;
21167
21238
  var ACCOUNT_ALREADY_DEPLOYED = 115;
21239
+ var NO_DEPLOYMENT_DATA = 116;
21168
21240
  var UNKNOWN_ERROR = 163;
21241
+ var MISSING_APPROVAL_WARNING = "[ChipiSDK:Connect] No `requestApproval` was provided, so every approval (connect, execute, signTypedData, session) is denied. Pass `requestApproval` to show the user an approval UI and resolve true/false.";
21242
+ function normalizeChainId(value) {
21243
+ try {
21244
+ if (typeof value === "bigint") return value;
21245
+ if (typeof value === "number") {
21246
+ return Number.isSafeInteger(value) && value >= 0 ? BigInt(value) : null;
21247
+ }
21248
+ if (typeof value !== "string" || value.length === 0) return null;
21249
+ if (/^0x[0-9a-f]+$/i.test(value) || /^[0-9]+$/.test(value)) return BigInt(value);
21250
+ return BigInt(shortString_exports.encodeShortString(value));
21251
+ } catch {
21252
+ return null;
21253
+ }
21254
+ }
21169
21255
  function createChipiWindowObject(deps) {
21170
21256
  const accountListeners = /* @__PURE__ */ new Set();
21171
21257
  const networkListeners = /* @__PURE__ */ new Set();
21172
- const approve = deps.requestApproval ?? (async () => true);
21258
+ let approved = false;
21259
+ let pendingConnect = null;
21260
+ let warnedMissingApproval = false;
21261
+ const approve = deps.requestApproval ?? (async () => {
21262
+ if (!warnedMissingApproval) {
21263
+ warnedMissingApproval = true;
21264
+ console.warn(MISSING_APPROVAL_WARNING);
21265
+ }
21266
+ return false;
21267
+ });
21173
21268
  async function requireApproval(req) {
21174
21269
  const ok = await approve(req);
21175
21270
  if (!ok) throw new RpcError2(USER_REFUSED_OP, "User refused the operation");
@@ -21177,19 +21272,27 @@ function createChipiWindowObject(deps) {
21177
21272
  const request = (async (call) => {
21178
21273
  switch (call.type) {
21179
21274
  case "wallet_requestAccounts": {
21180
- const accounts = await deps.getAccounts();
21181
- if (accounts.length === 0) {
21182
- await requireApproval({ type: "connect" });
21183
- return deps.getAccounts();
21275
+ if (call.params?.silent_mode) {
21276
+ return approved ? deps.getAccounts() : [];
21184
21277
  }
21185
- return accounts;
21278
+ if (approved) {
21279
+ const accounts = await deps.getAccounts();
21280
+ if (accounts.length > 0) return accounts;
21281
+ }
21282
+ if (!pendingConnect) {
21283
+ pendingConnect = requireApproval({ type: "connect" }).then(() => {
21284
+ approved = true;
21285
+ }).finally(() => {
21286
+ pendingConnect = null;
21287
+ });
21288
+ }
21289
+ await pendingConnect;
21290
+ return deps.getAccounts();
21186
21291
  }
21187
21292
  case "wallet_requestChainId":
21188
21293
  return deps.chainId;
21189
- case "wallet_getPermissions": {
21190
- const accounts = await deps.getAccounts();
21191
- return accounts.length > 0 ? ["accounts"] : [];
21192
- }
21294
+ case "wallet_getPermissions":
21295
+ return approved ? ["accounts"] : [];
21193
21296
  case "wallet_addInvokeTransaction": {
21194
21297
  const wireCalls = call.params?.calls ?? [];
21195
21298
  if (wireCalls.length === 0) {
@@ -21202,14 +21305,38 @@ function createChipiWindowObject(deps) {
21202
21305
  }
21203
21306
  case "wallet_signTypedData": {
21204
21307
  const typedData = call.params;
21308
+ const domainChainId = typedData?.domain?.chainId;
21309
+ if (domainChainId === void 0 || domainChainId === null) {
21310
+ throw new RpcError2(
21311
+ INVALID_REQUEST_PAYLOAD,
21312
+ `wallet_signTypedData: domain.chainId is required (the wallet chain is ${deps.chainId})`
21313
+ );
21314
+ }
21315
+ const expected = normalizeChainId(deps.chainId);
21316
+ const actual = normalizeChainId(domainChainId);
21317
+ if (actual === null || expected === null || actual !== expected) {
21318
+ throw new RpcError2(
21319
+ INVALID_REQUEST_PAYLOAD,
21320
+ `wallet_signTypedData: domain.chainId ${String(domainChainId)} does not match the wallet chain ${deps.chainId}`
21321
+ );
21322
+ }
21205
21323
  await requireApproval({ type: "signTypedData", typedData });
21206
21324
  return deps.signTypedData(typedData);
21207
21325
  }
21208
21326
  case "wallet_deploymentData":
21209
21327
  try {
21210
21328
  return await deps.getDeploymentData();
21211
- } catch {
21212
- throw new RpcError2(ACCOUNT_ALREADY_DEPLOYED, "Account already deployed");
21329
+ } catch (err2) {
21330
+ if (err2 instanceof Error && err2.message === "account_already_deployed") {
21331
+ throw new RpcError2(ACCOUNT_ALREADY_DEPLOYED, "Account already deployed");
21332
+ }
21333
+ if (err2 instanceof Error && err2.message === "account_deployment_data_unavailable") {
21334
+ throw new RpcError2(NO_DEPLOYMENT_DATA, "Account deployment data is not available");
21335
+ }
21336
+ throw new RpcError2(
21337
+ UNKNOWN_ERROR,
21338
+ err2 instanceof Error ? err2.message : "Could not read deployment data"
21339
+ );
21213
21340
  }
21214
21341
  case "wallet_supportedSpecs":
21215
21342
  return SUPPORTED_SPECS;
@@ -21500,6 +21627,6 @@ pako/dist/pako.esm.mjs:
21500
21627
  (*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) *)
21501
21628
  */
21502
21629
 
21503
- export { ChipiInjector, ChipiProvider, DEFAULT_RECOVER_LABELS, Recover, createChipiWindowObject, derivePrivacyAccount, injectChipiWallet, netPrivateBalance, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiContext, useChipiSession, useChipiWallet, useChipiWalletObject, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useGuardianRecovery, useMigrateWalletToPasskey, useMigrateWalletToShhh, usePrivateBalance, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useShhhSigner, useShield, useSignTypedData, useSyncOnChainTransfers, useThresholdSign, useTransfer, useUnshield, useUpdateWalletEncryption, useX402Payment, walletSupportsSessions };
21630
+ export { ChipiInjector, ChipiProvider, DEFAULT_RECOVER_LABELS, Recover, createChipiWindowObject, derivePrivacyAccount, injectChipiWallet, netPrivateBalance, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiContext, useChipiSession, useChipiWallet, useChipiWalletObject, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useExternalSignerExecute, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useGuardianRecovery, useMigrateWalletToPasskey, useMigrateWalletToShhh, usePrivateBalance, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useShhhSigner, useShield, useSignTypedData, useSyncOnChainTransfers, useThresholdSign, useTransfer, useUnshield, useUpdateWalletEncryption, useX402Payment, walletSupportsSessions };
21504
21631
  //# sourceMappingURL=index.mjs.map
21505
21632
  //# sourceMappingURL=index.mjs.map