@layr-labs/ecloud-sdk 0.2.2-dev → 0.3.0-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
  }
@@ -4139,7 +4313,8 @@ async function executeDeployBatch(data, context, gas, logger = noopLogger) {
4139
4313
  environmentConfig: context.environmentConfig,
4140
4314
  executions: data.executions,
4141
4315
  pendingMessage,
4142
- gas
4316
+ gas,
4317
+ authorizationList: data.authorizationList
4143
4318
  },
4144
4319
  logger
4145
4320
  );
@@ -4250,7 +4425,8 @@ async function executeUpgradeBatch(data, context, gas, logger = noopLogger) {
4250
4425
  environmentConfig: context.environmentConfig,
4251
4426
  executions: data.executions,
4252
4427
  pendingMessage,
4253
- gas
4428
+ gas,
4429
+ authorizationList: data.authorizationList
4254
4430
  },
4255
4431
  logger
4256
4432
  );
@@ -4560,166 +4736,44 @@ async function calculateBillingAuthSignature(options) {
4560
4736
  return { signature, expiry };
4561
4737
  }
4562
4738
 
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;
4739
+ // src/client/common/utils/userapi.ts
4740
+ init_session();
4741
+ function isJsonObject(value) {
4742
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4574
4743
  }
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
- }
4744
+ function readString(obj, key) {
4745
+ const v = obj[key];
4746
+ return typeof v === "string" ? v : void 0;
4582
4747
  }
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
- );
4748
+ function readNumber(obj, key) {
4749
+ const v = obj[key];
4750
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4751
+ }
4752
+ var MAX_ADDRESS_COUNT = 5;
4753
+ var CanViewAppLogsPermission = "0x2fd3f2fe";
4754
+ var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4755
+ var CanUpdateAppProfilePermission = "0x036fef61";
4756
+ function getDefaultClientId() {
4757
+ const version = true ? "0.3.0-dev.0" : "0.0.0";
4758
+ return `ecloud-sdk/v${version}`;
4759
+ }
4760
+ var UserApiClient = class {
4761
+ constructor(config, walletClient, publicClient, options) {
4762
+ this.config = config;
4763
+ this.walletClient = walletClient;
4764
+ this.publicClient = publicClient;
4765
+ this.clientId = options?.clientId || getDefaultClientId();
4766
+ this.useSession = options?.useSession ?? false;
4603
4767
  }
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);
4768
+ /**
4769
+ * Get the address of the connected wallet
4770
+ */
4771
+ get address() {
4772
+ const account = this.walletClient.account;
4773
+ if (!account) {
4774
+ throw new Error("WalletClient must have an account attached");
4615
4775
  }
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.2.2-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;
4776
+ return account.address;
4723
4777
  }
