@layr-labs/ecloud-sdk 0.2.2-dev → 0.3.0-dev

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/browser.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,10 +30,148 @@ 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
+ var session_exports = {};
35
+ __export(session_exports, {
36
+ SessionError: () => SessionError,
37
+ getComputeApiSession: () => getComputeApiSession,
38
+ isSessionValid: () => isSessionValid,
39
+ loginToComputeApi: () => loginToComputeApi,
40
+ logoutFromComputeApi: () => logoutFromComputeApi
41
+ });
42
+ function stripHexPrefix2(hex) {
43
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
44
+ }
45
+ async function parseErrorResponse(response) {
46
+ try {
47
+ const data = await response.json();
48
+ return data.error || response.statusText;
49
+ } catch {
50
+ return response.statusText;
51
+ }
52
+ }
53
+ async function loginToComputeApi(config, request) {
54
+ let response;
55
+ try {
56
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
57
+ method: "POST",
58
+ credentials: "include",
59
+ // Include cookies for session management
60
+ headers: {
61
+ "Content-Type": "application/json"
62
+ },
63
+ body: JSON.stringify({
64
+ message: request.message,
65
+ signature: stripHexPrefix2(request.signature)
66
+ })
67
+ });
68
+ } catch (error) {
69
+ throw new SessionError(
70
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
71
+ "NETWORK_ERROR"
72
+ );
73
+ }
74
+ if (!response.ok) {
75
+ const errorMessage = await parseErrorResponse(response);
76
+ const status = response.status;
77
+ if (status === 400) {
78
+ if (errorMessage.toLowerCase().includes("siwe")) {
79
+ throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
80
+ }
81
+ throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
82
+ }
83
+ if (status === 401) {
84
+ throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
85
+ }
86
+ throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
87
+ }
88
+ const data = await response.json();
89
+ return {
90
+ success: data.success,
91
+ address: data.address
92
+ };
93
+ }
94
+ async function getComputeApiSession(config) {
95
+ let response;
96
+ try {
97
+ response = await fetch(`${config.baseUrl}/auth/session`, {
98
+ method: "GET",
99
+ credentials: "include",
100
+ // Include cookies for session management
101
+ headers: {
102
+ "Content-Type": "application/json"
103
+ }
104
+ });
105
+ } catch {
106
+ return {
107
+ authenticated: false
108
+ };
109
+ }
110
+ if (response.status === 401) {
111
+ return {
112
+ authenticated: false
113
+ };
114
+ }
115
+ if (!response.ok) {
116
+ const errorMessage = await parseErrorResponse(response);
117
+ throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
118
+ }
119
+ const data = await response.json();
120
+ return {
121
+ authenticated: data.authenticated,
122
+ address: data.address,
123
+ chainId: data.chain_id
124
+ };
125
+ }
126
+ async function logoutFromComputeApi(config) {
127
+ let response;
128
+ try {
129
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
130
+ method: "POST",
131
+ credentials: "include",
132
+ // Include cookies for session management
133
+ headers: {
134
+ "Content-Type": "application/json"
135
+ }
136
+ });
137
+ } catch (error) {
138
+ throw new SessionError(
139
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
140
+ "NETWORK_ERROR"
141
+ );
142
+ }
143
+ if (response.status === 401) {
144
+ return;
145
+ }
146
+ if (!response.ok) {
147
+ const errorMessage = await parseErrorResponse(response);
148
+ throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
149
+ }
150
+ }
151
+ async function isSessionValid(config) {
152
+ const session = await getComputeApiSession(config);
153
+ return session.authenticated;
154
+ }
155
+ var SessionError;
156
+ var init_session = __esm({
157
+ "src/client/common/auth/session.ts"() {
158
+ "use strict";
159
+ SessionError = class extends Error {
160
+ constructor(message, code, statusCode) {
161
+ super(message);
162
+ this.code = code;
163
+ this.statusCode = statusCode;
164
+ this.name = "SessionError";
165
+ }
166
+ };
167
+ }
168
+ });
169
+
30
170
  // src/browser.ts
31
171
  var browser_exports = {};
