@chipi-stack/backend 13.12.0 → 14.0.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
@@ -1,7 +1,7 @@
1
1
  import { isValidApiKey, ChipiAuthError, STARKNET_NETWORKS, API_VERSIONING, validateErrorResponse, ChipiApiError, handleApiError, WALLET_RPC_ENDPOINTS, WALLET_CLASS_HASHES, API_ENDPOINTS, ChipiTransactionError, formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, ChipiSessionError, SESSION_ERRORS, SESSION_DEFAULTS, SESSION_ENTRYPOINTS } from '@chipi-stack/shared';
2
2
  import CryptoES from 'crypto-es';
3
3
  import { RpcProvider, ec, hash, Account, num, CairoCustomEnum, CairoOption, CairoOptionVariant, CallData, cairo, typedData } from 'starknet';
4
- import { STARKNET_CONTRACTS } from '@chipi-stack/types';
4
+ import { STARKNET_CONTRACTS, Chain } from '@chipi-stack/types';
5
5
  export { Chain, ChainToken } from '@chipi-stack/types';
6
6
 
7
7
  // src/chipi-sdk.ts
@@ -14,7 +14,7 @@ var ChipiClient = class {
14
14
  this.customAlphaUrl = config.alphaUrl;
15
15
  this.baseUrl = this.getBaseUrl();
16
16
  this.nodeUrl = config.nodeUrl || STARKNET_NETWORKS.MAINNET;
17
- this.sdkVersion = "11.21.0";
17
+ this.sdkVersion = "14.0.0";
18
18
  }
