@layr-labs/ecloud-sdk 0.3.1-dev → 0.3.1-dev.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.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,135 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/client/common/auth/session.ts
34
+ function stripHexPrefix2(hex) {
35
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
36
+ }
37
+ async function parseErrorResponse(response) {
38
+ try {
39
+ const data = await response.json();
40
+ return data.error || response.statusText;
41
+ } catch {
42
+ return response.statusText;
43
+ }
44
+ }
45
+ async function loginToComputeApi(config, request) {
46
+ let response;
47
+ try {
48
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
49
+ method: "POST",
50
+ credentials: "include",
51
+ // Include cookies for session management
52
+ headers: {
53
+ "Content-Type": "application/json"
54
+ },
55
+ body: JSON.stringify({
56
+ message: request.message,
57
+ signature: stripHexPrefix2(request.signature)
58
+ })
59
+ });
60
+ } catch (error) {
61
+ throw new SessionError(
62
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
63
+ "NETWORK_ERROR"
64
+ );
65
+ }
66
+ if (!response.ok) {
67
+ const errorMessage = await parseErrorResponse(response);
68
+ const status = response.status;
69
+ if (status === 400) {
70
+ if (errorMessage.toLowerCase().includes("siwe")) {
71
+ throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
72
+ }
73
+ throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
74
+ }
75
+ if (status === 401) {
76
+ throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
77
+ }
78
+ throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
79
+ }
80
+ const data = await response.json();
81
+ return {
82
+ success: data.success,
83
+ address: data.address
84
+ };
85
+ }
86
+ async function getComputeApiSession(config) {
87
+ let response;
88
+ try {
89
+ response = await fetch(`${config.baseUrl}/auth/session`, {
90
+ method: "GET",
91
+ credentials: "include",
92
+ // Include cookies for session management
93
+ headers: {
94
+ "Content-Type": "application/json"
95
+ }
96
+ });
97
+ } catch {
98
+ return {
99
+ authenticated: false
100
+ };
101
+ }
102
+ if (response.status === 401) {
103
+ return {
104
+ authenticated: false
105
+ };
106
+ }
107
+ if (!response.ok) {
108
+ const errorMessage = await parseErrorResponse(response);
109
+ throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
110
+ }
111
+ const data = await response.json();
112
+ return {
113
+ authenticated: data.authenticated,
114
+ address: data.address,
115
+ chainId: data.chain_id
116
+ };
117
+ }
118
+ async function logoutFromComputeApi(config) {
119
+ let response;
120
+ try {
121
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
122
+ method: "POST",
123
+ credentials: "include",
124
+ // Include cookies for session management
125
+ headers: {
126
+ "Content-Type": "application/json"
127
+ }
128
+ });
129
+ } catch (error) {
130
+ throw new SessionError(
131
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
132
+ "NETWORK_ERROR"
133
+ );
134
+ }
135
+ if (response.status === 401) {
136
+ return;
137
+ }
138
+ if (!response.ok) {
139
+ const errorMessage = await parseErrorResponse(response);
140
+ throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
141
+ }
142
+ }
143
+ async function isSessionValid(config) {
144
+ const session = await getComputeApiSession(config);
145
+ return session.authenticated;
146
+ }
147
+ var SessionError;
148
+ var init_session = __esm({
149
+ "src/client/common/auth/session.ts"() {
150
+ "use strict";
151
+ SessionError = class extends Error {
152
+ constructor(message, code, statusCode) {
153
+ super(message);
154
+ this.code = code;
155
+ this.statusCode = statusCode;
156
+ this.name = "SessionError";
157
+ }
158
+ };
159
+ }
160
+ });
161
+
30
162
  // src/index.ts
31
163
  var index_exports = {};
32
164
  __export(index_exports, {
@@ -2314,7 +2446,7 @@ function encodeExecuteBatchData(executions) {
2314
2446
  });
2315
2447
  }