4724
4778
  async getInfos(appIDs, addressCount = 1) {
4725
4779
  const count = Math.min(addressCount, MAX_ADDRESS_COUNT);
@@ -5608,21 +5662,214 @@ function isSubscriptionActive(status) {
5608
5662
 
5609
5663
  // src/client/common/utils/billingapi.ts
5610
5664
  var import_axios2 = __toESM(require("axios"), 1);
5665
+
5666
+ // src/client/common/auth/billingSession.ts
5667
+ var BillingSessionError = class extends Error {
5668
+ constructor(message, code, statusCode) {
5669
+ super(message);
5670
+ this.code = code;
5671
+ this.statusCode = statusCode;
5672
+ this.name = "BillingSessionError";
5673
+ }
5674
+ };
5675
+ function stripHexPrefix3(hex) {
5676
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
5677
+ }
5678
+ async function parseErrorResponse2(response) {
5679
+ try {
5680
+ const data = await response.json();
5681
+ return data.error || response.statusText;
5682
+ } catch {
5683
+ return response.statusText;
5684
+ }
5685
+ }
5686
+ async function loginToBillingApi(config, request) {
5687
+ let response;
5688
+ try {
5689
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
5690
+ method: "POST",
5691
+ credentials: "include",
5692
+ // Include cookies for session management
5693
+ headers: {
5694
+ "Content-Type": "application/json"
5695
+ },
5696
+ body: JSON.stringify({
5697
+ message: request.message,
5698
+ signature: stripHexPrefix3(request.signature)
5699
+ })
5700
+ });
5701
+ } catch (error) {
5702
+ throw new BillingSessionError(
5703
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5704
+ "NETWORK_ERROR"
5705
+ );
5706
+ }
5707
+ if (!response.ok) {
5708
+ const errorMessage = await parseErrorResponse2(response);
5709
+ const status = response.status;
5710
+ if (status === 400) {
5711
+ if (errorMessage.toLowerCase().includes("siwe")) {
5712
+ throw new BillingSessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
5713
+ }
5714
+ throw new BillingSessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
5715
+ }
5716
+ if (status === 401) {
5717
+ throw new BillingSessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
5718
+ }
5719
+ throw new BillingSessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
5720
+ }
5721
+ const data = await response.json();
5722
+ return {
5723
+ success: data.success,
5724
+ address: data.address
5725
+ };
5726
+ }
5727
+ async function getBillingApiSession(config) {
5728
+ let response;
5729
+ try {
5730
+ response = await fetch(`${config.baseUrl}/auth/session`, {
5731
+ method: "GET",
5732
+ credentials: "include",
5733
+ // Include cookies for session management
5734
+ headers: {
5735
+ "Content-Type": "application/json"
5736
+ }
5737
+ });
5738
+ } catch {
5739
+ return {
5740
+ authenticated: false
5741
+ };
5742
+ }
5743
+ if (response.status === 401) {
5744
+ return {
5745
+ authenticated: false
5746
+ };
5747
+ }
5748
+ if (!response.ok) {
5749
+ const errorMessage = await parseErrorResponse2(response);
5750
+ throw new BillingSessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
5751
+ }
5752
+ const data = await response.json();
5753
+ return {
5754
+ authenticated: data.authenticated,
5755
+ address: data.address,
5756
+ chainId: data.chainId,
5757
+ authenticatedAt: data.authenticatedAt
5758
+ };
5759
+ }
5760
+ async function logoutFromBillingApi(config) {
5761
+ let response;
5762
+ try {
5763
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
5764
+ method: "POST",
5765
+ credentials: "include",
5766
+ // Include cookies for session management
5767
+ headers: {
5768
+ "Content-Type": "application/json"
5769
+ }
5770
+ });
5771
+ } catch (error) {
5772
+ throw new BillingSessionError(
5773
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5774
+ "NETWORK_ERROR"
5775
+ );
5776
+ }
5777
+ if (response.status === 401) {
5778
+ return;
5779
+ }
5780
+ if (!response.ok) {
5781
+ const errorMessage = await parseErrorResponse2(response);
5782
+ throw new BillingSessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
5783
+ }
5784
+ }
5785
+
5786
+ // src/client/common/utils/billingapi.ts
5611
5787
  var BillingApiClient = class {
5612
- constructor(config, walletClient) {
5788
+ constructor(config, walletClient, options = {}) {
5613
5789
  this.config = config;
5614
5790
  this.walletClient = walletClient;
5791
+ this.options = options;
5792
+ this.useSession = options.useSession ?? false;
5793
+ if (!this.useSession && !walletClient) {
5794
+ throw new Error("WalletClient is required when not using session authentication");
5795
+ }
5615
5796
  }
5616
5797
  /**
5617
5798
  * Get the address of the connected wallet
5799
+ * Returns undefined if using session auth without a wallet client
5618
5800
  */
5619
5801
  get address() {
5620
- const account = this.walletClient.account;
5802
+ const account = this.walletClient?.account;
5621
5803
  if (!account) {
5622
- throw new Error("WalletClient must have an account attached");
5804
+ if (!this.useSession) {
5805
+ throw new Error("WalletClient must have an account attached");
5806
+ }
5807
+ return void 0;
5623
5808
  }
5624
5809
  return account.address;
5625
5810
  }
5811
+ /**
5812
+ * Get the base URL of the billing API
5813
+ */
5814
+ get baseUrl() {
5815
+ return this.config.billingApiServerURL;
5816
+ }
5817
+ // ==========================================================================
5818
+ // SIWE Session Methods
5819
+ // ==========================================================================
5820
+ /**
5821
+ * Login to the billing API using SIWE
5822
+ *
5823
+ * This establishes a session with the billing API by verifying the SIWE message
5824
+ * and signature. On success, a session cookie is set in the browser.
5825
+ *
5826
+ * @param request - Login request containing SIWE message and signature
5827
+ * @returns Login result with the authenticated address
5828
+ *
5829
+ * @example
5830
+ * ```typescript
5831
+ * const { message } = createSiweMessage({
5832
+ * address: userAddress,
5833
+ * chainId: 11155111,
5834
+ * domain: window.location.host,
5835
+ * uri: window.location.origin,
5836
+ * });
5837
+ *
5838
+ * const signature = await signMessageAsync({ message });
5839
+ * const result = await billingClient.siweLogin({ message, signature });
5840
+ * ```
5841
+ */
5842
+ async siweLogin(request) {
5843
+ return loginToBillingApi({ baseUrl: this.baseUrl }, request);
5844
+ }
5845
+ /**
5846
+ * Logout from the billing API
5847
+ *
5848
+ * This destroys the current session and clears the session cookie.
5849
+ */
5850
+ async siweLogout() {
5851
+ return logoutFromBillingApi({ baseUrl: this.baseUrl });
5852
+ }
5853
+ /**
5854
+ * Get the current session status from the billing API
5855
+ *
5856
+ * @returns Session information including authentication status and address
5857
+ */
5858
+ async getSession() {
5859
+ return getBillingApiSession({ baseUrl: this.baseUrl });
5860
+ }
5861
+ /**
5862
+ * Check if there is a valid session
5863
+ *
5864
+ * @returns True if session is authenticated, false otherwise
5865
+ */
5866
+ async isSessionValid() {
5867
+ const session = await this.getSession();
5868
+ return session.authenticated;
5869
+ }
5870
+ // ==========================================================================
5871
+ // Subscription Methods
5872
+ // ==========================================================================
5626
5873
  async createSubscription(productId = "compute", options) {
5627
5874
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5628
5875
  const body = options ? {
@@ -5641,10 +5888,72 @@ var BillingApiClient = class {
5641
5888
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5642
5889
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
5643
5890
  }
5891
+ // ==========================================================================
5892
+ // Internal Methods
5893
+ // ==========================================================================
5644
5894
  /**
5645
5895
  * Make an authenticated request to the billing API
5896
+ *
5897
+ * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
5646
5898
  */
5647
5899
  async makeAuthenticatedRequest(url, method, productId, body) {
5900
+ if (this.useSession) {
5901
+ return this.makeSessionAuthenticatedRequest(url, method, body);
5902
+ }
5903
+ return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
5904
+ }
5905
+ /**
5906
+ * Make a request using session-based authentication (cookies)
5907
+ */
5908
+ async makeSessionAuthenticatedRequest(url, method, body) {
5909
+ const headers = {};
5910
+ if (body) {
5911
+ headers["Content-Type"] = "application/json";
5912
+ }
5913
+ try {
5914
+ const response = await fetch(url, {
5915
+ method,
5916
+ credentials: "include",
5917
+ // Include cookies for session management
5918
+ headers,
5919
+ body: body ? JSON.stringify(body) : void 0
5920
+ });
5921
+ const status = response.status;
5922
+ const statusText = status >= 200 && status < 300 ? "OK" : "Error";
5923
+ if (status < 200 || status >= 300) {
5924
+ let errorBody;
5925
+ try {
5926
+ errorBody = await response.text();
5927
+ } catch {
5928
+ errorBody = statusText;
5929
+ }
5930
+ throw new Error(`BillingAPI request failed: ${status} ${statusText} - ${errorBody}`);
5931
+ }
5932
+ const responseData = await response.json();
5933
+ return {
5934
+ json: async () => responseData,
5935
+ text: async () => JSON.stringify(responseData)
5936
+ };
5937
+ } catch (error) {
5938
+ if (error.name === "TypeError" || error.message?.includes("fetch")) {
5939
+ throw new Error(
5940
+ `Failed to connect to BillingAPI at ${url}: ${error.message}
5941
+ Please check:
5942
+ 1. Your internet connection
5943
+ 2. The API server is accessible: ${this.config.billingApiServerURL}
5944
+ 3. Firewall/proxy settings`
5945
+ );
5946
+ }
5947
+ throw error;
5948
+ }
5949
+ }
5950
+ /**
5951
+ * Make a request using EIP-712 signature authentication
5952
+ */
5953
+ async makeSignatureAuthenticatedRequest(url, method, productId, body) {
5954
+ if (!this.walletClient) {
5955
+ throw new Error("WalletClient is required for signature authentication");
5956
+ }
5648
5957
  const expiry = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
5649
5958
  const { signature } = await calculateBillingAuthSignature({
5650
5959
  walletClient: this.walletClient,
@@ -5964,16 +6273,24 @@ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger)
5964
6273
  },
5965
6274
  logger
5966
6275
  );
6276
+ logger.debug("Checking delegation status...");
6277
+ const authorizationList = await createAuthorizationList({
6278
+ walletClient: batch.walletClient,
6279
+ publicClient: batch.publicClient,
6280
+ environmentConfig: batch.environmentConfig
6281
+ });
5967
6282
  logger.debug("Estimating gas...");
5968
6283
  const gasEstimate = await estimateBatchGas({
5969
6284
  publicClient: batch.publicClient,
5970
6285
  account: batch.walletClient.account.address,
5971
- executions: batch.executions
6286
+ executions: batch.executions,
6287
+ authorizationList
5972
6288
  });
5973
6289
  const data = {
5974
6290
  appId: batch.appId,
5975
6291
  salt: batch.salt,
5976
- executions: batch.executions
6292
+ executions: batch.executions,
6293
+ authorizationList
5977
6294
  };
5978
6295
  return {
5979
6296
  prepared: {
@@ -6202,16 +6519,24 @@ async function prepareDeploy(options, logger = defaultLogger) {
6202
6519
  },
6203
6520
  logger
6204
6521
  );
6522
+ logger.debug("Checking delegation status...");
6523
+ const authorizationList = await createAuthorizationList({
6524
+ walletClient: batch.walletClient,
6525
+ publicClient: batch.publicClient,
6526
+ environmentConfig: batch.environmentConfig
6527
+ });
6205
6528
  logger.debug("Estimating gas...");
6206
6529
  const gasEstimate = await estimateBatchGas({
6207
6530
  publicClient: batch.publicClient,
6208
6531
  account: batch.walletClient.account.address,
6209
- executions: batch.executions
6532
+ executions: batch.executions,
6533
+ authorizationList
6210
6534
  });
6211
6535
  const data = {
6212
6536
  appId: batch.appId,
6213
6537
  salt: batch.salt,
6214
- executions: batch.executions
6538
+ executions: batch.executions,
6539
+ authorizationList
6215
6540
  };
6216
6541
  return {
6217
6542
  prepared: {
@@ -6342,15 +6667,23 @@ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger
6342
6667
  needsPermissionChange,
6343
6668
  imageRef: options.imageRef
6344
6669
  });
6670
+ logger.debug("Checking delegation status...");
6671
+ const authorizationList = await createAuthorizationList({
6672
+ walletClient: batch.walletClient,
6673
+ publicClient: batch.publicClient,
6674
+ environmentConfig: batch.environmentConfig
6675
+ });
6345
6676
  logger.debug("Estimating gas...");
6346
6677
  const gasEstimate = await estimateBatchGas({
6347
6678
  publicClient: batch.publicClient,
6348
6679
  account: batch.walletClient.account.address,
6349
- executions: batch.executions
6680
+ executions: batch.executions,
6681
+ authorizationList
6350
6682
  });
6351
6683
  const data = {
6352
6684
  appId: batch.appId,
6353
- executions: batch.executions
6685
+ executions: batch.executions,
6686
+ authorizationList
6354
6687
  };
6355
6688
  return {
6356
6689
  prepared: {
@@ -6523,15 +6856,23 @@ async function prepareUpgrade(options, logger = defaultLogger) {
6523
6856
  needsPermissionChange,
6524
6857
  imageRef: finalImageRef
6525
6858
  });
6859
+ logger.debug("Checking delegation status...");
6860
+ const authorizationList = await createAuthorizationList({
6861
+ walletClient: batch.walletClient,
6862
+ publicClient: batch.publicClient,
6863
+ environmentConfig: batch.environmentConfig
6864
+ });
6526
6865
  logger.debug("Estimating gas...");
6527
6866
  const gasEstimate = await estimateBatchGas({
6528
6867
  publicClient: batch.publicClient,
6529
6868
  account: batch.walletClient.account.address,
6530
- executions: batch.executions
6869
+ executions: batch.executions,
6870
+ authorizationList
6531
6871
  });
6532
6872
  const data = {
6533
6873
  appId: batch.appId,
6534
- executions: batch.executions
6874
+ executions: batch.executions,
6875
+ authorizationList
6535
6876
  };
6536
6877
  return {
6537
6878
  prepared: {
@@ -7659,7 +8000,10 @@ function createBillingModule(config) {
7659
8000
  };
7660
8001
  }
7661
8002
  logger.debug(`Creating subscription for ${productId}...`);
7662
- const result = await billingApi.createSubscription(productId);
8003
+ const result = await billingApi.createSubscription(productId, {
8004
+ successUrl: opts?.successUrl,
8005
+ cancelUrl: opts?.cancelUrl
8006
+ });
7663
8007
  logger.debug(`Checkout URL: ${result.checkoutUrl}`);
7664
8008
  return {
7665
8009
  type: "checkout_created",
@@ -7751,9 +8095,22 @@ async function requestWithRetry(config) {
7751
8095
  }
7752
8096
  var BuildApiClient = class {
7753
8097
  constructor(options) {
7754
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
8098
+ let url = options.baseUrl;
8099
+ while (url.endsWith("/")) {
8100
+ url = url.slice(0, -1);
8101
+ }
8102
+ this.baseUrl = url;
7755
8103
  this.clientId = options.clientId;
7756
8104
  this.walletClient = options.walletClient;
8105
+ this.useSession = options.useSession ?? false;
8106
+ this.billingSessionId = options.billingSessionId;
8107
+ }
8108
+ /**
8109
+ * Update the billing session ID.
8110
+ * Call this after logging into the billing API to enable session-based auth for builds.
8111
+ */
8112
+ setBillingSessionId(sessionId) {
8113
+ this.billingSessionId = sessionId;
7757
8114
  }
7758
8115
  /**
7759
8116
  * Get the address of the connected wallet
@@ -7765,8 +8122,17 @@ var BuildApiClient = class {
7765
8122
  }
7766
8123
  return account.address;
7767
8124
  }
8125
+ /**
8126
+ * Submit a new build request.
8127
+ * Supports two auth modes (session auth is tried first when billingSessionId is available):
8128
+ * 1. Session-based auth: X-Billing-Session header (forwarded billing_session cookie)
8129
+ * 2. Signature-based auth: Authorization + X-Account + X-eigenx-expiry headers (requires walletClient)
8130
+ */
7768
8131
  async submitBuild(payload) {
7769
- return this.authenticatedJsonRequest("/builds", "POST", payload);
8132
+ if (this.useSession && this.billingSessionId) {
8133
+ return this.billingSessionAuthJsonRequest("/builds", "POST", payload);
8134
+ }
8135
+ return this.signatureAuthJsonRequest("/builds", "POST", payload);
7770
8136
  }
7771
8137
  async getBuild(buildId) {
7772
8138
  return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
@@ -7777,8 +8143,11 @@ var BuildApiClient = class {
7777
8143
  async verify(identifier) {
7778
8144
  return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
7779
8145
  }
8146
+ /**
8147
+ * Get build logs. Supports session auth (identity verification only, no billing check).
8148
+ */
7780
8149
  async getLogs(buildId) {
7781
- return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
8150
+ return this.sessionOrSignatureTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
7782
8151
  }
7783
8152
  async listBuilds(params) {
7784
8153
  const res = await requestWithRetry({
@@ -7786,7 +8155,9 @@ var BuildApiClient = class {
7786
8155
  method: "GET",
7787
8156
  params,
7788
8157
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7789
- timeout: 6e4
8158
+ timeout: 6e4,
8159
+ validateStatus: () => true,
8160
+ withCredentials: this.useSession
7790
8161
  });
7791
8162
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7792
8163
  return res.data;
@@ -7796,12 +8167,18 @@ var BuildApiClient = class {
7796
8167
  url: `${this.baseUrl}${path8}`,
7797
8168
  method: "GET",
7798
8169
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7799
- timeout: 6e4
8170
+ timeout: 6e4,
8171
+ validateStatus: () => true,
8172
+ withCredentials: this.useSession
7800
8173
  });
7801
8174
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7802
8175
  return res.data;
7803
8176
  }
7804
- async authenticatedJsonRequest(path8, method, body) {
8177
+ /**
8178
+ * Make a request that ALWAYS requires signature auth (for billing verification).
8179
+ * Used for endpoints like POST /builds that need to verify subscription status.
8180
+ */
8181
+ async signatureAuthJsonRequest(path8, method, body) {
7805
8182
  if (!this.walletClient?.account) {
7806
8183
  throw new Error("WalletClient with account required for authenticated requests");
7807
8184
  }
@@ -7823,32 +8200,69 @@ var BuildApiClient = class {
7823
8200
  method,
7824
8201
  headers,
7825
8202
  data: body,
7826
- timeout: 6e4
8203
+ timeout: 6e4,
8204
+ validateStatus: () => true,
8205
+ withCredentials: this.useSession
7827
8206
  });
7828
8207
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7829
8208
  return res.data;
7830
8209
  }
7831
- async authenticatedTextRequest(path8) {
7832
- if (!this.walletClient?.account) {
7833
- throw new Error("WalletClient with account required for authenticated requests");
8210
+ /**
8211
+ * Make a request using billing session auth (for billing verification without wallet signature).
8212
+ * Forwards the billing_session cookie value via X-Billing-Session header.
8213
+ * Used for endpoints that need to verify subscription status when using session-based auth.
8214
+ */
8215
+ async billingSessionAuthJsonRequest(path8, method, body) {
8216
+ if (!this.billingSessionId) {
8217
+ throw new Error("billingSessionId required for session-based billing auth");
7834
8218
  }
7835
- const headers = {};
8219
+ const headers = {
8220
+ "Content-Type": "application/json",
8221
+ "X-Billing-Session": this.billingSessionId
8222
+ };
7836
8223
  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
8224
+ const res = await requestWithRetry({
8225
+ url: `${this.baseUrl}${path8}`,
8226
+ method,
8227
+ headers,
8228
+ data: body,
8229
+ timeout: 6e4,
8230
+ validateStatus: () => true,
8231
+ withCredentials: this.useSession
7842
8232
  });
7843
- headers.Authorization = `Bearer ${signature}`;
7844
- headers["X-eigenx-expiry"] = expiry.toString();
7845
- headers["X-Account"] = this.address;
8233
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
8234
+ return res.data;
8235
+ }
8236
+ /**
8237
+ * Make an authenticated request that can use session OR signature auth.
8238
+ * When useSession is true, relies on cookies for identity verification.
8239
+ * Used for endpoints that only need identity verification (not billing).
8240
+ */
8241
+ async sessionOrSignatureTextRequest(path8) {
8242
+ const headers = {};
8243
+ if (this.clientId) headers["x-client-id"] = this.clientId;
8244
+ if (!this.useSession) {
8245
+ if (!this.walletClient?.account) {
8246
+ throw new Error("WalletClient with account required for authenticated requests");
8247
+ }
8248
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
8249
+ const { signature } = await calculateBillingAuthSignature({
8250
+ walletClient: this.walletClient,
8251
+ product: "compute",
8252
+ expiry
8253
+ });
8254
+ headers.Authorization = `Bearer ${signature}`;
8255
+ headers["X-eigenx-expiry"] = expiry.toString();
8256
+ headers["X-Account"] = this.address;
8257
+ }
7846
8258
  const res = await requestWithRetry({
7847
8259
  url: `${this.baseUrl}${path8}`,
7848
8260
  method: "GET",
7849
8261
  headers,
7850
8262
  timeout: 6e4,
7851
- responseType: "text"
8263
+ responseType: "text",
8264
+ validateStatus: () => true,
8265
+ withCredentials: this.useSession
7852
8266
  });
7853
8267
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7854
8268
  return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
@@ -8415,6 +8829,9 @@ function isSiweMessageNotYetValid(params) {
8415
8829
  return /* @__PURE__ */ new Date() < params.notBefore;
8416
8830
  }
8417
8831
 
8832
+ // src/client/common/auth/index.ts
8833
+ init_session();
8834
+
8418
8835
  // src/client/common/utils/instance.ts
8419
8836
  async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
8420
8837
  try {