19
19
  /**
20
20
  * Get the API public key (for internal SDK use)
@@ -25,7 +25,7 @@ var ChipiClient = class {
25
25
  getBaseUrl() {
26
26
  const version = `v${API_VERSIONING.VERSION}`;
27
27
  if (this.customAlphaUrl) {
28
- const cleanUrl = this.customAlphaUrl.replace(/\/v\d+$/, "").replace(/\/$/, "");
28
+ const cleanUrl = this.customAlphaUrl.replace(/\/v\d+\/?$/, "").replace(/\/$/, "");
29
29
  return `${cleanUrl}/${version}`;
30
30
  }
31
31
  return `https://celebrated-vision-production-66a5.up.railway.app/${version}`;
@@ -95,7 +95,6 @@ var ChipiClient = class {
95
95
  });
96
96
  const data = await response.json();
97
97
  if (!response.ok) {
98
- console.error("there was an error", data);
99
98
  const errorData = validateErrorResponse(data);
100
99
  throw new ChipiApiError(
101
100
  errorData.message,
@@ -135,6 +134,33 @@ var ChipiClient = class {
135
134
  throw handleApiError(error);
136
135
  }
137
136
  }
137
+ async patch({
138
+ endpoint,
139
+ bearerToken,
140
+ body
141
+ }) {
142
+ try {
143
+ const url = new URL(`${this.baseUrl}${endpoint}`);
144
+ this.addVersionParams(url);
145
+ const response = await fetch(url.toString(), {
146
+ method: "PATCH",
147
+ headers: this.getHeaders(bearerToken),
148
+ body: body ? JSON.stringify(body) : void 0
149
+ });
150
+ const data = await response.json();
151
+ if (!response.ok) {
152
+ const errorData = validateErrorResponse(data);
153
+ throw new ChipiApiError(
154
+ errorData.message,
155
+ errorData.code || `HTTP_${response.status}`,
156
+ response.status
157
+ );
158
+ }
159
+ return data;
160
+ } catch (error) {
161
+ throw handleApiError(error);
162
+ }
163
+ }
138
164
  async delete({
139
165
  endpoint,
140
166
  bearerToken
@@ -162,16 +188,26 @@ var ChipiClient = class {
162
188
  }
163
189
  };
164
190
  var encryptPrivateKey = (privateKey, password) => {
191
+ if (!privateKey || !password) {
192
+ throw new Error("Private key and password are required");
193
+ }
165
194
  return CryptoES.AES.encrypt(privateKey, password).toString();
166
195
  };
167
196
  var decryptPrivateKey = (encryptedPrivateKey, password) => {
197
+ if (!encryptedPrivateKey || !password) {
198
+ throw new Error("Encrypted private key and password are required");
199
+ }
168
200
  try {
169
201
  const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);
170
202
  const decrypted = bytes.toString(CryptoES.enc.Utf8);
171
- if (!decrypted) throw new Error("Decryption failed");
203
+ if (!decrypted) {
204
+ throw new Error("Decryption resulted in empty string");
205
+ }
172
206
  return decrypted;
173
207
  } catch (error) {
174
- console.error("Decryption failed:", error);
208
+ if (error instanceof Error) {
209
+ throw error;
210
+ }
175
211
  throw new Error(`Decryption failed: ${error}`);
176
212
  }
177
213
  };
@@ -216,10 +252,7 @@ var ChipiWallets = class {
216
252
  const privateKeyAX = this.getPrivateKeyAX();
217
253
  const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX);
218
254
  const accountClassHash = walletType === "READY" ? WALLET_CLASS_HASHES.READY : WALLET_CLASS_HASHES.CHIPI;
219
- const constructorCallData = this.buildConstructorCallData(
220
- walletType,
221
- starkKeyPubAX
222
- );
255
+ const constructorCallData = this.buildConstructorCallData(walletType, starkKeyPubAX);
223
256
  const publicKey = hash.calculateContractAddressFromHash(
224
257
  starkKeyPubAX,
225
258
  accountClassHash,
@@ -331,8 +364,22 @@ var ChipiWallets = class {
331
364
  if (err instanceof ChipiApiError && err.status === 404) {
332
365
  return null;
333
366
  }
334
- throw new Error(`getWallet error: ${String(err)}`);
367
+ throw err;
368
+ }
369
+ }
370
+ async updateWalletEncryption(params, bearerToken) {
371
+ const body = {
372
+ externalUserId: params.externalUserId,
373
+ newEncryptedPrivateKey: params.newEncryptedPrivateKey
374
+ };
375
+ if (params.publicKey != null) {
376
+ body.publicKey = params.publicKey;
335
377
  }
378
+ return this.client.patch({
379
+ endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/update-encryption-details`,
380
+ bearerToken,
381
+ body
382
+ });
336
383
  }
337
384
  async getTokenBalance({
338
385
  params,
@@ -360,12 +407,11 @@ var executePaymasterTransaction = async ({
360
407
  }
361
408
  const rpcUrl = WALLET_RPC_ENDPOINTS.READY;
362
409
  const accountClassHash = WALLET_CLASS_HASHES.READY;
363
- const privateKeyDecrypted = decryptPrivateKey(
364
- wallet.encryptedPrivateKey,
365
- encryptKey
366
- );
367
- if (!privateKeyDecrypted) {
368
- throw new Error("Failed to decrypt private key");
410
+ let privateKeyDecrypted;
411
+ try {
412
+ privateKeyDecrypted = decryptPrivateKey(wallet.encryptedPrivateKey, encryptKey);
413
+ } catch {
414
+ throw new Error("Failed to decrypt private key. Verify the encryptKey is correct.");
369
415
  }
370
416
  const provider = new RpcProvider({ nodeUrl: rpcUrl });
371
417
  const account = new Account({
@@ -438,16 +484,13 @@ var executePaymasterTransactionWithSession = async ({
438
484
  }) => {
439
485
  const { encryptKey, wallet, session, calls, saveToDatabase } = params;
440
486
  if (wallet.walletType !== "CHIPI") {
441
- console.error(
442
- "[ChipiSDK:Session:Execute] Invalid wallet type for session execution",
443
- {
444
- provided: wallet.walletType,
445
- required: "CHIPI",
446
- expectedClassHash: WALLET_CLASS_HASHES.CHIPI,
447
- walletAddress: wallet.publicKey?.slice(0, 15) + "...",
448
- hint: "Session keys only work with CHIPI wallets (SNIP-9 compatible)"
449
- }
450
- );
487
+ console.error("[ChipiSDK:Session:Execute] Invalid wallet type for session execution", {
488
+ provided: wallet.walletType,
489
+ required: "CHIPI",
490
+ expectedClassHash: WALLET_CLASS_HASHES.CHIPI,
491
+ walletAddress: wallet.publicKey?.slice(0, 15) + "...",
492
+ hint: "Session keys only work with CHIPI wallets (SNIP-9 compatible)"
493
+ });
451
494
  throw new ChipiSessionError(
452
495
  `Session execution requires CHIPI wallet type. Got: "${wallet.walletType || "undefined"}"`,
453
496
  SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION
@@ -466,18 +509,14 @@ var executePaymasterTransactionWithSession = async ({
466
509
  );
467
510
  }
468
511
  try {
469
- const sessionPrivateKey = decryptPrivateKey(
470
- session.encryptedPrivateKey,
471
- encryptKey
472
- );
473
- if (!sessionPrivateKey) {
474
- console.error(
475
- "[ChipiSDK:Session:Execute] Failed to decrypt session private key",
476
- {
477
- sessionPubKey: session.publicKey?.slice(0, 15) + "...",
478
- hint: "Ensure the encryptKey matches the one used when creating the session"
479
- }
480
- );
512
+ let sessionPrivateKey;
513
+ try {
514
+ sessionPrivateKey = decryptPrivateKey(session.encryptedPrivateKey, encryptKey);
515
+ } catch {
516
+ console.error("[ChipiSDK:Session:Execute] Failed to decrypt session private key", {
517
+ sessionPubKey: session.publicKey?.slice(0, 15) + "...",
518
+ hint: "Ensure the encryptKey matches the one used when creating the session"
519
+ });
481
520
  throw new ChipiSessionError(
482
521
  "Failed to decrypt session private key. Verify the encryptKey is correct.",
483
522
  SESSION_ERRORS.SESSION_DECRYPTION_FAILED
@@ -529,12 +568,9 @@ var executePaymasterTransactionWithSession = async ({
529
568
  }
530
569
  });
531
570
  if (!result.transactionHash) {
532
- console.error(
533
- "[ChipiSDK:Session:Execute] No transaction hash in response",
534
- {
535
- result
536
- }
537
- );
571
+ console.error("[ChipiSDK:Session:Execute] No transaction hash in response", {
572
+ result
573
+ });
538
574
  throw new Error("Response does not contain transaction hash");
539
575
  }
540
576
  return result.transactionHash;
@@ -701,32 +737,21 @@ var ChipiSkuPurchases = class {
701
737
  * @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details
702
738
  */