2316
2448
  async function estimateBatchGas(options) {
2317
- const { publicClient, account, executions } = options;
2449
+ const { publicClient, account, executions, authorizationList } = options;
2318
2450
  const executeBatchData = encodeExecuteBatchData(executions);
2319
2451
  const [gasTipCap, block, estimatedGas] = await Promise.all([
2320
2452
  publicClient.estimateMaxPriorityFeePerGas(),
@@ -2322,7 +2454,8 @@ async function estimateBatchGas(options) {
2322
2454
  publicClient.estimateGas({
2323
2455
  account,
2324
2456
  to: account,
2325
- data: executeBatchData
2457
+ data: executeBatchData,
2458
+ authorizationList
2326
2459
  })
2327
2460
  ]);
2328
2461
  const baseFee = block.baseFeePerGas ?? 0n;
@@ -2345,8 +2478,44 @@ async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
2345
2478
  const expectedCode = `0xef0100${delegatorAddress.slice(2)}`;
2346
2479
  return code.toLowerCase() === expectedCode.toLowerCase();
2347
2480
  }
2481
+ async function createAuthorizationList(options) {
2482
+ const { walletClient, publicClient, environmentConfig } = options;
2483
+ const account = walletClient.account;
2484
+ if (!account) {
2485
+ throw new Error("Wallet client must have an account");
2486
+ }
2487
+ const isDelegated2 = await checkERC7702Delegation(
2488
+ publicClient,
2489
+ account.address,
2490
+ environmentConfig.erc7702DelegatorAddress
2491
+ );
2492
+ if (isDelegated2) {
2493
+ return void 0;
2494
+ }
2495
+ const transactionNonce = await publicClient.getTransactionCount({
2496
+ address: account.address,
2497
+ blockTag: "pending"
2498
+ });
2499
+ const chainId = await publicClient.getChainId();
2500
+ const authorizationNonce = transactionNonce + 1;
2501
+ const signedAuthorization = await walletClient.signAuthorization({
2502
+ account,
2503
+ contractAddress: environmentConfig.erc7702DelegatorAddress,
2504
+ chainId,
2505
+ nonce: Number(authorizationNonce)
2506
+ });
2507
+ return [signedAuthorization];
2508
+ }
2348
2509
  async function executeBatch(options, logger = noopLogger) {
2349
- const { walletClient, publicClient, environmentConfig, executions, pendingMessage, gas } = options;
2510
+ const {
2511
+ walletClient,
2512
+ publicClient,
2513
+ environmentConfig,
2514
+ executions,
2515
+ pendingMessage,
2516
+ gas,
2517
+ authorizationList: providedAuthList
2518
+ } = options;
2350
2519
  const account = walletClient.account;
2351
2520
  if (!account) {
2352
2521
  throw new Error("Wallet client must have an account");
@@ -2356,27 +2525,29 @@ async function executeBatch(options, logger = noopLogger) {
2356
2525
  throw new Error("Wallet client must have a chain");
2357
2526
  }
2358
2527
  const executeBatchData = encodeExecuteBatchData(executions);
2359
- const isDelegated2 = await checkERC7702Delegation(
2360
- publicClient,
2361
- account.address,
2362
- environmentConfig.erc7702DelegatorAddress
2363
- );
2364
- let authorizationList = [];
2365
- if (!isDelegated2) {
2366
- const transactionNonce = await publicClient.getTransactionCount({
2367
- address: account.address,
2368
- blockTag: "pending"
2369
- });
2370
- const chainId = await publicClient.getChainId();
2371
- const authorizationNonce = transactionNonce + 1;
2372
- logger.debug("Using wallet client signing for EIP-7702 authorization");
2373
- const signedAuthorization = await walletClient.signAuthorization({
2374
- account: account.address,
2375
- contractAddress: environmentConfig.erc7702DelegatorAddress,
2376
- chainId,
2377
- nonce: Number(authorizationNonce)
2378
- });
2379
- authorizationList = [signedAuthorization];
2528
+ let authorizationList = providedAuthList || [];
2529
+ if (authorizationList.length === 0) {
2530
+ const isDelegated2 = await checkERC7702Delegation(
2531
+ publicClient,
2532
+ account.address,
2533
+ environmentConfig.erc7702DelegatorAddress
2534
+ );
2535
+ if (!isDelegated2) {
2536
+ const transactionNonce = await publicClient.getTransactionCount({
2537
+ address: account.address,
2538
+ blockTag: "pending"
2539
+ });
2540
+ const chainId = await publicClient.getChainId();
2541
+ const authorizationNonce = transactionNonce + 1;
2542
+ logger.debug("Using wallet client signing for EIP-7702 authorization");
2543
+ const signedAuthorization = await walletClient.signAuthorization({
2544
+ account,
2545
+ contractAddress: environmentConfig.erc7702DelegatorAddress,
2546
+ chainId,
2547
+ nonce: Number(authorizationNonce)
2548
+ });
2549
+ authorizationList = [signedAuthorization];
2550
+ }
2380
2551
  }
2381
2552
  if (pendingMessage) {
2382
2553
  logger.info(pendingMessage);
@@ -2391,6 +2562,9 @@ async function executeBatch(options, logger = noopLogger) {
2391
2562
  if (authorizationList.length > 0) {
2392
2563
  txRequest.authorizationList = authorizationList;
2393
2564
  }
2565
+ if (gas?.gasLimit) {
2566
+ txRequest.gas = gas.gasLimit;
2567
+ }
2394
2568
  if (gas?.maxFeePerGas) {
2395
2569
  txRequest.maxFeePerGas = gas.maxFeePerGas;
2396
2570
  }
@@ -2435,23 +2609,24 @@ var import_viem3 = require("viem");
2435
2609
  var import_viem2 = require("viem");
2436
2610
  var import_chains2 = require("viem/chains");
2437
2611
  var import_accounts = require("viem/accounts");
2438
- function getChainFromID(chainID, fallback = import_chains2.sepolia) {
2612
+ function getChainFromID(chainID, fallback2 = import_chains2.sepolia) {
2439
2613
  const id = Number(chainID);
2440
- return (0, import_viem2.extractChain)({ chains: SUPPORTED_CHAINS, id }) || fallback;
2614
+ return (0, import_viem2.extractChain)({ chains: SUPPORTED_CHAINS, id }) || fallback2;
2441
2615
  }
2442
2616
  function createClients(options) {
2443
2617
  const { privateKey, rpcUrl, chainId } = options;
2444
2618
  const privateKeyHex = addHexPrefix(privateKey);
2445
2619
  const account = (0, import_accounts.privateKeyToAccount)(privateKeyHex);
2446
2620
  const chain = getChainFromID(chainId);
2621
+ const transport = typeof rpcUrl === "string" ? (0, import_viem2.http)(rpcUrl) : (0, import_viem2.fallback)(rpcUrl.map((url) => (0, import_viem2.http)(url)));
2447
2622
  const publicClient = (0, import_viem2.createPublicClient)({
2448
2623
  chain,
2449
- transport: (0, import_viem2.http)(rpcUrl)
2624
+ transport
2450
2625
  });
2451
2626
  const walletClient = (0, import_viem2.createWalletClient)({
2452
2627
  account,
2453
2628
  chain,
2454
- transport: (0, import_viem2.http)(rpcUrl)
2629
+ transport
2455
2630
  });
2456
2631
  return { walletClient, publicClient };
2457
2632
  }
@@ -4139,7 +4314,8 @@ async function executeDeployBatch(data, context, gas, logger = noopLogger) {
4139
4314
  environmentConfig: context.environmentConfig,
4140
4315
  executions: data.executions,
4141
4316
  pendingMessage,
4142
- gas
4317
+ gas,
4318
+ authorizationList: data.authorizationList
4143
4319
  },
4144
4320
  logger
4145
4321
  );
@@ -4250,7 +4426,8 @@ async function executeUpgradeBatch(data, context, gas, logger = noopLogger) {
4250
4426
  environmentConfig: context.environmentConfig,
4251
4427
  executions: data.executions,
4252
4428
  pendingMessage,
4253
- gas
4429
+ gas,
4430
+ authorizationList: data.authorizationList
4254
4431
  },
4255
4432
  logger
4256
4433
  );
@@ -4560,166 +4737,44 @@ async function calculateBillingAuthSignature(options) {
4560
4737
  return { signature, expiry };
4561
4738
  }
4562
4739
 
4563
- // src/client/common/auth/session.ts
4564
- var SessionError = class extends Error {
4565
- constructor(message, code, statusCode) {
4566
- super(message);
4567
- this.code = code;
4568
- this.statusCode = statusCode;
4569
- this.name = "SessionError";
4570
- }
4571
- };
4572
- function stripHexPrefix2(hex) {
4573
- return hex.startsWith("0x") ? hex.slice(2) : hex;
4740
+ // src/client/common/utils/userapi.ts
4741
+ init_session();
4742
+ function isJsonObject(value) {
4743
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4574
4744
  }
4575
- async function parseErrorResponse(response) {
4576
- try {
4577
- const data = await response.json();
4578
- return data.error || response.statusText;
4579
- } catch {
4580
- return response.statusText;
4581
- }
4745
+ function readString(obj, key) {
4746
+ const v = obj[key];
4747
+ return typeof v === "string" ? v : void 0;
4582
4748
  }
4583
- async function loginToComputeApi(config, request) {
4584
- let response;
4585
- try {
4586
- response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
4587
- method: "POST",
4588
- credentials: "include",
4589
- // Include cookies for session management
4590
- headers: {
4591
- "Content-Type": "application/json"
4592
- },
4593
- body: JSON.stringify({
4594
- message: request.message,
4595
- signature: stripHexPrefix2(request.signature)
4596
- })
4597
- });
4598
- } catch (error) {
4599
- throw new SessionError(
4600
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
4601
- "NETWORK_ERROR"
4602
- );
4749
+ function readNumber(obj, key) {
4750
+ const v = obj[key];
4751
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4752
+ }
4753
+ var MAX_ADDRESS_COUNT = 5;
4754
+ var CanViewAppLogsPermission = "0x2fd3f2fe";
4755
+ var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4756
+ var CanUpdateAppProfilePermission = "0x036fef61";
4757
+ function getDefaultClientId() {
4758
+ const version = true ? "0.3.1-dev.0" : "0.0.0";
4759
+ return `ecloud-sdk/v${version}`;
4760
+ }
4761
+ var UserApiClient = class {
4762
+ constructor(config, walletClient, publicClient, options) {
4763
+ this.config = config;
4764
+ this.walletClient = walletClient;
4765
+ this.publicClient = publicClient;
4766
+ this.clientId = options?.clientId || getDefaultClientId();
4767
+ this.useSession = options?.useSession ?? false;
4603
4768
  }
4604
- if (!response.ok) {
4605
- const errorMessage = await parseErrorResponse(response);
4606
- const status = response.status;
4607
- if (status === 400) {
4608
- if (errorMessage.toLowerCase().includes("siwe")) {
4609
- throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
4610
- }
4611
- throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
4612
- }
4613
- if (status === 401) {
4614
- throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
4769
+ /**
4770
+ * Get the address of the connected wallet
4771
+ */
4772
+ get address() {
4773
+ const account = this.walletClient.account;
4774
+ if (!account) {
4775
+ throw new Error("WalletClient must have an account attached");
4615
4776
  }
4616
- throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
4617
- }
4618
- const data = await response.json();
4619
- return {
4620
- success: data.success,
4621
- address: data.address
4622
- };
4623
- }
4624
- async function getComputeApiSession(config) {
4625
- let response;
4626
- try {
4627
- response = await fetch(`${config.baseUrl}/auth/session`, {
4628
- method: "GET",
4629
- credentials: "include",
4630
- // Include cookies for session management
4631
- headers: {
4632
- "Content-Type": "application/json"
4633
- }
4634
- });
4635
- } catch {
4636
- return {
4637
- authenticated: false
4638
- };
4639
- }
4640
- if (response.status === 401) {
4641
- return {
4642
- authenticated: false
4643
- };
4644
- }
4645
- if (!response.ok) {
4646
- const errorMessage = await parseErrorResponse(response);
4647
- throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
4648
- }
4649
- const data = await response.json();
4650
- return {
4651
- authenticated: data.authenticated,
4652
- address: data.address,
4653
- chainId: data.chain_id
4654
- };
4655
- }
4656
- async function logoutFromComputeApi(config) {
4657
- let response;
4658
- try {
4659
- response = await fetch(`${config.baseUrl}/auth/logout`, {
4660
- method: "POST",
4661
- credentials: "include",
4662
- // Include cookies for session management
4663
- headers: {
4664
- "Content-Type": "application/json"
4665
- }
4666
- });
4667
- } catch (error) {
4668
- throw new SessionError(
4669
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
4670
- "NETWORK_ERROR"
4671
- );
4672
- }
4673
- if (response.status === 401) {
4674
- return;
4675
- }
4676
- if (!response.ok) {
4677
- const errorMessage = await parseErrorResponse(response);
4678
- throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
4679
- }
4680
- }
4681
- async function isSessionValid(config) {
4682
- const session = await getComputeApiSession(config);
4683
- return session.authenticated;
4684
- }
4685
-
4686
- // src/client/common/utils/userapi.ts
4687
- function isJsonObject(value) {
4688
- return typeof value === "object" && value !== null && !Array.isArray(value);
4689
- }
4690
- function readString(obj, key) {
4691
- const v = obj[key];
4692
- return typeof v === "string" ? v : void 0;
4693
- }
4694
- function readNumber(obj, key) {
4695
- const v = obj[key];
4696
- return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4697
- }
4698
- var MAX_ADDRESS_COUNT = 5;
4699
- var CanViewAppLogsPermission = "0x2fd3f2fe";
4700
- var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4701
- var CanUpdateAppProfilePermission = "0x036fef61";
4702
- function getDefaultClientId() {
4703
- const version = true ? "0.3.1-dev" : "0.0.0";
4704
- return `ecloud-sdk/v${version}`;
4705
- }
4706
- var UserApiClient = class {
4707
- constructor(config, walletClient, publicClient, options) {
4708
- this.config = config;
4709
- this.walletClient = walletClient;
4710
- this.publicClient = publicClient;
4711
- this.clientId = options?.clientId || getDefaultClientId();
4712
- this.useSession = options?.useSession ?? false;
4713
- }
4714
- /**
4715
- * Get the address of the connected wallet
4716
- */
4717
- get address() {
4718
- const account = this.walletClient.account;
4719
- if (!account) {
4720
- throw new Error("WalletClient must have an account attached");
4721
- }
4722
- return account.address;
4777
+ return account.address;
4723
4778
  }
4724
4779
  async getInfos(appIDs, addressCount = 1) {
4725
4780
  const count = Math.min(addressCount, MAX_ADDRESS_COUNT);
@@ -5608,21 +5663,214 @@ function isSubscriptionActive(status) {
5608
5663
 
5609
5664
  // src/client/common/utils/billingapi.ts
5610
5665
  var import_axios2 = __toESM(require("axios"), 1);
5666
+
5667
+ // src/client/common/auth/billingSession.ts
5668
+ var BillingSessionError = class extends Error {
5669
+ constructor(message, code, statusCode) {
5670
+ super(message);
5671
+ this.code = code;
5672
+ this.statusCode = statusCode;
5673
+ this.name = "BillingSessionError";
5674
+ }
5675
+ };
5676
+ function stripHexPrefix3(hex) {
5677
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
5678
+ }
5679
+ async function parseErrorResponse2(response) {
5680
+ try {
5681
+ const data = await response.json();
5682
+ return data.error || response.statusText;
5683
+ } catch {
5684
+ return response.statusText;
5685
+ }
5686
+ }
5687
+ async function loginToBillingApi(config, request) {
5688
+ let response;
5689
+ try {
5690
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
5691
+ method: "POST",
5692
+ credentials: "include",
5693
+ // Include cookies for session management
5694
+ headers: {
5695
+ "Content-Type": "application/json"
5696
+ },
5697
+ body: JSON.stringify({
5698
+ message: request.message,
5699
+ signature: stripHexPrefix3(request.signature)
5700
+ })
5701
+ });
5702
+ } catch (error) {
5703
+ throw new BillingSessionError(
5704
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5705
+ "NETWORK_ERROR"
5706
+ );
5707
+ }
5708
+ if (!response.ok) {
5709
+ const errorMessage = await parseErrorResponse2(response);
5710
+ const status = response.status;
5711
+ if (status === 400) {
5712
+ if (errorMessage.toLowerCase().includes("siwe")) {
5713
+ throw new BillingSessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
5714
+ }
5715
+ throw new BillingSessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
5716
+ }
5717
+ if (status === 401) {
5718
+ throw new BillingSessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
5719
+ }
5720
+ throw new BillingSessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
5721
+ }
5722
+ const data = await response.json();
5723
+ return {
5724
+ success: data.success,
5725
+ address: data.address
5726
+ };
5727
+ }
5728
+ async function getBillingApiSession(config) {
5729
+ let response;
5730
+ try {
5731
+ response = await fetch(`${config.baseUrl}/auth/session`, {
5732
+ method: "GET",
5733
+ credentials: "include",
5734
+ // Include cookies for session management
5735
+ headers: {
5736
+ "Content-Type": "application/json"
5737
+ }
5738
+ });
5739
+ } catch {
5740
+ return {
5741
+ authenticated: false
5742
+ };
5743
+ }
5744
+ if (response.status === 401) {
5745
+ return {
5746
+ authenticated: false
5747
+ };
5748
+ }
5749
+ if (!response.ok) {
5750
+ const errorMessage = await parseErrorResponse2(response);
5751
+ throw new BillingSessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
5752
+ }
5753
+ const data = await response.json();
5754
+ return {
5755
+ authenticated: data.authenticated,
5756
+ address: data.address,
5757
+ chainId: data.chainId,
5758
+ authenticatedAt: data.authenticatedAt
5759
+ };
5760
+ }
5761
+ async function logoutFromBillingApi(config) {
5762
+ let response;
5763
+ try {
5764
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
5765
+ method: "POST",
5766
+ credentials: "include",
5767
+ // Include cookies for session management
5768
+ headers: {
5769
+ "Content-Type": "application/json"
5770
+ }
5771
+ });
5772
+ } catch (error) {
5773
+ throw new BillingSessionError(
5774
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5775
+ "NETWORK_ERROR"
5776
+ );
5777
+ }
5778
+ if (response.status === 401) {
5779
+ return;
5780
+ }
5781
+ if (!response.ok) {
5782
+ const errorMessage = await parseErrorResponse2(response);
5783
+ throw new BillingSessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
5784
+ }
5785
+ }
5786
+
5787
+ // src/client/common/utils/billingapi.ts
5611
5788
  var BillingApiClient = class {
5612
- constructor(config, walletClient) {
5789
+ constructor(config, walletClient, options = {}) {
5613
5790
  this.config = config;
5614
5791
  this.walletClient = walletClient;
5792
+ this.options = options;
5793
+ this.useSession = options.useSession ?? false;
5794
+ if (!this.useSession && !walletClient) {
5795
+ throw new Error("WalletClient is required when not using session authentication");
5796
+ }
5615
5797
  }
5616
5798
  /**
5617
5799
  * Get the address of the connected wallet
5800
+ * Returns undefined if using session auth without a wallet client
5618
5801
  */
5619
5802
  get address() {
5620
- const account = this.walletClient.account;
5803
+ const account = this.walletClient?.account;
5621
5804
  if (!account) {
5622
- throw new Error("WalletClient must have an account attached");
5805
+ if (!this.useSession) {
5806
+ throw new Error("WalletClient must have an account attached");
5807
+ }
5808
+ return void 0;
5623
5809
  }
5624
5810
  return account.address;
5625
5811
  }
5812
+ /**
5813
+ * Get the base URL of the billing API
5814
+ */
5815
+ get baseUrl() {
5816
+ return this.config.billingApiServerURL;
5817
+ }
5818
+ // ==========================================================================
5819
+ // SIWE Session Methods
5820
+ // ==========================================================================
5821
+ /**
5822
+ * Login to the billing API using SIWE
5823
+ *
5824
+ * This establishes a session with the billing API by verifying the SIWE message
5825
+ * and signature. On success, a session cookie is set in the browser.
5826
+ *
5827
+ * @param request - Login request containing SIWE message and signature
5828
+ * @returns Login result with the authenticated address
5829
+ *
5830
+ * @example
5831
+ * ```typescript
5832
+ * const { message } = createSiweMessage({
5833
+ * address: userAddress,
5834
+ * chainId: 11155111,
5835
+ * domain: window.location.host,
5836
+ * uri: window.location.origin,
5837
+ * });
5838
+ *
5839
+ * const signature = await signMessageAsync({ message });
5840
+ * const result = await billingClient.siweLogin({ message, signature });
5841
+ * ```
5842
+ */
5843
+ async siweLogin(request) {
5844
+ return loginToBillingApi({ baseUrl: this.baseUrl }, request);
5845
+ }
5846
+ /**
5847
+ * Logout from the billing API
5848
+ *
5849
+ * This destroys the current session and clears the session cookie.
5850
+ */
5851
+ async siweLogout() {
5852
+ return logoutFromBillingApi({ baseUrl: this.baseUrl });
5853
+ }
5854
+ /**
5855
+ * Get the current session status from the billing API
5856
+ *
5857
+ * @returns Session information including authentication status and address
5858
+ */
5859
+ async getSession() {
5860
+ return getBillingApiSession({ baseUrl: this.baseUrl });
5861
+ }
5862
+ /**
5863
+ * Check if there is a valid session
5864
+ *
5865
+ * @returns True if session is authenticated, false otherwise
5866
+ */
5867
+ async isSessionValid() {
5868
+ const session = await this.getSession();
5869
+ return session.authenticated;
5870
+ }
5871
+ // ==========================================================================
5872
+ // Subscription Methods
5873
+ // ==========================================================================
5626
5874
  async createSubscription(productId = "compute", options) {
5627
5875
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5628
5876
  const body = options ? {
@@ -5641,10 +5889,72 @@ var BillingApiClient = class {
5641
5889
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5642
5890
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
5643
5891
  }
5892
+ // ==========================================================================
5893
+ // Internal Methods
5894
+ // ==========================================================================
5644
5895
  /**
5645
5896
  * Make an authenticated request to the billing API
5897
+ *
5898
+ * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
5646
5899
  */
5647
5900
  async makeAuthenticatedRequest(url, method, productId, body) {
5901
+ if (this.useSession) {
5902
+ return this.makeSessionAuthenticatedRequest(url, method, body);
5903
+ }
5904
+ return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
5905
+ }
5906
+ /**
5907
+ * Make a request using session-based authentication (cookies)
5908
+ */
5909
+ async makeSessionAuthenticatedRequest(url, method, body) {
5910
+ const headers = {};
5911
+ if (body) {
5912
+ headers["Content-Type"] = "application/json";
5913
+ }
5914
+ try {
5915
+ const response = await fetch(url, {
5916
+ method,
5917
+ credentials: "include",
5918
+ // Include cookies for session management
5919
+ headers,
5920
+ body: body ? JSON.stringify(body) : void 0
5921
+ });
5922
+ const status = response.status;
5923
+ const statusText = status >= 200 && status < 300 ? "OK" : "Error";
5924
+ if (status < 200 || status >= 300) {
5925
+ let errorBody;
5926
+ try {
5927
+ errorBody = await response.text();
5928
+ } catch {
5929
+ errorBody = statusText;
5930
+ }
5931
+ throw new Error(`BillingAPI request failed: ${status} ${statusText} - ${errorBody}`);
5932
+ }
5933
+ const responseData = await response.json();
5934
+ return {
5935
+ json: async () => responseData,
5936
+ text: async () => JSON.stringify(responseData)
5937
+ };
5938
+ } catch (error) {
5939
+ if (error.name === "TypeError" || error.message?.includes("fetch")) {
5940
+ throw new Error(
5941
+ `Failed to connect to BillingAPI at ${url}: ${error.message}
5942
+ Please check:
5943
+ 1. Your internet connection
5944
+ 2. The API server is accessible: ${this.config.billingApiServerURL}
5945
+ 3. Firewall/proxy settings`
5946
+ );
5947
+ }
5948
+ throw error;
5949
+ }
5950
+ }
5951
+ /**
5952
+ * Make a request using EIP-712 signature authentication
5953
+ */
5954
+ async makeSignatureAuthenticatedRequest(url, method, productId, body) {
5955
+ if (!this.walletClient) {
5956
+ throw new Error("WalletClient is required for signature authentication");
5957
+ }
5648
5958
  const expiry = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
5649
5959
  const { signature } = await calculateBillingAuthSignature({
5650
5960
  walletClient: this.walletClient,
@@ -5964,16 +6274,24 @@ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger)
5964
6274
  },
5965
6275
  logger
5966
6276
  );
6277
+ logger.debug("Checking delegation status...");
6278
+ const authorizationList = await createAuthorizationList({
6279
+ walletClient: batch.walletClient,
6280
+ publicClient: batch.publicClient,
6281
+ environmentConfig: batch.environmentConfig
6282
+ });
5967
6283
  logger.debug("Estimating gas...");
5968
6284
  const gasEstimate = await estimateBatchGas({
5969
6285
  publicClient: batch.publicClient,
5970
6286
  account: batch.walletClient.account.address,
5971
- executions: batch.executions
6287
+ executions: batch.executions,
6288
+ authorizationList
5972
6289
  });
5973
6290
  const data = {
5974
6291
  appId: batch.appId,
5975
6292
  salt: batch.salt,
5976
- executions: batch.executions
6293
+ executions: batch.executions,
6294
+ authorizationList
5977
6295
  };
5978
6296
  return {
5979
6297
  prepared: {
@@ -6202,16 +6520,24 @@ async function prepareDeploy(options, logger = defaultLogger) {
6202
6520
  },
6203
6521
  logger
6204
6522
  );
6523
+ logger.debug("Checking delegation status...");
6524
+ const authorizationList = await createAuthorizationList({
6525
+ walletClient: batch.walletClient,
6526
+ publicClient: batch.publicClient,
6527
+ environmentConfig: batch.environmentConfig
6528
+ });
6205
6529
  logger.debug("Estimating gas...");
6206
6530
  const gasEstimate = await estimateBatchGas({
6207
6531
  publicClient: batch.publicClient,
6208
6532
  account: batch.walletClient.account.address,
6209
- executions: batch.executions
6533
+ executions: batch.executions,
6534
+ authorizationList
6210
6535
  });
6211
6536
  const data = {
6212
6537
  appId: batch.appId,
6213
6538
  salt: batch.salt,
6214
- executions: batch.executions
6539
+ executions: batch.executions,
6540
+ authorizationList
6215
6541
  };
6216
6542
  return {
6217
6543
  prepared: {
@@ -6342,15 +6668,23 @@ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger
6342
6668
  needsPermissionChange,
6343
6669
  imageRef: options.imageRef
6344
6670
  });
6671
+ logger.debug("Checking delegation status...");
6672
+ const authorizationList = await createAuthorizationList({
6673
+ walletClient: batch.walletClient,
6674
+ publicClient: batch.publicClient,
6675
+ environmentConfig: batch.environmentConfig
6676
+ });
6345
6677
  logger.debug("Estimating gas...");
6346
6678
  const gasEstimate = await estimateBatchGas({
6347
6679
  publicClient: batch.publicClient,
6348
6680
  account: batch.walletClient.account.address,
6349
- executions: batch.executions
6681
+ executions: batch.executions,
6682
+ authorizationList
6350
6683
  });
6351
6684
  const data = {
6352
6685
  appId: batch.appId,
6353
- executions: batch.executions
6686
+ executions: batch.executions,
6687
+ authorizationList
6354
6688
  };
6355
6689
  return {
6356
6690
  prepared: {
@@ -6523,15 +6857,23 @@ async function prepareUpgrade(options, logger = defaultLogger) {
6523
6857
  needsPermissionChange,
6524
6858
  imageRef: finalImageRef
6525
6859
  });
6860
+ logger.debug("Checking delegation status...");
6861
+ const authorizationList = await createAuthorizationList({
6862
+ walletClient: batch.walletClient,
6863
+ publicClient: batch.publicClient,
6864
+ environmentConfig: batch.environmentConfig
6865
+ });
6526
6866
  logger.debug("Estimating gas...");
6527
6867
  const gasEstimate = await estimateBatchGas({
6528
6868
  publicClient: batch.publicClient,
6529
6869
  account: batch.walletClient.account.address,
6530
- executions: batch.executions
6870
+ executions: batch.executions,
6871
+ authorizationList
6531
6872
  });
6532
6873
  const data = {
6533
6874
  appId: batch.appId,
6534
- executions: batch.executions
6875
+ executions: batch.executions,
6876
+ authorizationList
6535
6877
  };
6536
6878
  return {
6537
6879
  prepared: {
@@ -7659,7 +8001,10 @@ function createBillingModule(config) {
7659
8001
  };
7660
8002
  }
7661
8003
  logger.debug(`Creating subscription for ${productId}...`);
7662
- const result = await billingApi.createSubscription(productId);
8004
+ const result = await billingApi.createSubscription(productId, {
8005
+ successUrl: opts?.successUrl,
8006
+ cancelUrl: opts?.cancelUrl
8007
+ });
7663
8008
  logger.debug(`Checkout URL: ${result.checkoutUrl}`);
7664
8009
  return {
7665
8010
  type: "checkout_created",
@@ -7751,9 +8096,22 @@ async function requestWithRetry(config) {
7751
8096
  }
7752
8097
  var BuildApiClient = class {
7753
8098
  constructor(options) {
7754
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
8099
+ let url = options.baseUrl;
8100
+ while (url.endsWith("/")) {
8101
+ url = url.slice(0, -1);
8102
+ }
8103
+ this.baseUrl = url;
7755
8104
  this.clientId = options.clientId;
7756
8105
  this.walletClient = options.walletClient;
8106
+ this.useSession = options.useSession ?? false;
8107
+ this.billingSessionId = options.billingSessionId;
8108
+ }
8109
+ /**
8110
+ * Update the billing session ID.
8111
+ * Call this after logging into the billing API to enable session-based auth for builds.
8112
+ */
8113
+ setBillingSessionId(sessionId) {
8114
+ this.billingSessionId = sessionId;
7757
8115
  }
7758
8116
  /**
7759
8117
  * Get the address of the connected wallet
@@ -7765,8 +8123,17 @@ var BuildApiClient = class {
7765
8123
  }
7766
8124
  return account.address;
7767
8125
  }
8126
+ /**
8127
+ * Submit a new build request.
8128
+ * Supports two auth modes (session auth is tried first when billingSessionId is available):
8129
+ * 1. Session-based auth: X-Billing-Session header (forwarded billing_session cookie)
8130
+ * 2. Signature-based auth: Authorization + X-Account + X-eigenx-expiry headers (requires walletClient)
8131
+ */
7768
8132
  async submitBuild(payload) {
7769
- return this.authenticatedJsonRequest("/builds", "POST", payload);
8133
+ if (this.useSession && this.billingSessionId) {
8134
+ return this.billingSessionAuthJsonRequest("/builds", "POST", payload);
8135
+ }
8136
+ return this.signatureAuthJsonRequest("/builds", "POST", payload);
7770
8137
  }
7771
8138
  async getBuild(buildId) {
7772
8139
  return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
@@ -7777,8 +8144,11 @@ var BuildApiClient = class {
7777
8144
  async verify(identifier) {
7778
8145
  return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
7779
8146
  }
8147
+ /**
8148
+ * Get build logs. Supports session auth (identity verification only, no billing check).
8149
+ */
7780
8150
  async getLogs(buildId) {
7781
- return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
8151
+ return this.sessionOrSignatureTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
7782
8152
  }
7783
8153
  async listBuilds(params) {
7784
8154
  const res = await requestWithRetry({
@@ -7786,7 +8156,9 @@ var BuildApiClient = class {
7786
8156
  method: "GET",
7787
8157
  params,
7788
8158
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7789
- timeout: 6e4
8159
+ timeout: 6e4,
8160
+ validateStatus: () => true,
8161
+ withCredentials: this.useSession
7790
8162
  });
7791
8163
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7792
8164
  return res.data;
@@ -7796,12 +8168,18 @@ var BuildApiClient = class {
7796
8168
  url: `${this.baseUrl}${path8}`,
7797
8169
  method: "GET",
7798
8170
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7799
- timeout: 6e4
8171
+ timeout: 6e4,
8172
+ validateStatus: () => true,
8173
+ withCredentials: this.useSession
7800
8174
  });
7801
8175
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7802
8176
  return res.data;
7803
8177
  }
7804
- async authenticatedJsonRequest(path8, method, body) {
8178
+ /**
8179
+ * Make a request that ALWAYS requires signature auth (for billing verification).
8180
+ * Used for endpoints like POST /builds that need to verify subscription status.
8181
+ */
8182
+ async signatureAuthJsonRequest(path8, method, body) {
7805
8183
  if (!this.walletClient?.account) {
7806
8184
  throw new Error("WalletClient with account required for authenticated requests");
7807
8185
  }
@@ -7823,32 +8201,69 @@ var BuildApiClient = class {
7823
8201
  method,
7824
8202
  headers,
7825
8203
  data: body,
7826
- timeout: 6e4
8204
+ timeout: 6e4,
8205
+ validateStatus: () => true,
8206
+ withCredentials: this.useSession
7827
8207
  });
7828
8208
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7829
8209
  return res.data;
7830
8210
  }
7831
- async authenticatedTextRequest(path8) {
7832
- if (!this.walletClient?.account) {
7833
- throw new Error("WalletClient with account required for authenticated requests");
8211
+ /**
8212
+ * Make a request using billing session auth (for billing verification without wallet signature).
8213
+ * Forwards the billing_session cookie value via X-Billing-Session header.
8214
+ * Used for endpoints that need to verify subscription status when using session-based auth.
8215
+ */
8216
+ async billingSessionAuthJsonRequest(path8, method, body) {
8217
+ if (!this.billingSessionId) {
8218
+ throw new Error("billingSessionId required for session-based billing auth");
7834
8219
  }
7835
- const headers = {};
8220
+ const headers = {
8221
+ "Content-Type": "application/json",
8222
+ "X-Billing-Session": this.billingSessionId
8223
+ };
7836
8224
  if (this.clientId) headers["x-client-id"] = this.clientId;
7837
- const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
7838
- const { signature } = await calculateBillingAuthSignature({
7839
- walletClient: this.walletClient,
7840
- product: "compute",
7841
- expiry
8225
+ const res = await requestWithRetry({
8226
+ url: `${this.baseUrl}${path8}`,
8227
+ method,
8228
+ headers,
8229
+ data: body,
8230
+ timeout: 6e4,
8231
+ validateStatus: () => true,
8232
+ withCredentials: this.useSession
7842
8233
  });
7843
- headers.Authorization = `Bearer ${signature}`;
7844
- headers["X-eigenx-expiry"] = expiry.toString();
7845
- headers["X-Account"] = this.address;
8234
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
8235
+ return res.data;
8236
+ }
8237
+ /**
8238
+ * Make an authenticated request that can use session OR signature auth.
8239
+ * When useSession is true, relies on cookies for identity verification.
8240
+ * Used for endpoints that only need identity verification (not billing).
8241
+ */
8242
+ async sessionOrSignatureTextRequest(path8) {
8243
+ const headers = {};
8244
+ if (this.clientId) headers["x-client-id"] = this.clientId;
8245
+ if (!this.useSession) {
8246
+ if (!this.walletClient?.account) {
8247
+ throw new Error("WalletClient with account required for authenticated requests");
8248
+ }
8249
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
8250
+ const { signature } = await calculateBillingAuthSignature({
8251
+ walletClient: this.walletClient,
8252
+ product: "compute",
8253
+ expiry
8254
+ });
8255
+ headers.Authorization = `Bearer ${signature}`;
8256
+ headers["X-eigenx-expiry"] = expiry.toString();
8257
+ headers["X-Account"] = this.address;
8258
+ }
7846
8259
  const res = await requestWithRetry({
7847
8260
  url: `${this.baseUrl}${path8}`,
7848
8261
  method: "GET",
7849
8262
  headers,
7850
8263
  timeout: 6e4,
7851
- responseType: "text"
8264
+ responseType: "text",
8265
+ validateStatus: () => true,
8266
+ withCredentials: this.useSession
7852
8267
  });
7853
8268
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7854
8269
  return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
@@ -8415,6 +8830,9 @@ function isSiweMessageNotYetValid(params) {
8415
8830
  return /* @__PURE__ */ new Date() < params.notBefore;
8416
8831
  }
8417
8832
 
8833
+ // src/client/common/auth/index.ts
8834
+ init_session();
8835
+
8418
8836
  // src/client/common/utils/instance.ts
8419
8837
  async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
8420
8838
  try {