32
172
  __export(browser_exports, {
33
173
  BillingApiClient: () => BillingApiClient,
174
+ BillingSessionError: () => BillingSessionError,
34
175
  BuildApiClient: () => BuildApiClient,
35
176
  SessionError: () => SessionError,
36
177
  UserApiClient: () => UserApiClient,
@@ -62,6 +203,7 @@ __export(browser_exports, {
62
203
  getAppsByCreator: () => getAppsByCreator,
63
204
  getAppsByDeveloper: () => getAppsByDeveloper,
64
205
  getAvailableEnvironments: () => getAvailableEnvironments,
206
+ getBillingApiSession: () => getBillingApiSession,
65
207
  getBillingEnvironmentConfig: () => getBillingEnvironmentConfig,
66
208
  getBuildType: () => getBuildType,
67
209
  getChainFromID: () => getChainFromID,
@@ -69,6 +211,7 @@ __export(browser_exports, {
69
211
  getEnvironmentConfig: () => getEnvironmentConfig,
70
212
  getKMSKeysForEnvironment: () => getKMSKeysForEnvironment,
71
213
  getMaxActiveAppsPerUser: () => getMaxActiveAppsPerUser,
214
+ isBillingSessionValid: () => isBillingSessionValid,
72
215
  isDelegated: () => isDelegated,
73
216
  isEnvironmentAvailable: () => isEnvironmentAvailable,
74
217
  isMainnet: () => isMainnet,
@@ -76,7 +219,11 @@ __export(browser_exports, {
76
219
  isSiweMessageExpired: () => isSiweMessageExpired,
77
220
  isSiweMessageNotYetValid: () => isSiweMessageNotYetValid,
78
221
  isSubscriptionActive: () => isSubscriptionActive,
222
+ loginToBillingApi: () => loginToBillingApi,
223
+ loginToBothApis: () => loginToBothApis,
79
224
  loginToComputeApi: () => loginToComputeApi,
225
+ logoutFromBillingApi: () => logoutFromBillingApi,
226
+ logoutFromBothApis: () => logoutFromBothApis,
80
227
  logoutFromComputeApi: () => logoutFromComputeApi,
81
228
  noopLogger: () => noopLogger,
82
229
  parseSiweMessage: () => parseSiweMessage,
@@ -511,130 +658,8 @@ async function calculateBillingAuthSignature(options) {
511
658
  return { signature, expiry };
512
659
  }
513
660
 
514
- // src/client/common/auth/session.ts
515
- var SessionError = class extends Error {
516
- constructor(message, code, statusCode) {
517
- super(message);
518
- this.code = code;
519
- this.statusCode = statusCode;
520
- this.name = "SessionError";
521
- }
522
- };
523
- function stripHexPrefix2(hex) {
524
- return hex.startsWith("0x") ? hex.slice(2) : hex;
525
- }
526
- async function parseErrorResponse(response) {
527
- try {
528
- const data = await response.json();
529
- return data.error || response.statusText;
530
- } catch {
531
- return response.statusText;
532
- }
533
- }
534
- async function loginToComputeApi(config, request) {
535
- let response;
536
- try {
537
- response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
538
- method: "POST",
539
- credentials: "include",
540
- // Include cookies for session management
541
- headers: {
542
- "Content-Type": "application/json"
543
- },
544
- body: JSON.stringify({
545
- message: request.message,
546
- signature: stripHexPrefix2(request.signature)
547
- })
548
- });
549
- } catch (error) {
550
- throw new SessionError(
551
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
552
- "NETWORK_ERROR"
553
- );
554
- }
555
- if (!response.ok) {
556
- const errorMessage = await parseErrorResponse(response);
557
- const status = response.status;
558
- if (status === 400) {
559
- if (errorMessage.toLowerCase().includes("siwe")) {
560
- throw new SessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
561
- }
562
- throw new SessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
563
- }
564
- if (status === 401) {
565
- throw new SessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
566
- }
567
- throw new SessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
568
- }
569
- const data = await response.json();
570
- return {
571
- success: data.success,
572
- address: data.address
573
- };
574
- }
575
- async function getComputeApiSession(config) {
576
- let response;
577
- try {
578
- response = await fetch(`${config.baseUrl}/auth/session`, {
579
- method: "GET",
580
- credentials: "include",
581
- // Include cookies for session management
582
- headers: {
583
- "Content-Type": "application/json"
584
- }
585
- });
586
- } catch {
587
- return {
588
- authenticated: false
589
- };
590
- }
591
- if (response.status === 401) {
592
- return {
593
- authenticated: false
594
- };
595
- }
596
- if (!response.ok) {
597
- const errorMessage = await parseErrorResponse(response);
598
- throw new SessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
599
- }
600
- const data = await response.json();
601
- return {
602
- authenticated: data.authenticated,
603
- address: data.address,
604
- chainId: data.chain_id
605
- };
606
- }
607
- async function logoutFromComputeApi(config) {
608
- let response;
609
- try {
610
- response = await fetch(`${config.baseUrl}/auth/logout`, {
611
- method: "POST",
612
- credentials: "include",
613
- // Include cookies for session management
614
- headers: {
615
- "Content-Type": "application/json"
616
- }
617
- });
618
- } catch (error) {
619
- throw new SessionError(
620
- `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
621
- "NETWORK_ERROR"
622
- );
623
- }
624
- if (response.status === 401) {
625
- return;
626
- }
627
- if (!response.ok) {
628
- const errorMessage = await parseErrorResponse(response);
629
- throw new SessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
630
- }
631
- }
632
- async function isSessionValid(config) {
633
- const session = await getComputeApiSession(config);
634
- return session.authenticated;
635
- }
636
-
637
661
  // src/client/common/utils/userapi.ts
662
+ init_session();
638
663
  function isJsonObject(value) {
639
664
  return typeof value === "object" && value !== null && !Array.isArray(value);
640
665
  }
@@ -651,7 +676,7 @@ var CanViewAppLogsPermission = "0x2fd3f2fe";
651
676
  var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
652
677
  var CanUpdateAppProfilePermission = "0x036fef61";
653
678
  function getDefaultClientId() {
654
- const version = true ? "0.2.2-dev" : "0.0.0";
679
+ const version = true ? "0.3.0-dev" : "0.0.0";
655
680
  return `ecloud-sdk/v${version}`;
656
681
  }
657
682
  var UserApiClient = class {
@@ -989,21 +1014,233 @@ function transformAppRelease(raw) {
989
1014
 
990
1015
  // src/client/common/utils/billingapi.ts
991
1016
  var import_axios2 = __toESM(require("axios"), 1);
1017
+
1018
+ // src/client/common/auth/billingSession.ts
1019
+ var BillingSessionError = class extends Error {
1020
+ constructor(message, code, statusCode) {
1021
+ super(message);
1022
+ this.code = code;
1023
+ this.statusCode = statusCode;
1024
+ this.name = "BillingSessionError";
1025
+ }
1026
+ };
1027
+ function stripHexPrefix3(hex) {
1028
+ return hex.startsWith("0x") ? hex.slice(2) : hex;
1029
+ }
1030
+ async function parseErrorResponse2(response) {
1031
+ try {
1032
+ const data = await response.json();
1033
+ return data.error || response.statusText;
1034
+ } catch {
1035
+ return response.statusText;
1036
+ }
1037
+ }
1038
+ async function loginToBillingApi(config, request) {
1039
+ let response;
1040
+ try {
1041
+ response = await fetch(`${config.baseUrl}/auth/siwe/login`, {
1042
+ method: "POST",
1043
+ credentials: "include",
1044
+ // Include cookies for session management
1045
+ headers: {
1046
+ "Content-Type": "application/json"
1047
+ },
1048
+ body: JSON.stringify({
1049
+ message: request.message,
1050
+ signature: stripHexPrefix3(request.signature)
1051
+ })
1052
+ });
1053
+ } catch (error) {
1054
+ throw new BillingSessionError(
1055
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
1056
+ "NETWORK_ERROR"
1057
+ );
1058
+ }
1059
+ if (!response.ok) {
1060
+ const errorMessage = await parseErrorResponse2(response);
1061
+ const status = response.status;
1062
+ if (status === 400) {
1063
+ if (errorMessage.toLowerCase().includes("siwe")) {
1064
+ throw new BillingSessionError(`Invalid SIWE message: ${errorMessage}`, "INVALID_MESSAGE", status);
1065
+ }
1066
+ throw new BillingSessionError(`Bad request: ${errorMessage}`, "INVALID_MESSAGE", status);
1067
+ }
1068
+ if (status === 401) {
1069
+ throw new BillingSessionError(`Invalid signature: ${errorMessage}`, "INVALID_SIGNATURE", status);
1070
+ }
1071
+ throw new BillingSessionError(`Login failed: ${errorMessage}`, "UNKNOWN", status);
1072
+ }
1073
+ const data = await response.json();
1074
+ return {
1075
+ success: data.success,
1076
+ address: data.address
1077
+ };
1078
+ }
1079
+ async function getBillingApiSession(config) {
1080
+ let response;
1081
+ try {
1082
+ response = await fetch(`${config.baseUrl}/auth/session`, {
1083
+ method: "GET",
1084
+ credentials: "include",
1085
+ // Include cookies for session management
1086
+ headers: {
1087
+ "Content-Type": "application/json"
1088
+ }
1089
+ });
1090
+ } catch {
1091
+ return {
1092
+ authenticated: false
1093
+ };
1094
+ }
1095
+ if (response.status === 401) {
1096
+ return {
1097
+ authenticated: false
1098
+ };
1099
+ }
1100
+ if (!response.ok) {
1101
+ const errorMessage = await parseErrorResponse2(response);
1102
+ throw new BillingSessionError(`Failed to get session: ${errorMessage}`, "UNKNOWN", response.status);
1103
+ }
1104
+ const data = await response.json();
1105
+ return {
1106
+ authenticated: data.authenticated,
1107
+ address: data.address,
1108
+ chainId: data.chainId,
1109
+ authenticatedAt: data.authenticatedAt
1110
+ };
1111
+ }
1112
+ async function logoutFromBillingApi(config) {
1113
+ let response;
1114
+ try {
1115
+ response = await fetch(`${config.baseUrl}/auth/logout`, {
1116
+ method: "POST",
1117
+ credentials: "include",
1118
+ // Include cookies for session management
1119
+ headers: {
1120
+ "Content-Type": "application/json"
1121
+ }
1122
+ });
1123
+ } catch (error) {
1124
+ throw new BillingSessionError(
1125
+ `Network error connecting to ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`,
1126
+ "NETWORK_ERROR"
1127
+ );
1128
+ }
1129
+ if (response.status === 401) {
1130
+ return;
1131
+ }
1132
+ if (!response.ok) {
1133
+ const errorMessage = await parseErrorResponse2(response);
1134
+ throw new BillingSessionError(`Logout failed: ${errorMessage}`, "UNKNOWN", response.status);
1135
+ }
1136
+ }
1137
+ async function isBillingSessionValid(config) {
1138
+ const session = await getBillingApiSession(config);
1139
+ return session.authenticated;
1140
+ }
1141
+ async function loginToBothApis(computeConfig, billingConfig, request) {
1142
+ const { loginToComputeApi: loginToComputeApi2 } = await Promise.resolve().then(() => (init_session(), session_exports));
1143
+ const [compute, billing] = await Promise.all([
1144
+ loginToComputeApi2(computeConfig, request),
1145
+ loginToBillingApi(billingConfig, request)
1146
+ ]);
1147
+ return { compute, billing };
1148
+ }
1149
+ async function logoutFromBothApis(computeConfig, billingConfig) {
1150
+ const { logoutFromComputeApi: logoutFromComputeApi2 } = await Promise.resolve().then(() => (init_session(), session_exports));
1151
+ await Promise.all([
1152
+ logoutFromComputeApi2(computeConfig),
1153
+ logoutFromBillingApi(billingConfig)
1154
+ ]);
1155
+ }
1156
+
1157
+ // src/client/common/utils/billingapi.ts
992
1158
  var BillingApiClient = class {
993
- constructor(config, walletClient) {
1159
+ constructor(config, walletClient, options = {}) {
994
1160
  this.config = config;
995
1161
  this.walletClient = walletClient;
1162
+ this.options = options;
1163
+ this.useSession = options.useSession ?? false;
1164
+ if (!this.useSession && !walletClient) {
1165
+ throw new Error("WalletClient is required when not using session authentication");
1166
+ }
996
1167
  }
997
1168
  /**
998
1169
  * Get the address of the connected wallet
1170
+ * Returns undefined if using session auth without a wallet client
999
1171
  */
1000
1172
  get address() {
1001
- const account = this.walletClient.account;
1173
+ const account = this.walletClient?.account;
1002
1174
  if (!account) {
1003
- throw new Error("WalletClient must have an account attached");
1175
+ if (!this.useSession) {
1176
+ throw new Error("WalletClient must have an account attached");
1177
+ }
1178
+ return void 0;
1004
1179
  }
1005
1180
  return account.address;
1006
1181
  }
1182
+ /**
1183
+ * Get the base URL of the billing API
1184
+ */
1185
+ get baseUrl() {
1186
+ return this.config.billingApiServerURL;
1187
+ }
1188
+ // ==========================================================================
1189
+ // SIWE Session Methods
1190
+ // ==========================================================================
1191
+ /**
1192
+ * Login to the billing API using SIWE
1193
+ *
1194
+ * This establishes a session with the billing API by verifying the SIWE message
1195
+ * and signature. On success, a session cookie is set in the browser.
1196
+ *
1197
+ * @param request - Login request containing SIWE message and signature
1198
+ * @returns Login result with the authenticated address
1199
+ *
1200
+ * @example
1201
+ * ```typescript
1202
+ * const { message } = createSiweMessage({
1203
+ * address: userAddress,
1204
+ * chainId: 11155111,
1205
+ * domain: window.location.host,
1206
+ * uri: window.location.origin,
1207
+ * });
1208
+ *
1209
+ * const signature = await signMessageAsync({ message });
1210
+ * const result = await billingClient.siweLogin({ message, signature });
1211
+ * ```
1212
+ */
1213
+ async siweLogin(request) {
1214
+ return loginToBillingApi({ baseUrl: this.baseUrl }, request);
1215
+ }
1216
+ /**
1217
+ * Logout from the billing API
1218
+ *
1219
+ * This destroys the current session and clears the session cookie.
1220
+ */
1221
+ async siweLogout() {
1222
+ return logoutFromBillingApi({ baseUrl: this.baseUrl });
1223
+ }
1224
+ /**
1225
+ * Get the current session status from the billing API
1226
+ *
1227
+ * @returns Session information including authentication status and address
1228
+ */
1229
+ async getSession() {
1230
+ return getBillingApiSession({ baseUrl: this.baseUrl });
1231
+ }
1232
+ /**
1233
+ * Check if there is a valid session
1234
+ *
1235
+ * @returns True if session is authenticated, false otherwise
1236
+ */
1237
+ async isSessionValid() {
1238
+ const session = await this.getSession();
1239
+ return session.authenticated;
1240
+ }
1241
+ // ==========================================================================
1242
+ // Subscription Methods
1243
+ // ==========================================================================
1007
1244
  async createSubscription(productId = "compute", options) {
1008
1245
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
1009
1246
  const body = options ? {
@@ -1022,10 +1259,72 @@ var BillingApiClient = class {
1022
1259
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
1023
1260
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
1024
1261
  }
1262
+ // ==========================================================================
1263
+ // Internal Methods
1264
+ // ==========================================================================
1025
1265
  /**
1026
1266
  * Make an authenticated request to the billing API
1267
+ *
1268
+ * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
1027
1269
  */
1028
1270
  async makeAuthenticatedRequest(url, method, productId, body) {
1271
+ if (this.useSession) {
1272
+ return this.makeSessionAuthenticatedRequest(url, method, body);
1273
+ }
1274
+ return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
1275
+ }
1276
+ /**
1277
+ * Make a request using session-based authentication (cookies)
1278
+ */
1279
+ async makeSessionAuthenticatedRequest(url, method, body) {
1280
+ const headers = {};
1281
+ if (body) {
1282
+ headers["Content-Type"] = "application/json";
1283
+ }
1284
+ try {
1285
+ const response = await fetch(url, {
1286
+ method,
1287
+ credentials: "include",
1288
+ // Include cookies for session management
1289
+ headers,
1290
+ body: body ? JSON.stringify(body) : void 0
1291
+ });
1292
+ const status = response.status;
1293
+ const statusText = status >= 200 && status < 300 ? "OK" : "Error";
1294
+ if (status < 200 || status >= 300) {
1295
+ let errorBody;
1296
+ try {
1297
+ errorBody = await response.text();
1298
+ } catch {
1299
+ errorBody = statusText;
1300
+ }
1301
+ throw new Error(`BillingAPI request failed: ${status} ${statusText} - ${errorBody}`);
1302
+ }
1303
+ const responseData = await response.json();
1304
+ return {
1305
+ json: async () => responseData,
1306
+ text: async () => JSON.stringify(responseData)
1307
+ };
1308
+ } catch (error) {
1309
+ if (error.name === "TypeError" || error.message?.includes("fetch")) {
1310
+ throw new Error(
1311
+ `Failed to connect to BillingAPI at ${url}: ${error.message}
1312
+ Please check:
1313
+ 1. Your internet connection
1314
+ 2. The API server is accessible: ${this.config.billingApiServerURL}
1315
+ 3. Firewall/proxy settings`
1316
+ );
1317
+ }
1318
+ throw error;
1319
+ }
1320
+ }
1321
+ /**
1322
+ * Make a request using EIP-712 signature authentication
1323
+ */
1324
+ async makeSignatureAuthenticatedRequest(url, method, productId, body) {
1325
+ if (!this.walletClient) {
1326
+ throw new Error("WalletClient is required for signature authentication");
1327
+ }
1029
1328
  const expiry = BigInt(Math.floor(Date.now() / 1e3) + 5 * 60);
1030
1329
  const { signature } = await calculateBillingAuthSignature({
1031
1330
  walletClient: this.walletClient,
@@ -1112,9 +1411,22 @@ async function requestWithRetry(config) {
1112
1411
  }
1113
1412
  var BuildApiClient = class {
1114
1413
  constructor(options) {
1115
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
1414
+ let url = options.baseUrl;
1415
+ while (url.endsWith("/")) {
1416
+ url = url.slice(0, -1);
1417
+ }
1418
+ this.baseUrl = url;
1116
1419
  this.clientId = options.clientId;
1117
1420
  this.walletClient = options.walletClient;
1421
+ this.useSession = options.useSession ?? false;
1422
+ this.billingSessionId = options.billingSessionId;
1423
+ }
1424
+ /**
1425
+ * Update the billing session ID.
1426
+ * Call this after logging into the billing API to enable session-based auth for builds.
1427
+ */
1428
+ setBillingSessionId(sessionId) {
1429
+ this.billingSessionId = sessionId;
1118
1430
  }
1119
1431
  /**
1120
1432
  * Get the address of the connected wallet
@@ -1126,8 +1438,17 @@ var BuildApiClient = class {
1126
1438
  }
1127
1439
  return account.address;
1128
1440
  }
1441
+ /**
1442
+ * Submit a new build request.
1443
+ * Supports two auth modes (session auth is tried first when billingSessionId is available):
1444
+ * 1. Session-based auth: X-Billing-Session header (forwarded billing_session cookie)
1445
+ * 2. Signature-based auth: Authorization + X-Account + X-eigenx-expiry headers (requires walletClient)
1446
+ */
1129
1447
  async submitBuild(payload) {
1130
- return this.authenticatedJsonRequest("/builds", "POST", payload);
1448
+ if (this.useSession && this.billingSessionId) {
1449
+ return this.billingSessionAuthJsonRequest("/builds", "POST", payload);
1450
+ }
1451
+ return this.signatureAuthJsonRequest("/builds", "POST", payload);
1131
1452
  }
1132
1453
  async getBuild(buildId) {
1133
1454
  return this.publicJsonRequest(`/builds/${encodeURIComponent(buildId)}`);
@@ -1138,8 +1459,11 @@ var BuildApiClient = class {
1138
1459
  async verify(identifier) {
1139
1460
  return this.publicJsonRequest(`/builds/verify/${encodeURIComponent(identifier)}`);
1140
1461
  }
1462
+ /**
1463
+ * Get build logs. Supports session auth (identity verification only, no billing check).
1464
+ */
1141
1465
  async getLogs(buildId) {
1142
- return this.authenticatedTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
1466
+ return this.sessionOrSignatureTextRequest(`/builds/${encodeURIComponent(buildId)}/logs`);
1143
1467
  }
1144
1468
  async listBuilds(params) {
1145
1469
  const res = await requestWithRetry({
@@ -1147,7 +1471,9 @@ var BuildApiClient = class {
1147
1471
  method: "GET",
1148
1472
  params,
1149
1473
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
1150
- timeout: 6e4
1474
+ timeout: 6e4,
1475
+ validateStatus: () => true,
1476
+ withCredentials: this.useSession
1151
1477
  });
1152
1478
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
1153
1479
  return res.data;
@@ -1157,12 +1483,18 @@ var BuildApiClient = class {
1157
1483
  url: `${this.baseUrl}${path}`,
1158
1484
  method: "GET",
1159
1485
  headers: this.clientId ? { "x-client-id": this.clientId } : void 0,
1160
- timeout: 6e4
1486
+ timeout: 6e4,
1487
+ validateStatus: () => true,
1488
+ withCredentials: this.useSession
1161
1489
  });
1162
1490
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
1163
1491
  return res.data;
1164
1492
  }
1165
- async authenticatedJsonRequest(path, method, body) {
1493
+ /**
1494
+ * Make a request that ALWAYS requires signature auth (for billing verification).
1495
+ * Used for endpoints like POST /builds that need to verify subscription status.
1496
+ */
1497
+ async signatureAuthJsonRequest(path, method, body) {
1166
1498
  if (!this.walletClient?.account) {
1167
1499
  throw new Error("WalletClient with account required for authenticated requests");
1168
1500
  }
@@ -1184,32 +1516,69 @@ var BuildApiClient = class {
1184
1516
  method,
1185
1517
  headers,
1186
1518
  data: body,
1187
- timeout: 6e4
1519
+ timeout: 6e4,
1520
+ validateStatus: () => true,
1521
+ withCredentials: this.useSession
1188
1522
  });
1189
1523
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
1190
1524
  return res.data;
1191
1525
  }
1192
- async authenticatedTextRequest(path) {
1193
- if (!this.walletClient?.account) {
1194
- throw new Error("WalletClient with account required for authenticated requests");
1526
+ /**
1527
+ * Make a request using billing session auth (for billing verification without wallet signature).
1528
+ * Forwards the billing_session cookie value via X-Billing-Session header.
1529
+ * Used for endpoints that need to verify subscription status when using session-based auth.
1530
+ */
1531
+ async billingSessionAuthJsonRequest(path, method, body) {
1532
+ if (!this.billingSessionId) {
1533
+ throw new Error("billingSessionId required for session-based billing auth");
1195
1534
  }
1196
- const headers = {};
1535
+ const headers = {
1536
+ "Content-Type": "application/json",
1537
+ "X-Billing-Session": this.billingSessionId
1538
+ };
1197
1539
  if (this.clientId) headers["x-client-id"] = this.clientId;
1198
- const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
1199
- const { signature } = await calculateBillingAuthSignature({
1200
- walletClient: this.walletClient,
1201
- product: "compute",
1202
- expiry
1540
+ const res = await requestWithRetry({
1541
+ url: `${this.baseUrl}${path}`,
1542
+ method,
1543
+ headers,
1544
+ data: body,
1545
+ timeout: 6e4,
1546
+ validateStatus: () => true,
1547
+ withCredentials: this.useSession
1203
1548
  });
1204
- headers.Authorization = `Bearer ${signature}`;
1205
- headers["X-eigenx-expiry"] = expiry.toString();
1206
- headers["X-Account"] = this.address;
1549
+ if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
1550
+ return res.data;
1551
+ }
1552
+ /**
1553
+ * Make an authenticated request that can use session OR signature auth.
1554
+ * When useSession is true, relies on cookies for identity verification.
1555
+ * Used for endpoints that only need identity verification (not billing).
1556
+ */
1557
+ async sessionOrSignatureTextRequest(path) {
1558
+ const headers = {};
1559
+ if (this.clientId) headers["x-client-id"] = this.clientId;
1560
+ if (!this.useSession) {
1561
+ if (!this.walletClient?.account) {
1562
+ throw new Error("WalletClient with account required for authenticated requests");
1563
+ }
1564
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + 60);
1565
+ const { signature } = await calculateBillingAuthSignature({
1566
+ walletClient: this.walletClient,
1567
+ product: "compute",
1568
+ expiry
1569
+ });
1570
+ headers.Authorization = `Bearer ${signature}`;
1571
+ headers["X-eigenx-expiry"] = expiry.toString();
1572
+ headers["X-Account"] = this.address;
1573
+ }
1207
1574
  const res = await requestWithRetry({
1208
1575
  url: `${this.baseUrl}${path}`,
1209
1576
  method: "GET",
1210
1577
  headers,
1211
1578
  timeout: 6e4,
1212
- responseType: "text"
1579
+ responseType: "text",
1580
+ validateStatus: () => true,
1581
+ withCredentials: this.useSession
1213
1582
  });
1214
1583
  if (res.status < 200 || res.status >= 300) throw buildApiHttpError(res);
1215
1584
  return typeof res.data === "string" ? res.data : JSON.stringify(res.data);
@@ -4698,8 +5067,12 @@ function isSiweMessageNotYetValid(params) {
4698
5067
  return /* @__PURE__ */ new Date() < params.notBefore;
4699
5068
  }
4700
5069
 
5070
+ // src/browser.ts
5071
+ init_session();
5072
+
4701
5073
  // src/client/common/hooks/useComputeSession.ts
4702
5074
  var import_react = require("react");
5075
+ init_session();
4703
5076
  function useComputeSession(config) {
4704
5077
  const {
4705
5078
  baseUrl,
@@ -4957,6 +5330,7 @@ function getKMSKeysForEnvironment(environment, build = "prod") {
4957
5330
  // Annotate the CommonJS export names for ESM import in node:
4958
5331
  0 && (module.exports = {
4959
5332
  BillingApiClient,
5333
+ BillingSessionError,
4960
5334
  BuildApiClient,
4961
5335
  SessionError,
4962
5336
  UserApiClient,
@@ -4988,6 +5362,7 @@ function getKMSKeysForEnvironment(environment, build = "prod") {
4988
5362
  getAppsByCreator,
4989
5363
  getAppsByDeveloper,
4990
5364
  getAvailableEnvironments,
5365
+ getBillingApiSession,
4991
5366
  getBillingEnvironmentConfig,
4992
5367
  getBuildType,
4993
5368
  getChainFromID,
@@ -4995,6 +5370,7 @@ function getKMSKeysForEnvironment(environment, build = "prod") {
4995
5370
  getEnvironmentConfig,
4996
5371
  getKMSKeysForEnvironment,
4997
5372
  getMaxActiveAppsPerUser,
5373
+ isBillingSessionValid,
4998
5374
  isDelegated,
4999
5375
  isEnvironmentAvailable,
5000
5376
  isMainnet,
@@ -5002,7 +5378,11 @@ function getKMSKeysForEnvironment(environment, build = "prod") {
5002
5378
  isSiweMessageExpired,
5003
5379
  isSiweMessageNotYetValid,
5004
5380
  isSubscriptionActive,
5381
+ loginToBillingApi,
5382
+ loginToBothApis,
5005
5383
  loginToComputeApi,
5384
+ logoutFromBillingApi,
5385
+ logoutFromBothApis,
5006
5386
  logoutFromComputeApi,
5007
5387
  noopLogger,
5008
5388
  parseSiweMessage,