@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.js CHANGED
@@ -1,3 +1,137 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
6
+ // src/client/common/auth/session.ts
7
+ function stripHexPrefix2(hex) {
8
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
9
+ }
10
+ async function parseErrorResponse(response) {
11
+ try {
12
+ const data = await response.json();
13
+ return data.error || response.statusText;
14
+ } catch {
15
+ return response.statusText;
16
+ }
17
+ }
18
+ async function loginToComputeApi(config, request) {
19
+ let response;
20
+ try {
21
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
22
+ method: "POST",
23
+ credentials: "include",
24
+ // Include cookies for session management
25
+ headers: {
26
+ "Content-Type": "application/json"
27
+ },
28
+ body: JSON.stringify({
29
+ message: request.message,
30
+ signature: stripHexPrefix2(request.signature)
31
+ })
32
+ });
33
+ } catch (error) {
34
+ throw new SessionError(
35
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
36
+ "NETWORK_ERROR"
37
+ );
38
+ }
39
+ if (!response.ok) {
40
+ const errorMessage = await parseErrorResponse(response);
41
+ const status = response.status;
42
+ if (status === 400) {
43
+ if (errorMessage.toLowerCase().includes("siwe")) {
44
+ throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
45
+ }
46
+ throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
47
+ }
48
+ if (status === 401) {
49
+ throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
50
+ }
51
+ throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
52
+ }
53
+ const data = await response.json();
54
+ return {
55
+ success: data.success,
56
+ address: data.address
57
+ };
58
+ }
59
+ async function getComputeApiSession(config) {
60
+ let response;
61
+ try {
62
+ response = await fetch(`${config.baseUrl}/auth/session`, {
63
+ method: "GET",
64
+ credentials: "include",
65
+ // Include cookies for session management
66
+ headers: {
67
+ "Content-Type": "application/json"
68
+ }
69
+ });
70
+ } catch {
71
+ return {
72
+ authenticated: false
73
+ };
74
+ }
75
+ if (response.status === 401) {
76
+ return {
77
+ authenticated: false
78
+ };
79
+ }
80
+ if (!response.ok) {
81
+ const errorMessage = await parseErrorResponse(response);
82
+ throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
83
+ }
84
+ const data = await response.json();
85
+ return {
86
+ authenticated: data.authenticated,
87
+ address: data.address,
88
+ chainId: data.chain_id
89
+ };
90
+ }
91
+ async function logoutFromComputeApi(config) {
92
+ let response;
93
+ try {
94
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
95
+ method: "POST",
96
+ credentials: "include",
97
+ // Include cookies for session management
98
+ headers: {
99
+ "Content-Type": "application/json"
100
+ }
101
+ });
102
+ } catch (error) {
103
+ throw new SessionError(
104
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
105
+ "NETWORK_ERROR"
106
+ );
107
+ }
108
+ if (response.status === 401) {
109
+ return;
110
+ }
111
+ if (!response.ok) {
112
+ const errorMessage = await parseErrorResponse(response);
113
+ throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
114
+ }
115
+ }
116
+ async function isSessionValid(config) {
117
+ const session = await getComputeApiSession(config);
118
+ return session.authenticated;
119
+ }
120
+ var SessionError;
121
+ var init_session = __esm({
122
+ "src/client/common/auth/session.ts"() {
123
+ "use strict";
124
+ SessionError = class extends Error {
125
+ constructor(message, code, statusCode) {
126
+ super(message);
127
+ this.code = code;
128
+ this.statusCode = statusCode;
129
+ this.name = "SessionError";
130
+ }
131
+ };
132
+ }
133
+ });
134
+
1
135
  // src/client/modules/compute/app/index.ts
2
136
  import { parseAbi as parseAbi2, encodeFunctionData as encodeFunctionData3 } from "viem";
3
137
 
@@ -2167,7 +2301,7 @@ function encodeExecuteBatchData(executions) {
2167
2301
  });
2168
2302
  }
