@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.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
  }
@@ -2285,26 +2461,27 @@ async function executeBatch(options, logger = noopLogger) {
2285
2461
  import { encodeFunctionData as encodeFunctionData2, decodeErrorResult as decodeErrorResult2, bytesToHex } from "viem";
2286
2462
 
2287
2463
  // src/client/common/utils/helpers.ts
2288
- import { extractChain, createPublicClient, createWalletClient, http } from "viem";
2464
+ import { extractChain, createPublicClient, createWalletClient, http, fallback } from "viem";
2289
2465
  import { sepolia as sepolia2 } from "viem/chains";
2290
2466
  import { privateKeyToAccount } from "viem/accounts";
2291
- function getChainFromID(chainID, fallback = sepolia2) {
2467
+ function getChainFromID(chainID, fallback2 = sepolia2) {
2292
2468
  const id = Number(chainID);
2293
- return extractChain({ chains: SUPPORTED_CHAINS, id }) || fallback;
2469
+ return extractChain({ chains: SUPPORTED_CHAINS, id }) || fallback2;
2294
2470
  }
2295
2471
  function createClients(options) {
2296
2472
  const { privateKey, rpcUrl, chainId } = options;
2297
2473
  const privateKeyHex = addHexPrefix(privateKey);
2298
2474
  const account = privateKeyToAccount(privateKeyHex);
2299
2475
  const chain = getChainFromID(chainId);
2476
+ const transport = typeof rpcUrl === "string" ? http(rpcUrl) : fallback(rpcUrl.map((url) => http(url)));
2300
2477
  const publicClient = createPublicClient({
2301
2478
  chain,
2302
- transport: http(rpcUrl)
2479
+ transport
2303
2480
  });
2304
2481
  const walletClient = createWalletClient({
2305
2482
  account,
2306
2483
  chain,
2307
- transport: http(rpcUrl)
2484
+ transport
2308
2485
  });
2309
2486
  return { walletClient, publicClient };
2310
2487
  }
@@ -3992,7 +4169,8 @@ async function executeDeployBatch(data, context, gas, logger = noopLogger) {
3992
4169
  environmentConfig: context.environmentConfig,
3993
4170
  executions: data.executions,
3994
4171
  pendingMessage,
3995
- gas
4172
+ gas,
4173
+ authorizationList: data.authorizationList
3996
4174
  },
3997
4175
  logger
3998
4176
  );
@@ -4103,7 +4281,8 @@ async function executeUpgradeBatch(data, context, gas, logger = noopLogger) {
4103
4281
  environmentConfig: context.environmentConfig,
4104
4282
  executions: data.executions,
4105
4283
  pendingMessage,
4106
- gas
4284
+ gas,
4285
+ authorizationList: data.authorizationList
4107
4286
  },
4108
4287
  logger
4109
4288
  );
@@ -4413,166 +4592,44 @@ async function calculateBillingAuthSignature(options) {
4413
4592
  return { signature, expiry };
4414
4593
  }
4415
4594
 
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;
4595
+ // src/client/common/utils/userapi.ts
4596
+ init_session();
4597
+ function isJsonObject(value) {
4598
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4427
4599
  }
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
- }
4600
+ function readString(obj, key) {
4601
+ const v = obj[key];
4602
+ return typeof v === "string" ? v : void 0;
4435
4603
  }
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
- );
4604
+ function readNumber(obj, key) {
4605
+ const v = obj[key];
4606
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
4607
+ }
4608
+ var MAX_ADDRESS_COUNT = 5;
4609
+ var CanViewAppLogsPermission = "0x2fd3f2fe";
4610
+ var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
4611
+ var CanUpdateAppProfilePermission = "0x036fef61";
4612
+ function getDefaultClientId() {
4613
+ const version = true ? "0.3.1-dev.0" : "0.0.0";
4614
+ return `ecloud-sdk/v${version}`;
4615
+ }
4616
+ var UserApiClient = class {
4617
+ constructor(config, walletClient, publicClient, options) {
4618
+ this.config = config;
4619
+ this.walletClient = walletClient;
4620
+ this.publicClient = publicClient;
4621
+ this.clientId = options?.clientId || getDefaultClientId();
4622
+ this.useSession = options?.useSession ?? false;
4456
4623
  }
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);
4624
+ /**
4625
+ * Get the address of the connected wallet
4626
+ */
4627
+ get address() {
4628
+ const account = this.walletClient.account;
4629
+ if (!account) {
4630
+ throw new Error("WalletClient must have an account attached");
4468
4631
  }
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.3.1-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;
4632
+ return account.address;
4576
4633
  }