703
739
  async purchaseSku(params, bearerToken) {
704
- const {
705
- skuId,
706
- skuReference,
707
- currencyAmount,
708
- currency,
709
- chain,
710
- token,
711
- encryptKey,
712
- wallet
713
- } = params;
714
- const usdAmount = await this.exchanges.getUsdAmount(
715
- currencyAmount,
716
- currency,
717
- bearerToken
718
- );
719
- const tokenAddress = STARKNET_CONTRACTS[token].contractAddress;
720
- if (usdAmount <= 0) {
721
- throw new Error(
722
- `Invalid USD amount: ${usdAmount}. Amount must be positive.`
723
- );
740
+ const { skuId, skuReference, currencyAmount, currency, chain, token, encryptKey, wallet } = params;
741
+ if (chain !== Chain.STARKNET) {
742
+ throw new Error(`Unsupported chain for SKU purchases: ${chain}`);
743
+ }
744
+ const tokenConfig = STARKNET_CONTRACTS[token];
745
+ if (!tokenConfig?.contractAddress) {
746
+ throw new Error(`Unsupported token for Starknet SKU purchases: ${token}`);
747
+ }
748
+ const usdAmount = await this.exchanges.getUsdAmount(currencyAmount, currency, bearerToken);
749
+ const tokenAddress = tokenConfig.contractAddress;
750
+ if (!Number.isFinite(usdAmount) || usdAmount <= 0) {
751
+ throw new Error(`Invalid USD amount: ${usdAmount}. Amount must be positive.`);
724
752
  }
725
753
  const minUsdAmount = Math.max(usdAmount, 1e-6);
726
- const parsedAmount = formatAmount(
727
- minUsdAmount.toString(),
728
- STARKNET_CONTRACTS[token].decimals
729
- );
754
+ const parsedAmount = formatAmount(minUsdAmount.toString(), tokenConfig.decimals);
730
755
  const calls = [
731
756
  {
732
757
  contractAddress: tokenAddress,
@@ -888,6 +913,12 @@ var ChipiSessions = class {
888
913
  */
889
914
  createSessionKey(params) {
890
915
  const { encryptKey, durationSeconds = SESSION_DEFAULTS.DURATION_SECONDS } = params;
916
+ if (typeof durationSeconds !== "number" || !Number.isFinite(durationSeconds) || !Number.isInteger(durationSeconds) || durationSeconds <= 0) {
917
+ throw new ChipiSessionError(
918
+ `Invalid session duration: ${durationSeconds}. Must be a positive integer.`,
919
+ SESSION_ERRORS.SESSION_CREATION_FAILED
920
+ );
921
+ }
891
922
  try {
892
923
  const rawPrivateKey = ec.starkCurve.utils.randomPrivateKey();
893
924
  const privateKeyHex = this.toHex(rawPrivateKey);
@@ -901,13 +932,10 @@ var ChipiSessions = class {
901
932
  };
902
933
  } catch (error) {
903
934
  const err = error instanceof Error ? error : new Error(String(error));
904
- console.error(
905
- "[ChipiSDK:Session:Create] Failed to generate session key",
906
- {
907
- error: err.message,
908
- durationRequested: durationSeconds
909
- }
910
- );
935
+ console.error("[ChipiSDK:Session:Create] Failed to generate session key", {
936
+ error: err.message,
937
+ durationRequested: durationSeconds
938
+ });
911
939
  throw new ChipiSessionError(
912
940
  `Failed to create session key: ${err.message}`,
913
941
  SESSION_ERRORS.SESSION_CREATION_FAILED
@@ -942,22 +970,15 @@ var ChipiSessions = class {
942
970
  */
943
971
  async addSessionKeyToContract(params, bearerToken) {
944
972
  const { encryptKey, wallet, sessionConfig } = params;
945
- this.validateChipiWallet(
946
- wallet.walletType,
947
- "AddToContract",
948
- wallet.publicKey
949
- );
973
+ this.validateChipiWallet(wallet.walletType, "AddToContract", wallet.publicKey);
950
974
  try {
951
- console.log(
952
- "[ChipiSDK:Session:AddToContract] Registering session on-chain",
953
- {
954
- walletAddress: wallet.publicKey.slice(0, 15) + "...",
955
- sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
956
- validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
957
- maxCalls: sessionConfig.maxCalls,
958
- allowedEntrypoints: sessionConfig.allowedEntrypoints.length
959
- }
960
- );
975
+ console.log("[ChipiSDK:Session:AddToContract] Registering session on-chain", {
976
+ walletAddress: wallet.publicKey.slice(0, 15) + "...",
977
+ sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
978
+ validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
979
+ maxCalls: sessionConfig.maxCalls,
980
+ allowedEntrypoints: sessionConfig.allowedEntrypoints.length
981
+ });
961
982
  const calldata = [
962
983
  sessionConfig.sessionPublicKey,
963
984
  num.toHex(sessionConfig.validUntil),
@@ -983,13 +1004,10 @@ var ChipiSessions = class {
983
1004
  bearerToken,
984
1005
  client: this.client
985
1006
  });
986
- console.log(
987
- "[ChipiSDK:Session:AddToContract] Session registered successfully",
988
- {
989
- txHash,
990
- sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "..."
991
- }
992
- );
1007
+ console.log("[ChipiSDK:Session:AddToContract] Session registered successfully", {
1008
+ txHash,
1009
+ sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "..."
1010
+ });
993
1011
  return txHash;
994
1012
  } catch (error) {
995
1013
  const err = error instanceof Error ? error : new Error(String(error));
@@ -1137,17 +1155,33 @@ var ChipiSessions = class {
1137
1155
  return sessionData;
1138
1156
  } catch (error) {
1139
1157
  const err = error instanceof Error ? error : new Error(String(error));
1140
- console.error("[ChipiSDK:Session:GetData] Query failed", {
1158
+ const sessionNotFoundPatterns = [
1159
+ /entry point.*not found/i,
1160
+ /requested entrypoint was not found/i,
1161
+ /invalid message selector/i,
1162
+ /contract not found/i,
1163
+ /is not deployed/i,
1164
+ /revert.*get_session_data/i
1165
+ ];
1166
+ const isSessionNotFound = sessionNotFoundPatterns.some((p) => p.test(err.message));
1167
+ if (isSessionNotFound) {
1168
+ console.log("[ChipiSDK:Session:GetData] Session not found on contract", {
1169
+ walletAddress: walletAddress?.slice(0, 15) + "...",
1170
+ sessionPubKey: sessionPublicKey?.slice(0, 15) + "..."
1171
+ });
1172
+ return {
1173
+ isActive: false,
1174
+ validUntil: 0,
1175
+ remainingCalls: 0,
1176
+ allowedEntrypoints: []
1177
+ };
1178
+ }
1179
+ console.error("[ChipiSDK:Session:GetData] RPC/network error", {
1141
1180
  error: err.message,
1142
1181
  walletAddress: walletAddress?.slice(0, 15) + "...",
1143
1182
  sessionPubKey: sessionPublicKey?.slice(0, 15) + "..."
1144
1183
  });
1145
- return {
1146
- isActive: false,
1147
- validUntil: 0,
1148
- remainingCalls: 0,
1149
- allowedEntrypoints: []
1150
- };
1184
+ throw err;
1151
1185
  }
1152
1186
  }
1153
1187
  /**
@@ -1360,7 +1394,6 @@ var ChipiSDK = class {
1360
1394
  params,
1361
1395
  bearerToken
1362
1396
  }) {
1363
- console.log("createWallet params:", params);
1364
1397
  return this.wallets.createWallet({
1365
1398
  ...params,
1366
1399
  bearerToken: this.resolveBearerToken(bearerToken)
@@ -1376,10 +1409,7 @@ var ChipiSDK = class {
1376
1409
  });
1377
1410
  }
1378
1411
  async getTransactionList(query, bearerToken) {
1379
- return this.transactions.getTransactionList(
1380
- query,
1381
- this.resolveBearerToken(bearerToken)
1382
- );
1412
+ return this.transactions.getTransactionList(query, this.resolveBearerToken(bearerToken));
1383
1413
  }
1384
1414
  async getWallet(params, bearerToken) {
1385
1415
  return this.wallets.getWallet(params, this.resolveBearerToken(bearerToken));
@@ -1397,19 +1427,13 @@ var ChipiSDK = class {
1397
1427
  params,
1398
1428
  bearerToken
1399
1429
  }) {
1400
- return this.skuPurchases.purchaseSku(
1401
- params,
1402
- this.resolveBearerToken(bearerToken)
1403
- );
1430
+ return this.skuPurchases.purchaseSku(params, this.resolveBearerToken(bearerToken));
1404
1431
  }
1405
1432
  /**
1406
1433
  * Get a SKU purchase by id
1407
1434
  */
1408
1435
  async getSkuPurchase(id, bearerToken) {
1409
- return this.skuPurchases.getSkuPurchase(
1410
- id,
1411
- this.resolveBearerToken(bearerToken)
1412
- );
1436
+ return this.skuPurchases.getSkuPurchase(id, this.resolveBearerToken(bearerToken));
1413
1437
  }
1414
1438
  /// SKUS
1415
1439
  async getSkuList(params, bearerToken) {