2169
2303
  async function estimateBatchGas(options) {
2170
- const { publicClient, account, executions } = options;
2304
+ const { publicClient, account, executions, authorizationList } = options;
2171
2305
  const executeBatchData = encodeExecuteBatchData(executions);
2172
2306
  const [gasTipCap, block, estimatedGas] = await Promise.all([
2173
2307
  publicClient.estimateMaxPriorityFeePerGas(),
@@ -2175,7 +2309,8 @@ async function estimateBatchGas(options) {
2175
2309
  publicClient.estimateGas({
2176
2310
  account,
2177
2311
  to: account,
2178
- data: executeBatchData
2312
+ data: executeBatchData,
2313
+ authorizationList
2179
2314
  })
2180
2315
  ]);
2181
2316
  const baseFee = block.baseFeePerGas ?? 0n;
@@ -2198,8 +2333,44 @@ async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
2198
2333
  const expectedCode = `0xef0100${delegatorAddress.slice(2)}`;
2199
2334
  return code.toLowerCase() === expectedCode.toLowerCase();
2200
2335
  }
2336
+ async function createAuthorizationList(options) {
2337
+ const { walletClient, publicClient, environmentConfig } = options;
2338
+ const account = walletClient.account;
2339
+ if (!account) {
2340
+ throw new Error("Wallet client must have an account");
2341
+ }
2342
+ const isDelegated2 = await checkERC7702Delegation(
2343
+ publicClient,
2344
+ account.address,
2345
+ environmentConfig.erc7702DelegatorAddress
2346
+ );
2347
+ if (isDelegated2) {
2348
+ return void 0;
2349
+ }
2350
+ const transactionNonce = await publicClient.getTransactionCount({
2351
+ address: account.address,
2352
+ blockTag: "pending"
2353
+ });
2354
+ const chainId = await publicClient.getChainId();
2355
+ const authorizationNonce = transactionNonce + 1;
2356
+ const signedAuthorization = await walletClient.signAuthorization({
2357
+ account,
2358
+ contractAddress: environmentConfig.erc7702DelegatorAddress,
2359
+ chainId,
2360
+ nonce: Number(authorizationNonce)
2361
+ });
2362
+ return [signedAuthorization];
2363
+ }
2201
2364
  async function executeBatch(options, logger = noopLogger) {
2202
- const { walletClient, publicClient, environmentConfig, executions, pendingMessage, gas } = options;
2365
+ const {
2366
+ walletClient,
2367
+ publicClient,
2368
+ environmentConfig,
2369
+ executions,
2370
+ pendingMessage,
2371
+ gas,
2372
+ authorizationList: providedAuthList
2373
+ } = options;
2203
2374
  const account = walletClient.account;
2204
2375
  if (!account) {
2205
2376
  throw new Error("Wallet client must have an account");
@@ -2209,27 +2380,29 @@ async function executeBatch(options, logger = noopLogger) {
2209
2380
  throw new Error("Wallet client must have a chain");
2210
2381
  }
2211
2382
  const executeBatchData = encodeExecuteBatchData(executions);
2212
- const isDelegated2 = await checkERC7702Delegation(
2213
- publicClient,
2214
- account.address,
2215
- environmentConfig.erc7702DelegatorAddress
2216
- );
2217
- let authorizationList = [];
2218
- if (!isDelegated2) {
2219
- const transactionNonce = await publicClient.getTransactionCount({
2220
- address: account.address,
2221
- blockTag: "pending"
2222
- });
2223
- const chainId = await publicClient.getChainId();
2224
- const authorizationNonce = transactionNonce + 1;
2225
- logger.debug("Using wallet client signing for EIP-7702 authorization");
2226
- const signedAuthorization = await walletClient.signAuthorization({
2227
- account: account.address,
2228
- contractAddress: environmentConfig.erc7702DelegatorAddress,
2229
- chainId,
2230
- nonce: Number(authorizationNonce)
2231
- });
2232
- authorizationList = [signedAuthorization];
2383
+ let authorizationList = providedAuthList || [];
2384
+ if (authorizationList.length === 0) {
2385
+ const isDelegated2 = await checkERC7702Delegation(
2386
+ publicClient,
2387
+ account.address,
2388
+ environmentConfig.erc7702DelegatorAddress
2389
+ );
2390
+ if (!isDelegated2) {
2391
+ const transactionNonce = await publicClient.getTransactionCount({
2392
+ address: account.address,
2393
+ blockTag: "pending"
2394
+ });
2395
+ const chainId = await publicClient.getChainId();
2396
+ const authorizationNonce = transactionNonce + 1;
2397
+ logger.debug("Using wallet client signing for EIP-7702 authorization");
2398
+ const signedAuthorization = await walletClient.signAuthorization({
2399
+ account,
2400
+ contractAddress: environmentConfig.erc7702DelegatorAddress,
2401
+ chainId,
2402
+ nonce: Number(authorizationNonce)
2403
+ });
2404
+ authorizationList = [signedAuthorization];
2405
+ }
2233
2406
  }
2234
2407
  if (pendingMessage) {
2235
2408
  logger.info(pendingMessage);
@@ -2244,6 +2417,9 @@ async function executeBatch(options, logger = noopLogger) {
2244
2417
  if (authorizationList.length > 0) {
2245
2418
  txRequest.authorizationList = authorizationList;
2246
2419
  }
2420
+ if (gas?.gasLimit) {
2421
+ txRequest.gas = gas.gasLimit;
2422
+ }
2247
2423
  if (gas?.maxFeePerGas) {
2248
2424
  txRequest.maxFeePerGas = gas.maxFeePerGas;
2249
2425
  }
@@ -3992,7 +4168,8 @@ async function executeDeployBatch(data, context, gas, logger = noopLogger) {
3992
4168
  environmentConfig: context.environmentConfig,
3993
4169
  executions: data.executions,
3994
4170
  pendingMessage,
3995
- gas
4171
+ gas,
4172
+ authorizationList: data.authorizationList
3996
4173
  },
3997
4174
  logger
3998
4175
  );
@@ -4103,7 +4280,8 @@ async function executeUpgradeBatch(data, context, gas, logger = noopLogger) {
4103
4280
  environmentConfig: context.environmentConfig,
4104
4281
  executions: data.executions,
4105
4282
  pendingMessage,
4106
- gas
4283
+ gas,
4284
+ authorizationList: data.authorizationList
4107
4285
  },
4108
4286
  logger
4109
4287
  );
@@ -4413,166 +4591,44 @@ async function calculateBillingAuthSignature(options) {
4413
4591
  return { signature, expiry };
4414
4592
  }
4415
4593
 
4416
- // src/client/common/auth/session.ts
4417
- var SessionError = class extends Error {
4418
- constructor(message, code, statusCode) {
4419
- super(message);
4420
- this.code = code;
4421
- this.statusCode = statusCode;
4422
- this.name = "SessionError";
4423
- }
4424
- };
4425
- function stripHexPrefix2(hex) {
4426
- return hex.startsWith("0x") ? hex.slice(2) : hex;
4594
+ // src/client/common/utils/userapi.ts
4595
+ init_session();
4596
+ function isJsonObject(value) {
4597
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4427
4598
  }
4428
- async function parseErrorResponse(response) {
4429
- try {
4430
- const data = await response.json();
4431
- return data.error || response.statusText;
4432
- } catch {
4433
- return response.statusText;
4434
- }
4599
+ function readString(obj, key) {
4600
+ const v = obj[key];
4601
+ return typeof v === "string" ? v : void 0;
4435
4602
  }
4436
- async function loginToComputeApi(config, request) {
4437
- let response;
4438
- try {
4439
- response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
4440
- method: "POST",
4441
- credentials: "include",
4442
- // Include cookies for session management
4443
- headers: {
4444
- "Content-Type": "application/json"
4445
- },
4446
- body: JSON.stringify({
4447
- message: request.message,
4448
- signature: stripHexPrefix2(request.signature)
4449
- })
4450
- });
4451
- } catch (error) {
4452
- throw new SessionError(
4453
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
4454
- "NETWORK_ERROR"
4455
- );
4603
+ function readNumber(obj, key) {
4604
+ const v = obj[key];
4605
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4606
+ }
4607
+ var MAX_ADDRESS_COUNT = 5;
4608
+ var CanViewAppLogsPermission = "0x2fd3f2fe";
4609
+ var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4610
+ var CanUpdateAppProfilePermission = "0x036fef61";
4611
+ function getDefaultClientId() {
4612
+ const version = true ? "0.3.0-dev.0" : "0.0.0";
4613
+ return `ecloud-sdk/v${version}`;
4614
+ }
4615
+ var UserApiClient = class {
4616
+ constructor(config, walletClient, publicClient, options) {
4617
+ this.config = config;
4618
+ this.walletClient = walletClient;
4619
+ this.publicClient = publicClient;
4620
+ this.clientId = options?.clientId || getDefaultClientId();
4621
+ this.useSession = options?.useSession ?? false;
4456
4622
  }
4457
- if (!response.ok) {
4458
- const errorMessage = await parseErrorResponse(response);
4459
- const status = response.status;
4460
- if (status === 400) {
4461
- if (errorMessage.toLowerCase().includes("siwe")) {
4462
- throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
4463
- }
4464
- throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
4465
- }
4466
- if (status === 401) {
4467
- throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
4623
+ /**
4624
+ * Get the address of the connected wallet
4625
+ */
4626
+ get address() {
4627
+ const account = this.walletClient.account;
4628
+ if (!account) {
4629
+ throw new Error("WalletClient must have an account attached");
4468
4630
  }
4469
- throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
4470
- }
4471
- const data = await response.json();
4472
- return {
4473
- success: data.success,
4474
- address: data.address
4475
- };
4476
- }
4477
- async function getComputeApiSession(config) {
4478
- let response;
4479
- try {
4480
- response = await fetch(`${config.baseUrl}/auth/session`, {
4481
- method: "GET",
4482
- credentials: "include",
4483
- // Include cookies for session management
4484
- headers: {
4485
- "Content-Type": "application/json"
4486
- }
4487
- });
4488
- } catch {
4489
- return {
4490
- authenticated: false
4491
- };
4492
- }
4493
- if (response.status === 401) {
4494
- return {
4495
- authenticated: false
4496
- };
4497
- }
4498
- if (!response.ok) {
4499
- const errorMessage = await parseErrorResponse(response);
4500
- throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
4501
- }
4502
- const data = await response.json();
4503
- return {
4504
- authenticated: data.authenticated,
4505
- address: data.address,
4506
- chainId: data.chain_id
4507
- };
4508
- }
4509
- async function logoutFromComputeApi(config) {
4510
- let response;
4511
- try {
4512
- response = await fetch(`${config.baseUrl}/auth/logout`, {
4513
- method: "POST",
4514
- credentials: "include",
4515
- // Include cookies for session management
4516
- headers: {
4517
- "Content-Type": "application/json"
4518
- }
4519
- });
4520
- } catch (error) {
4521
- throw new SessionError(
4522
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
4523
- "NETWORK_ERROR"
4524
- );
4525
- }
4526
- if (response.status === 401) {
4527
- return;
4528
- }
4529
- if (!response.ok) {
4530
- const errorMessage = await parseErrorResponse(response);
4531
- throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
4532
- }
4533
- }
4534
- async function isSessionValid(config) {
4535
- const session = await getComputeApiSession(config);
4536
- return session.authenticated;
4537
- }
4538
-
4539
- // src/client/common/utils/userapi.ts
4540
- function isJsonObject(value) {
4541
- return typeof value === "object" && value !== null && !Array.isArray(value);
4542
- }
4543
- function readString(obj, key) {
4544
- const v = obj[key];
4545
- return typeof v === "string" ? v : void 0;
4546
- }
4547
- function readNumber(obj, key) {
4548
- const v = obj[key];
4549
- return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4550
- }
4551
- var MAX_ADDRESS_COUNT = 5;
4552
- var CanViewAppLogsPermission = "0x2fd3f2fe";
4553
- var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4554
- var CanUpdateAppProfilePermission = "0x036fef61";
4555
- function getDefaultClientId() {
4556
- const version = true ? "0.2.2-dev" : "0.0.0";
4557
- return `ecloud-sdk/v${version}`;
4558
- }
4559
- var UserApiClient = class {
4560
- constructor(config, walletClient, publicClient, options) {
4561
- this.config = config;
4562
- this.walletClient = walletClient;
4563
- this.publicClient = publicClient;
4564
- this.clientId = options?.clientId || getDefaultClientId();
4565
- this.useSession = options?.useSession ?? false;
4566
- }
4567
- /**
4568
- * Get the address of the connected wallet
4569
- */
4570
- get address() {
4571
- const account = this.walletClient.account;
4572
- if (!account) {
4573
- throw new Error("WalletClient must have an account attached");
4574
- }
4575
- return account.address;
4631
+ return account.address;
4576
4632
  }
4577
4633
  async getInfos(appIDs, addressCount = 1) {
4578
4634
  const count = Math.min(addressCount, MAX_ADDRESS_COUNT);
@@ -5461,21 +5517,214 @@ function isSubscriptionActive(status) {
5461
5517
 
5462
5518
  // src/client/common/utils/billingapi.ts
5463
5519
  import axios2 from "axios";
5520
+
5521
+ // src/client/common/auth/billingSession.ts
5522
+ var BillingSessionError = class extends Error {
5523
+ constructor(message, code, statusCode) {
5524
+ super(message);
5525
+ this.code = code;
5526
+ this.statusCode = statusCode;
5527
+ this.name = "BillingSessionError";
5528
+ }
5529
+ };
5530
+ function stripHexPrefix3(hex) {
5531
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
5532
+ }
5533
+ async function parseErrorResponse2(response) {
5534
+ try {
5535
+ const data = await response.json();
5536
+ return data.error || response.statusText;
5537
+ } catch {
5538
+ return response.statusText;
5539
+ }
5540
+ }
5541
+ async function loginToBillingApi(config, request) {
5542
+ let response;
5543
+ try {
5544
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
5545
+ method: "POST",
5546
+ credentials: "include",
5547
+ // Include cookies for session management
5548
+ headers: {
5549
+ "Content-Type": "application/json"
5550
+ },
5551
+ body: JSON.stringify({
5552
+ message: request.message,
5553
+ signature: stripHexPrefix3(request.signature)
5554
+ })
5555
+ });
5556
+ } catch (error) {
5557
+ throw new BillingSessionError(
5558
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5559
+ "NETWORK_ERROR"
5560
+ );
5561
+ }
5562
+ if (!response.ok) {
5563
+ const errorMessage = await parseErrorResponse2(response);
5564
+ const status = response.status;
5565
+ if (status === 400) {
5566
+ if (errorMessage.toLowerCase().includes("siwe")) {
5567
+ throw new BillingSessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
5568
+ }
5569
+ throw new BillingSessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
5570
+ }
5571
+ if (status === 401) {
5572
+ throw new BillingSessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
5573
+ }
5574
+ throw new BillingSessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
5575
+ }
5576
+ const data = await response.json();
5577
+ return {
5578
+ success: data.success,
5579
+ address: data.address
5580
+ };
5581
+ }
5582
+ async function getBillingApiSession(config) {
5583
+ let response;
5584
+ try {
5585
+ response = await fetch(`${config.baseUrl}/auth/session`, {
5586
+ method: "GET",
5587
+ credentials: "include",
5588
+ // Include cookies for session management
5589
+ headers: {
5590
+ "Content-Type": "application/json"
5591
+ }
5592
+ });
5593
+ } catch {
5594
+ return {
5595
+ authenticated: false
5596
+ };
5597
+ }
5598
+ if (response.status === 401) {
5599
+ return {
5600
+ authenticated: false
5601
+ };
5602
+ }
5603
+ if (!response.ok) {
5604
+ const errorMessage = await parseErrorResponse2(response);
5605
+ throw new BillingSessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
5606
+ }
5607
+ const data = await response.json();
5608
+ return {
5609
+ authenticated: data.authenticated,
5610
+ address: data.address,
5611
+ chainId: data.chainId,
5612
+ authenticatedAt: data.authenticatedAt
5613
+ };
5614
+ }
5615
+ async function logoutFromBillingApi(config) {
5616
+ let response;
5617
+ try {
5618
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
5619
+ method: "POST",
5620
+ credentials: "include",
5621
+ // Include cookies for session management
5622
+ headers: {
5623
+ "Content-Type": "application/json"
5624
+ }
5625
+ });
5626
+ } catch (error) {
5627
+ throw new BillingSessionError(
5628
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5629
+ "NETWORK_ERROR"
5630
+ );
5631
+ }
5632
+ if (response.status === 401) {
5633
+ return;
5634
+ }
5635
+ if (!response.ok) {
5636
+ const errorMessage = await parseErrorResponse2(response);
5637
+ throw new BillingSessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
5638
+ }
5639
+ }
5640
+
5641
+ // src/client/common/utils/billingapi.ts
5464
5642
  var BillingApiClient = class {
5465
- constructor(config, walletClient) {
5643
+ constructor(config, walletClient, options = {}) {
5466
5644
  this.config = config;
5467
5645
  this.walletClient = walletClient;
5646
+ this.options = options;
5647
+ this.useSession = options.useSession ?? false;
5648
+ if (!this.useSession && !walletClient) {
5649
+ throw new Error("WalletClient is required when not using session authentication");
5650
+ }
5468
5651
  }
5469
5652
  /**
5470
5653
  * Get the address of the connected wallet
5654
+ * Returns undefined if using session auth without a wallet client
5471
5655
  */
5472
5656
  get address() {
5473
- const account = this.walletClient.account;
5657
+ const account = this.walletClient?.account;
5474
5658
  if (!account) {
5475
- throw new Error("WalletClient must have an account attached");
5659
+ if (!this.useSession) {
5660
+ throw new Error("WalletClient must have an account attached");
5661
+ }
5662
+ return void 0;
5476
5663
  }
5477
5664
  return account.address;
5478
5665
  }
5666
+ /**
5667
+ * Get the base URL of the billing API
5668
+ */
5669
+ get baseUrl() {
5670
+ return this.config.billingApiServerURL;
5671
+ }
5672
+ // ==========================================================================
5673
+ // SIWE Session Methods
5674
+ // ==========================================================================
5675
+ /**
5676
+ * Login to the billing API using SIWE
5677
+ *
5678
+ * This establishes a session with the billing API by verifying the SIWE message
5679
+ * and signature. On success, a session cookie is set in the browser.
5680
+ *
5681
+ * @param request - Login request containing SIWE message and signature
5682
+ * @returns Login result with the authenticated address
5683
+ *
5684
+ * @example
5685
+ * ```typescript
5686
+ * const { message } = createSiweMessage({
5687
+ * address: userAddress,
5688
+ * chainId: 11155111,
5689
+ * domain: window.location.host,
5690
+ * uri: window.location.origin,
5691
+ * });
5692
+ *
5693
+ * const signature = await signMessageAsync({ message });
5694
+ * const result = await billingClient.siweLogin({ message, signature });
5695
+ * ```
5696
+ */
5697
+ async siweLogin(request) {
5698
+ return loginToBillingApi({ baseUrl: this.baseUrl }, request);
5699
+ }
5700
+ /**
5701
+ * Logout from the billing API
5702
+ *
5703
+ * This destroys the current session and clears the session cookie.
5704
+ */
5705
+ async siweLogout() {
5706
+ return logoutFromBillingApi({ baseUrl: this.baseUrl });
5707
+ }
5708
+ /**
5709
+ * Get the current session status from the billing API
5710
+ *
5711
+ * @returns Session information including authentication status and address
5712
+ */
5713
+ async getSession() {
5714
+ return getBillingApiSession({ baseUrl: this.baseUrl });
5715
+ }
5716
+ /**
5717
+ * Check if there is a valid session
5718
+ *
5719
+ * @returns True if session is authenticated, false otherwise
5720
+ */
5721
+ async isSessionValid() {
5722
+ const session = await this.getSession();
5723
+ return session.authenticated;
5724
+ }
5725
+ // ==========================================================================
5726
+ // Subscription Methods
5727
+ // ==========================================================================
5479
5728
  async createSubscription(productId = "compute", options) {
5480
5729
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5481
5730
  const body = options ? {
@@ -5494,10 +5743,72 @@ var BillingApiClient = class {
5494
5743
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5495
5744
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
5496
5745
  }
5746
+ // ==========================================================================
5747
+ // Internal Methods
5748
+ // ==========================================================================
5497
5749
  /**
5498
5750
  * Make an authenticated request to the billing API
5751
+ *
5752
+ * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
5499
5753
  */
5500
5754
  async makeAuthenticatedRequest(url, method, productId, body) {
5755
+ if (this.useSession) {
5756
+ return this.makeSessionAuthenticatedRequest(url, method, body);
5757
+ }
5758
+ return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
5759
+ }
5760
+ /**
5761
+ * Make a request using session-based authentication (cookies)
5762
+ */
5763
+ async makeSessionAuthenticatedRequest(url, method, body) {
5764
+ const headers = {};
5765
+ if (body) {
5766
+ headers["Content-Type"] = "application/json";
5767
+ }
5768
+ try {
5769
+ const response = await fetch(url, {
5770
+ method,
5771
+ credentials: "include",
5772
+ // Include cookies for session management
5773
+ headers,
5774
+ body: body ? JSON.stringify(body) : void 0
5775
+ });
5776
+ const status = response.status;
5777
+ const statusText = status >= 200 && status < 300 ? "OK" : "Error";
5778
+ if (status < 200 || status >= 300) {
5779
+ let errorBody;
5780
+ try {
5781
+ errorBody = await response.text();
5782
+ } catch {
5783
+ errorBody = statusText;
5784
+ }
5785
+ throw new Error(`BillingAPI request failed: ${status} ${statusText} - ${errorBody}`);
5786
+ }
5787
+ const responseData = await response.json();
5788
+ return {
5789
+ json: async () => responseData,
5790
+ text: async () => JSON.stringify(responseData)
5791
+ };
5792
+ } catch (error) {
5793
+ if (error.name === "TypeError" || error.message?.includes("fetch")) {
5794
+ throw new Error(
5795
+ `Failed to connect to BillingAPI at ${url}: ${error.message}
5796
+ Please check:
5797
+ 1. Your internet connection
5798
+ 2. The API server is accessible: ${this.config.billingApiServerURL}
5799
+ 3. Firewall/proxy settings`
5800
+ );
5801
+ }
5802
+ throw error;
5803
+ }
5804
+ }
5805
+ /**
5806
+ * Make a request using EIP-712 signature authentication
5807
+ */
5808
+ async makeSignatureAuthenticatedRequest(url, method, productId, body) {
5809
+ if (!this.walletClient) {
5810
+ throw new Error("WalletClient is required for signature authentication");
5811
+ }
5501
5812
  const expiry = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
5502
5813
  const { signature } = await calculateBillingAuthSignature({
5503
5814
  walletClient: this.walletClient,
@@ -5817,16 +6128,24 @@ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger)
5817
6128
  },
5818
6129
  logger
5819
6130
  );
6131
+ logger.debug("Checking delegation status...");
6132
+ const authorizationList = await createAuthorizationList({
6133
+ walletClient: batch.walletClient,
6134
+ publicClient: batch.publicClient,
6135
+ environmentConfig: batch.environmentConfig
6136
+ });
5820
6137
  logger.debug("Estimating gas...");
5821
6138
  const gasEstimate = await estimateBatchGas({
5822
6139
  publicClient: batch.publicClient,
5823
6140
  account: batch.walletClient.account.address,
5824
- executions: batch.executions
6141
+ executions: batch.executions,
6142
+ authorizationList
5825
6143
  });
5826
6144
  const data = {
5827
6145
  appId: batch.appId,
5828
6146
  salt: batch.salt,
5829
- executions: batch.executions
6147
+ executions: batch.executions,
6148
+ authorizationList
5830
6149
  };
5831
6150
  return {
5832
6151
  prepared: {
@@ -6055,16 +6374,24 @@ async function prepareDeploy(options, logger = defaultLogger) {
6055
6374
  },
6056
6375
  logger
6057
6376
  );
6377
+ logger.debug("Checking delegation status...");
6378
+ const authorizationList = await createAuthorizationList({
6379
+ walletClient: batch.walletClient,
6380
+ publicClient: batch.publicClient,
6381
+ environmentConfig: batch.environmentConfig
6382
+ });
6058
6383
  logger.debug("Estimating gas...");
6059
6384
  const gasEstimate = await estimateBatchGas({
6060
6385
  publicClient: batch.publicClient,
6061
6386
  account: batch.walletClient.account.address,
6062
- executions: batch.executions
6387
+ executions: batch.executions,
6388
+ authorizationList
6063
6389
  });
6064
6390
  const data = {
6065
6391
  appId: batch.appId,
6066
6392
  salt: batch.salt,
6067
- executions: batch.executions
6393
+ executions: batch.executions,
6394
+ authorizationList
6068
6395
  };
6069
6396
  return {
6070
6397
  prepared: {
@@ -6195,15 +6522,23 @@ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger
6195
6522
  needsPermissionChange,
6196
6523
  imageRef: options.imageRef
6197
6524
  });
6525
+ logger.debug("Checking delegation status...");
6526
+ const authorizationList = await createAuthorizationList({
6527
+ walletClient: batch.walletClient,
6528
+ publicClient: batch.publicClient,
6529
+ environmentConfig: batch.environmentConfig
6530
+ });
6198
6531
  logger.debug("Estimating gas...");
6199
6532
  const gasEstimate = await estimateBatchGas({
6200
6533
  publicClient: batch.publicClient,
6201
6534
  account: batch.walletClient.account.address,
6202
- executions: batch.executions
6535
+ executions: batch.executions,
6536
+ authorizationList
6203
6537
  });
6204
6538
  const data = {
6205
6539
  appId: batch.appId,
6206
- executions: batch.executions
6540
+ executions: batch.executions,
6541
+ authorizationList
6207
6542
  };
6208
6543
  return {
6209
6544
  prepared: {
@@ -6376,15 +6711,23 @@ async function prepareUpgrade(options, logger = defaultLogger) {
6376
6711
  needsPermissionChange,
6377
6712
  imageRef: finalImageRef
6378
6713
  });
6714
+ logger.debug("Checking delegation status...");
6715
+ const authorizationList = await createAuthorizationList({
6716
+ walletClient: batch.walletClient,
6717
+ publicClient: batch.publicClient,
6718
+ environmentConfig: batch.environmentConfig
6719
+ });
6379
6720
  logger.debug("Estimating gas...");
6380
6721
  const gasEstimate = await estimateBatchGas({
6381
6722
  publicClient: batch.publicClient,
6382
6723
  account: batch.walletClient.account.address,
6383
- executions: batch.executions
6724
+ executions: batch.executions,
6725
+ authorizationList
6384
6726
  });
6385
6727
  const data = {
6386
6728
  appId: batch.appId,
6387
- executions: batch.executions
6729
+ executions: batch.executions,
6730
+ authorizationList
6388
6731
  };
6389
6732
  return {
6390
6733
  prepared: {
@@ -7512,7 +7855,10 @@ function createBillingModule(config) {
7512
7855
  };
7513
7856
  }
7514
7857
  logger.debug(`Creating subscription for ${productId}...`);
7515
- const result = await billingApi.createSubscription(productId);
7858
+ const result = await billingApi.createSubscription(productId, {
7859
+ successUrl: opts?.successUrl,
7860
+ cancelUrl: opts?.cancelUrl
7861
+ });
7516
7862
  logger.debug(`Checkout URL: ${result.checkoutUrl}`);
7517
7863
  return {
7518
7864
  type: "checkout_created",
@@ -7604,9 +7950,22 @@ async function requestWithRetry(config) {
7604
7950
  }
7605
7951
  var BuildApiClient = class {
7606
7952
  constructor(options) {
7607
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
7953
+ let url = options.baseUrl;
7954
+ while (url.endsWith("/")) {
7955
+ url = url.slice(0, -1);
7956
+ }
7957
+ this.baseUrl = url;
7608
7958
  this.clientId = options.clientId;
7609
7959
  this.walletClient = options.walletClient;
7960
+ this.useSession = options.useSession ?? false;
7961
+ this.billingSessionId = options.billingSessionId;
7962
+ }
7963
+ /**
7964
+ * Update the billing session ID.
7965
+ * Call this after logging into the billing API to enable session-based auth for builds.
7966
+ */
7967
+ setBillingSessionId(sessionId) {
7968
+ this.billingSessionId = sessionId;
7610
7969
  }
7611
7970
  /**
7612
7971
  * Get the address of the connected wallet
@@ -7618,8 +7977,17 @@ var BuildApiClient = class {
7618
7977
  }
7619
7978
  return account.address;
7620
7979
  }
7980
+ /**
7981
+ * Submit a new build request.
7982
+ * Supports two auth modes (session auth is tried first when billingSessionId is available):
7983
+ * 1. Session-based auth: X-Billing-Session header (forwarded billing_session cookie)
7984
+ * 2. Signature-based auth: Authorization + X-Account + X-eigenx-expiry headers (requires walletClient)
7985
+ */
7621
7986
  async submitBuild(payload) {
7622
- return this.authenticatedJsonRequest("/builds", "POST", payload);
7987
+ if (this.useSession && this.billingSessionId) {
7988
+ return this.billingSessionAuthJsonRequest("/builds", "POST", payload);
7989
+ }
7990
+ return this.signatureAuthJsonRequest("/builds", "POST", payload);
7623
7991
  }
7624
7992
  async getBuild(buildId) {
7625
7993
  return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
@@ -7630,8 +7998,11 @@ var BuildApiClient = class {
7630
7998
  async verify(identifier) {
7631
7999
  return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
7632
8000
  }
8001
+ /**
8002
+ * Get build logs. Supports session auth (identity verification only, no billing check).
8003
+ */
7633
8004
  async getLogs(buildId) {
7634
- return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
8005
+ return this.sessionOrSignatureTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
7635
8006
  }
7636
8007
  async listBuilds(params) {
7637
8008
  const res = await requestWithRetry({
@@ -7639,7 +8010,9 @@ var BuildApiClient = class {
7639
8010
  method: "GET",
7640
8011
  params,
7641
8012
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7642
- timeout: 6e4
8013
+ timeout: 6e4,
8014
+ validateStatus: () => true,
8015
+ withCredentials: this.useSession
7643
8016
  });
7644
8017
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7645
8018
  return res.data;
@@ -7649,12 +8022,18 @@ var BuildApiClient = class {
7649
8022
  url: `${this.baseUrl}${path8}`,
7650
8023
  method: "GET",
7651
8024
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7652
- timeout: 6e4
8025
+ timeout: 6e4,
8026
+ validateStatus: () => true,
8027
+ withCredentials: this.useSession
7653
8028
  });
7654
8029
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7655
8030
  return res.data;
7656
8031
  }
7657
- async authenticatedJsonRequest(path8, method, body) {
8032
+ /**
8033
+ * Make a request that ALWAYS requires signature auth (for billing verification).
8034
+ * Used for endpoints like POST /builds that need to verify subscription status.
8035
+ */
8036
+ async signatureAuthJsonRequest(path8, method, body) {
7658
8037
  if (!this.walletClient?.account) {
7659
8038
  throw new Error("WalletClient with account required for authenticated requests");
7660
8039
  }
@@ -7676,32 +8055,69 @@ var BuildApiClient = class {
7676
8055
  method,
7677
8056
  headers,
7678
8057
  data: body,
7679
- timeout: 6e4
8058
+ timeout: 6e4,
8059
+ validateStatus: () => true,
8060
+ withCredentials: this.useSession
7680
8061
  });
7681
8062
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7682
8063
  return res.data;
7683
8064
  }
7684
- async authenticatedTextRequest(path8) {
7685
- if (!this.walletClient?.account) {
7686
- throw new Error("WalletClient with account required for authenticated requests");
8065
+ /**
8066
+ * Make a request using billing session auth (for billing verification without wallet signature).
8067
+ * Forwards the billing_session cookie value via X-Billing-Session header.
8068
+ * Used for endpoints that need to verify subscription status when using session-based auth.
8069
+ */
8070
+ async billingSessionAuthJsonRequest(path8, method, body) {
8071
+ if (!this.billingSessionId) {
8072
+ throw new Error("billingSessionId required for session-based billing auth");
7687
8073
  }
7688
- const headers = {};
8074
+ const headers = {
8075
+ "Content-Type": "application/json",
8076
+ "X-Billing-Session": this.billingSessionId
8077
+ };
7689
8078
  if (this.clientId) headers["x-client-id"] = this.clientId;
7690
- const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
7691
- const { signature } = await calculateBillingAuthSignature({
7692
- walletClient: this.walletClient,
7693
- product: "compute",
7694
- expiry
8079
+ const res = await requestWithRetry({
8080
+ url: `${this.baseUrl}${path8}`,
8081
+ method,
8082
+ headers,
8083
+ data: body,
8084
+ timeout: 6e4,
8085
+ validateStatus: () => true,
8086
+ withCredentials: this.useSession
7695
8087
  });
7696
- headers.Authorization = `Bearer ${signature}`;
7697
- headers["X-eigenx-expiry"] = expiry.toString();
7698
- headers["X-Account"] = this.address;
8088
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
8089
+ return res.data;
8090
+ }
8091
+ /**
8092
+ * Make an authenticated request that can use session OR signature auth.
8093
+ * When useSession is true, relies on cookies for identity verification.
8094
+ * Used for endpoints that only need identity verification (not billing).
8095
+ */
8096
+ async sessionOrSignatureTextRequest(path8) {
8097
+ const headers = {};
8098
+ if (this.clientId) headers["x-client-id"] = this.clientId;
8099
+ if (!this.useSession) {
8100
+ if (!this.walletClient?.account) {
8101
+ throw new Error("WalletClient with account required for authenticated requests");
8102
+ }
8103
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
8104
+ const { signature } = await calculateBillingAuthSignature({
8105
+ walletClient: this.walletClient,
8106
+ product: "compute",
8107
+ expiry
8108
+ });
8109
+ headers.Authorization = `Bearer ${signature}`;
8110
+ headers["X-eigenx-expiry"] = expiry.toString();
8111
+ headers["X-Account"] = this.address;
8112
+ }
7699
8113
  const res = await requestWithRetry({
7700
8114
  url: `${this.baseUrl}${path8}`,
7701
8115
  method: "GET",
7702
8116
  headers,
7703
8117
  timeout: 6e4,
7704
- responseType: "text"
8118
+ responseType: "text",
8119
+ validateStatus: () => true,
8120
+ withCredentials: this.useSession
7705
8121
  });
7706
8122
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7707
8123
  return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
@@ -8268,6 +8684,9 @@ function isSiweMessageNotYetValid(params) {
8268
8684
  return /* @__PURE__ */ new Date() < params.notBefore;
8269
8685
  }
8270
8686
 
8687
+ // src/client/common/auth/index.ts
8688
+ init_session();
8689
+
8271
8690
  // src/client/common/utils/instance.ts
8272
8691
  async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
8273
8692
  try {