4577
4634
  async getInfos(appIDs, addressCount = 1) {
4578
4635
  const count = Math.min(addressCount, MAX_ADDRESS_COUNT);
@@ -5461,21 +5518,214 @@ function isSubscriptionActive(status) {
5461
5518
 
5462
5519
  // src/client/common/utils/billingapi.ts
5463
5520
  import axios2 from "axios";
5521
+
5522
+ // src/client/common/auth/billingSession.ts
5523
+ var BillingSessionError = class extends Error {
5524
+ constructor(message, code, statusCode) {
5525
+ super(message);
5526
+ this.code = code;
5527
+ this.statusCode = statusCode;
5528
+ this.name = "BillingSessionError";
5529
+ }
5530
+ };
5531
+ function stripHexPrefix3(hex) {
5532
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
5533
+ }
5534
+ async function parseErrorResponse2(response) {
5535
+ try {
5536
+ const data = await response.json();
5537
+ return data.error || response.statusText;
5538
+ } catch {
5539
+ return response.statusText;
5540
+ }
5541
+ }
5542
+ async function loginToBillingApi(config, request) {
5543
+ let response;
5544
+ try {
5545
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
5546
+ method: "POST",
5547
+ credentials: "include",
5548
+ // Include cookies for session management
5549
+ headers: {
5550
+ "Content-Type": "application/json"
5551
+ },
5552
+ body: JSON.stringify({
5553
+ message: request.message,
5554
+ signature: stripHexPrefix3(request.signature)
5555
+ })
5556
+ });
5557
+ } catch (error) {
5558
+ throw new BillingSessionError(
5559
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5560
+ "NETWORK_ERROR"
5561
+ );
5562
+ }
5563
+ if (!response.ok) {
5564
+ const errorMessage = await parseErrorResponse2(response);
5565
+ const status = response.status;
5566
+ if (status === 400) {
5567
+ if (errorMessage.toLowerCase().includes("siwe")) {
5568
+ throw new BillingSessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
5569
+ }
5570
+ throw new BillingSessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
5571
+ }
5572
+ if (status === 401) {
5573
+ throw new BillingSessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
5574
+ }
5575
+ throw new BillingSessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
5576
+ }
5577
+ const data = await response.json();
5578
+ return {
5579
+ success: data.success,
5580
+ address: data.address
5581
+ };
5582
+ }
5583
+ async function getBillingApiSession(config) {
5584
+ let response;
5585
+ try {
5586
+ response = await fetch(`${config.baseUrl}/auth/session`, {
5587
+ method: "GET",
5588
+ credentials: "include",
5589
+ // Include cookies for session management
5590
+ headers: {
5591
+ "Content-Type": "application/json"
5592
+ }
5593
+ });
5594
+ } catch {
5595
+ return {
5596
+ authenticated: false
5597
+ };
5598
+ }
5599
+ if (response.status === 401) {
5600
+ return {
5601
+ authenticated: false
5602
+ };
5603
+ }
5604
+ if (!response.ok) {
5605
+ const errorMessage = await parseErrorResponse2(response);
5606
+ throw new BillingSessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
5607
+ }
5608
+ const data = await response.json();
5609
+ return {
5610
+ authenticated: data.authenticated,
5611
+ address: data.address,
5612
+ chainId: data.chainId,
5613
+ authenticatedAt: data.authenticatedAt
5614
+ };
5615
+ }
5616
+ async function logoutFromBillingApi(config) {
5617
+ let response;
5618
+ try {
5619
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
5620
+ method: "POST",
5621
+ credentials: "include",
5622
+ // Include cookies for session management
5623
+ headers: {
5624
+ "Content-Type": "application/json"
5625
+ }
5626
+ });
5627
+ } catch (error) {
5628
+ throw new BillingSessionError(
5629
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
5630
+ "NETWORK_ERROR"
5631
+ );
5632
+ }
5633
+ if (response.status === 401) {
5634
+ return;
5635
+ }
5636
+ if (!response.ok) {
5637
+ const errorMessage = await parseErrorResponse2(response);
5638
+ throw new BillingSessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
5639
+ }
5640
+ }
5641
+
5642
+ // src/client/common/utils/billingapi.ts
5464
5643
  var BillingApiClient = class {
5465
- constructor(config, walletClient) {
5644
+ constructor(config, walletClient, options = {}) {
5466
5645
  this.config = config;
5467
5646
  this.walletClient = walletClient;
5647
+ this.options = options;
5648
+ this.useSession = options.useSession ?? false;
5649
+ if (!this.useSession && !walletClient) {
5650
+ throw new Error("WalletClient is required when not using session authentication");
5651
+ }
5468
5652
  }
5469
5653
  /**
5470
5654
  * Get the address of the connected wallet
5655
+ * Returns undefined if using session auth without a wallet client
5471
5656
  */
5472
5657
  get address() {
5473
- const account = this.walletClient.account;
5658
+ const account = this.walletClient?.account;
5474
5659
  if (!account) {
5475
- throw new Error("WalletClient must have an account attached");
5660
+ if (!this.useSession) {
5661
+ throw new Error("WalletClient must have an account attached");
5662
+ }
5663
+ return void 0;
5476
5664
  }
5477
5665
  return account.address;
5478
5666
  }
5667
+ /**
5668
+ * Get the base URL of the billing API
5669
+ */
5670
+ get baseUrl() {
5671
+ return this.config.billingApiServerURL;
5672
+ }
5673
+ // ==========================================================================
5674
+ // SIWE Session Methods
5675
+ // ==========================================================================
5676
+ /**
5677
+ * Login to the billing API using SIWE
5678
+ *
5679
+ * This establishes a session with the billing API by verifying the SIWE message
5680
+ * and signature. On success, a session cookie is set in the browser.
5681
+ *
5682
+ * @param request - Login request containing SIWE message and signature
5683
+ * @returns Login result with the authenticated address
5684
+ *
5685
+ * @example
5686
+ * ```typescript
5687
+ * const { message } = createSiweMessage({
5688
+ * address: userAddress,
5689
+ * chainId: 11155111,
5690
+ * domain: window.location.host,
5691
+ * uri: window.location.origin,
5692
+ * });
5693
+ *
5694
+ * const signature = await signMessageAsync({ message });
5695
+ * const result = await billingClient.siweLogin({ message, signature });
5696
+ * ```
5697
+ */
5698
+ async siweLogin(request) {
5699
+ return loginToBillingApi({ baseUrl: this.baseUrl }, request);
5700
+ }
5701
+ /**
5702
+ * Logout from the billing API
5703
+ *
5704
+ * This destroys the current session and clears the session cookie.
5705
+ */
5706
+ async siweLogout() {
5707
+ return logoutFromBillingApi({ baseUrl: this.baseUrl });
5708
+ }
5709
+ /**
5710
+ * Get the current session status from the billing API
5711
+ *
5712
+ * @returns Session information including authentication status and address
5713
+ */
5714
+ async getSession() {
5715
+ return getBillingApiSession({ baseUrl: this.baseUrl });
5716
+ }
5717
+ /**
5718
+ * Check if there is a valid session
5719
+ *
5720
+ * @returns True if session is authenticated, false otherwise
5721
+ */
5722
+ async isSessionValid() {
5723
+ const session = await this.getSession();
5724
+ return session.authenticated;
5725
+ }
5726
+ // ==========================================================================
5727
+ // Subscription Methods
5728
+ // ==========================================================================
5479
5729
  async createSubscription(productId = "compute", options) {
5480
5730
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5481
5731
  const body = options ? {
@@ -5494,10 +5744,72 @@ var BillingApiClient = class {
5494
5744
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
5495
5745
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
5496
5746
  }
5747
+ // ==========================================================================
5748
+ // Internal Methods
5749
+ // ==========================================================================
5497
5750
  /**
5498
5751
  * Make an authenticated request to the billing API
5752
+ *
5753
+ * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
5499
5754
  */
5500
5755
  async makeAuthenticatedRequest(url, method, productId, body) {
5756
+ if (this.useSession) {
5757
+ return this.makeSessionAuthenticatedRequest(url, method, body);
5758
+ }
5759
+ return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
5760
+ }
5761
+ /**
5762
+ * Make a request using session-based authentication (cookies)
5763
+ */
5764
+ async makeSessionAuthenticatedRequest(url, method, body) {
5765
+ const headers = {};
5766
+ if (body) {
5767
+ headers["Content-Type"] = "application/json";
5768
+ }
5769
+ try {
5770
+ const response = await fetch(url, {
5771
+ method,
5772
+ credentials: "include",
5773
+ // Include cookies for session management
5774
+ headers,
5775
+ body: body ? JSON.stringify(body) : void 0
5776
+ });
5777
+ const status = response.status;
5778
+ const statusText = status >= 200 && status < 300 ? "OK" : "Error";
5779
+ if (status < 200 || status >= 300) {
5780
+ let errorBody;
5781
+ try {
5782
+ errorBody = await response.text();
5783
+ } catch {
5784
+ errorBody = statusText;
5785
+ }
5786
+ throw new Error(`BillingAPI request failed: ${status} ${statusText} - ${errorBody}`);
5787
+ }
5788
+ const responseData = await response.json();
5789
+ return {
5790
+ json: async () => responseData,
5791
+ text: async () => JSON.stringify(responseData)
5792
+ };
5793
+ } catch (error) {
5794
+ if (error.name === "TypeError" || error.message?.includes("fetch")) {
5795
+ throw new Error(
5796
+ `Failed to connect to BillingAPI at ${url}: ${error.message}
5797
+ Please check:
5798
+ 1. Your internet connection
5799
+ 2. The API server is accessible: ${this.config.billingApiServerURL}
5800
+ 3. Firewall/proxy settings`
5801
+ );
5802
+ }
5803
+ throw error;
5804
+ }
5805
+ }
5806
+ /**
5807
+ * Make a request using EIP-712 signature authentication
5808
+ */
5809
+ async makeSignatureAuthenticatedRequest(url, method, productId, body) {
5810
+ if (!this.walletClient) {
5811
+ throw new Error("WalletClient is required for signature authentication");
5812
+ }
5501
5813
  const expiry = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
5502
5814
  const { signature } = await calculateBillingAuthSignature({
5503
5815
  walletClient: this.walletClient,
@@ -5817,16 +6129,24 @@ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger)
5817
6129
  },
5818
6130
  logger
5819
6131
  );
6132
+ logger.debug("Checking delegation status...");
6133
+ const authorizationList = await createAuthorizationList({
6134
+ walletClient: batch.walletClient,
6135
+ publicClient: batch.publicClient,
6136
+ environmentConfig: batch.environmentConfig
6137
+ });
5820
6138
  logger.debug("Estimating gas...");
5821
6139
  const gasEstimate = await estimateBatchGas({
5822
6140
  publicClient: batch.publicClient,
5823
6141
  account: batch.walletClient.account.address,
5824
- executions: batch.executions
6142
+ executions: batch.executions,
6143
+ authorizationList
5825
6144
  });
5826
6145
  const data = {
5827
6146
  appId: batch.appId,
5828
6147
  salt: batch.salt,
5829
- executions: batch.executions
6148
+ executions: batch.executions,
6149
+ authorizationList
5830
6150
  };
5831
6151
  return {
5832
6152
  prepared: {
@@ -6055,16 +6375,24 @@ async function prepareDeploy(options, logger = defaultLogger) {
6055
6375
  },
6056
6376
  logger
6057
6377
  );
6378
+ logger.debug("Checking delegation status...");
6379
+ const authorizationList = await createAuthorizationList({
6380
+ walletClient: batch.walletClient,
6381
+ publicClient: batch.publicClient,
6382
+ environmentConfig: batch.environmentConfig
6383
+ });
6058
6384
  logger.debug("Estimating gas...");
6059
6385
  const gasEstimate = await estimateBatchGas({
6060
6386
  publicClient: batch.publicClient,
6061
6387
  account: batch.walletClient.account.address,
6062
- executions: batch.executions
6388
+ executions: batch.executions,
6389
+ authorizationList
6063
6390
  });
6064
6391
  const data = {
6065
6392
  appId: batch.appId,
6066
6393
  salt: batch.salt,
6067
- executions: batch.executions
6394
+ executions: batch.executions,
6395
+ authorizationList
6068
6396
  };
6069
6397
  return {
6070
6398
  prepared: {
@@ -6195,15 +6523,23 @@ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger
6195
6523
  needsPermissionChange,
6196
6524
  imageRef: options.imageRef
6197
6525
  });
6526
+ logger.debug("Checking delegation status...");
6527
+ const authorizationList = await createAuthorizationList({
6528
+ walletClient: batch.walletClient,
6529
+ publicClient: batch.publicClient,
6530
+ environmentConfig: batch.environmentConfig
6531
+ });
6198
6532
  logger.debug("Estimating gas...");
6199
6533
  const gasEstimate = await estimateBatchGas({
6200
6534
  publicClient: batch.publicClient,
6201
6535
  account: batch.walletClient.account.address,
6202
- executions: batch.executions
6536
+ executions: batch.executions,
6537
+ authorizationList
6203
6538
  });
6204
6539
  const data = {
6205
6540
  appId: batch.appId,
6206
- executions: batch.executions
6541
+ executions: batch.executions,
6542
+ authorizationList
6207
6543
  };
6208
6544
  return {
6209
6545
  prepared: {
@@ -6376,15 +6712,23 @@ async function prepareUpgrade(options, logger = defaultLogger) {
6376
6712
  needsPermissionChange,
6377
6713
  imageRef: finalImageRef
6378
6714
  });
6715
+ logger.debug("Checking delegation status...");
6716
+ const authorizationList = await createAuthorizationList({
6717
+ walletClient: batch.walletClient,
6718
+ publicClient: batch.publicClient,
6719
+ environmentConfig: batch.environmentConfig
6720
+ });
6379
6721
  logger.debug("Estimating gas...");
6380
6722
  const gasEstimate = await estimateBatchGas({
6381
6723
  publicClient: batch.publicClient,
6382
6724
  account: batch.walletClient.account.address,
6383
- executions: batch.executions
6725
+ executions: batch.executions,
6726
+ authorizationList
6384
6727
  });
6385
6728
  const data = {
6386
6729
  appId: batch.appId,
6387
- executions: batch.executions
6730
+ executions: batch.executions,
6731
+ authorizationList
6388
6732
  };
6389
6733
  return {
6390
6734
  prepared: {
@@ -7512,7 +7856,10 @@ function createBillingModule(config) {
7512
7856
  };
7513
7857
  }
7514
7858
  logger.debug(`Creating subscription for ${productId}...`);
7515
- const result = await billingApi.createSubscription(productId);
7859
+ const result = await billingApi.createSubscription(productId, {
7860
+ successUrl: opts?.successUrl,
7861
+ cancelUrl: opts?.cancelUrl
7862
+ });
7516
7863
  logger.debug(`Checkout URL: ${result.checkoutUrl}`);
7517
7864
  return {
7518
7865
  type: "checkout_created",
@@ -7604,9 +7951,22 @@ async function requestWithRetry(config) {
7604
7951
  }
7605
7952
  var BuildApiClient = class {
7606
7953
  constructor(options) {
7607
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
7954
+ let url = options.baseUrl;
7955
+ while (url.endsWith("/")) {
7956
+ url = url.slice(0, -1);
7957
+ }
7958
+ this.baseUrl = url;
7608
7959
  this.clientId = options.clientId;
7609
7960
  this.walletClient = options.walletClient;
7961
+ this.useSession = options.useSession ?? false;
7962
+ this.billingSessionId = options.billingSessionId;
7963
+ }
7964
+ /**
7965
+ * Update the billing session ID.
7966
+ * Call this after logging into the billing API to enable session-based auth for builds.
7967
+ */
7968
+ setBillingSessionId(sessionId) {
7969
+ this.billingSessionId = sessionId;
7610
7970
  }
7611
7971
  /**
7612
7972
  * Get the address of the connected wallet
@@ -7618,8 +7978,17 @@ var BuildApiClient = class {
7618
7978
  }
7619
7979
  return account.address;
7620
7980
  }
7981
+ /**
7982
+ * Submit a new build request.
7983
+ * Supports two auth modes (session auth is tried first when billingSessionId is available):
7984
+ * 1. Session-based auth: X-Billing-Session header (forwarded billing_session cookie)
7985
+ * 2. Signature-based auth: Authorization + X-Account + X-eigenx-expiry headers (requires walletClient)
7986
+ */
7621
7987
  async submitBuild(payload) {
7622
- return this.authenticatedJsonRequest("/builds", "POST", payload);
7988
+ if (this.useSession && this.billingSessionId) {
7989
+ return this.billingSessionAuthJsonRequest("/builds", "POST", payload);
7990
+ }
7991
+ return this.signatureAuthJsonRequest("/builds", "POST", payload);
7623
7992
  }
7624
7993
  async getBuild(buildId) {
7625
7994
  return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
@@ -7630,8 +7999,11 @@ var BuildApiClient = class {
7630
7999
  async verify(identifier) {
7631
8000
  return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
7632
8001
  }
8002
+ /**
8003
+ * Get build logs. Supports session auth (identity verification only, no billing check).
8004
+ */
7633
8005
  async getLogs(buildId) {
7634
- return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
8006
+ return this.sessionOrSignatureTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
7635
8007
  }
7636
8008
  async listBuilds(params) {
7637
8009
  const res = await requestWithRetry({
@@ -7639,7 +8011,9 @@ var BuildApiClient = class {
7639
8011
  method: "GET",
7640
8012
  params,
7641
8013
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7642
- timeout: 6e4
8014
+ timeout: 6e4,
8015
+ validateStatus: () => true,
8016
+ withCredentials: this.useSession
7643
8017
  });
7644
8018
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7645
8019
  return res.data;
@@ -7649,12 +8023,18 @@ var BuildApiClient = class {
7649
8023
  url: `${this.baseUrl}${path8}`,
7650
8024
  method: "GET",
7651
8025
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
7652
- timeout: 6e4
8026
+ timeout: 6e4,
8027
+ validateStatus: () => true,
8028
+ withCredentials: this.useSession
7653
8029
  });
7654
8030
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7655
8031
  return res.data;
7656
8032
  }
7657
- async authenticatedJsonRequest(path8, method, body) {
8033
+ /**
8034
+ * Make a request that ALWAYS requires signature auth (for billing verification).
8035
+ * Used for endpoints like POST /builds that need to verify subscription status.
8036
+ */
8037
+ async signatureAuthJsonRequest(path8, method, body) {
7658
8038
  if (!this.walletClient?.account) {
7659
8039
  throw new Error("WalletClient with account required for authenticated requests");
7660
8040
  }
@@ -7676,32 +8056,69 @@ var BuildApiClient = class {
7676
8056
  method,
7677
8057
  headers,
7678
8058
  data: body,
7679
- timeout: 6e4
8059
+ timeout: 6e4,
8060
+ validateStatus: () => true,
8061
+ withCredentials: this.useSession
7680
8062
  });
7681
8063
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7682
8064
  return res.data;
7683
8065
  }
7684
- async authenticatedTextRequest(path8) {
7685
- if (!this.walletClient?.account) {
7686
- throw new Error("WalletClient with account required for authenticated requests");
8066
+ /**
8067
+ * Make a request using billing session auth (for billing verification without wallet signature).
8068
+ * Forwards the billing_session cookie value via X-Billing-Session header.
8069
+ * Used for endpoints that need to verify subscription status when using session-based auth.
8070
+ */
8071
+ async billingSessionAuthJsonRequest(path8, method, body) {
8072
+ if (!this.billingSessionId) {
8073
+ throw new Error("billingSessionId required for session-based billing auth");
7687
8074
  }
7688
- const headers = {};
8075
+ const headers = {
8076
+ "Content-Type": "application/json",
8077
+ "X-Billing-Session": this.billingSessionId
8078
+ };
7689
8079
  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
8080
+ const res = await requestWithRetry({
8081
+ url: `${this.baseUrl}${path8}`,
8082
+ method,
8083
+ headers,
8084
+ data: body,
8085
+ timeout: 6e4,
8086
+ validateStatus: () => true,
8087
+ withCredentials: this.useSession
7695
8088
  });
7696
- headers.Authorization = `Bearer ${signature}`;
7697
- headers["X-eigenx-expiry"] = expiry.toString();
7698
- headers["X-Account"] = this.address;
8089
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
8090
+ return res.data;
8091
+ }
8092
+ /**
8093
+ * Make an authenticated request that can use session OR signature auth.
8094
+ * When useSession is true, relies on cookies for identity verification.
8095
+ * Used for endpoints that only need identity verification (not billing).
8096
+ */
8097
+ async sessionOrSignatureTextRequest(path8) {
8098
+ const headers = {};
8099
+ if (this.clientId) headers["x-client-id"] = this.clientId;
8100
+ if (!this.useSession) {
8101
+ if (!this.walletClient?.account) {
8102
+ throw new Error("WalletClient with account required for authenticated requests");
8103
+ }
8104
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
8105
+ const { signature } = await calculateBillingAuthSignature({
8106
+ walletClient: this.walletClient,
8107
+ product: "compute",
8108
+ expiry
8109
+ });
8110
+ headers.Authorization = `Bearer ${signature}`;
8111
+ headers["X-eigenx-expiry"] = expiry.toString();
8112
+ headers["X-Account"] = this.address;
8113
+ }
7699
8114
  const res = await requestWithRetry({
7700
8115
  url: `${this.baseUrl}${path8}`,
7701
8116
  method: "GET",
7702
8117
  headers,
7703
8118
  timeout: 6e4,
7704
- responseType: "text"
8119
+ responseType: "text",
8120
+ validateStatus: () => true,
8121
+ withCredentials: this.useSession
7705
8122
  });
7706
8123
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
7707
8124
  return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
@@ -8268,6 +8685,9 @@ function isSiweMessageNotYetValid(params) {
8268
8685
  return /* @__PURE__ */ new Date() < params.notBefore;
8269
8686
  }
8270
8687
 
8688
+ // src/client/common/auth/index.ts
8689
+ init_session();
8690
+
8271
8691
  // src/client/common/utils/instance.ts
8272
8692
  async function getCurrentInstanceType(preflightCtx, appID, logger, clientId) {
8273
8693
  try {