@elsoul/erpc-sdk 0.1.0 → 0.3.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/README.md CHANGED
@@ -48,6 +48,7 @@ network request.
48
48
  | `erpc.ethereum.subscriptions` | Ethereum WebSocket subscriptions |
49
49
  | `erpc.price` | Price metadata, updates, and streams |
50
50
  | `erpc.account` | ERPC token balance |
51
+ | `erpc.usage` | Masked monthly API-key usage |
51
52
 
52
53
  ## Examples
53
54
 
@@ -72,6 +73,33 @@ await heads.unsubscribe()
72
73
  erpc.close()
73
74
  ```
74
75
 
76
+ Monthly API-key usage is available from the same client:
77
+
78
+ ```ts
79
+ const usage = await erpc.usage.getMonthlyApiKeyUsage({
80
+ yearMonth: '2026-08',
81
+ })
82
+ ```
83
+
84
+ For scoped ERPC Cloud OAuth access tokens, create a client that cannot receive
85
+ or retain refresh credentials:
86
+
87
+ ```ts
88
+ import { createErpcCloudClient } from '@elsoul/erpc-sdk'
89
+
90
+ const cloud = createErpcCloudClient({ accessToken })
91
+ const catalog = await cloud.catalog.list()
92
+ const credit = await cloud.credit.get()
93
+ const resources = await cloud.resources.list()
94
+ const first = resources[0]
95
+ const status = first ? await cloud.resources.getStatus(first.id) : undefined
96
+ const monthlyUsage = await cloud.usage.getMonthlyApiKeyUsage()
97
+ ```
98
+
99
+ Catalog, credit, and resource results are projected onto documented public
100
+ fields. Interactive login and operating-system keychain storage belong to
101
+ `@elsoul/erpc-cli`.
102
+
75
103
  ## Raw methods
76
104
 
77
105
  The typed catalogs track methods available from ERPC. The raw API provides
package/dist/index.cjs CHANGED
@@ -242,9 +242,82 @@ var AccountClient = class {
242
242
  }
243
243
  };
244
244
 
245
+ // src/catalog.ts
246
+ var resourceKinds = [
247
+ "bare-metal",
248
+ "solana-grpc",
249
+ "solana-shredstream",
250
+ "vps"
251
+ ];
252
+ var resourceModes = [
253
+ "dedicated",
254
+ "direct",
255
+ "shared"
256
+ ];
257
+ var objectValue = (value) => typeof value === "object" && value !== null ? value : null;
258
+ var stringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string") ? value : null;
259
+ var parseOffering = (value) => {
260
+ const offering = objectValue(value);
261
+ if (offering === null || typeof offering.id !== "string" || typeof offering.kind !== "string" || !resourceKinds.includes(offering.kind) || typeof offering.name !== "string" || typeof offering.description !== "string" || offering.mode !== void 0 && (typeof offering.mode !== "string" || !resourceModes.includes(offering.mode))) return null;
262
+ const regions = stringArray(offering.regions);
263
+ const capabilities = stringArray(offering.capabilities);
264
+ if (regions === null || capabilities === null) return null;
265
+ const compute = offering.compute === void 0 ? void 0 : objectValue(offering.compute);
266
+ if (compute !== void 0 && (compute === null || compute.tenancy !== "virtual-machine" && compute.tenancy !== "bare-metal")) return null;
267
+ const solana = offering.solana === void 0 ? void 0 : objectValue(offering.solana);
268
+ if (solana !== void 0 && (solana === null || solana.transport !== "grpc" && solana.transport !== "shredstream")) return null;
269
+ const billing = offering.billing === void 0 ? void 0 : objectValue(offering.billing);
270
+ if (billing !== void 0 && (billing === null || billing.unit !== "cents-per-hour" || typeof billing.amountCents !== "number" || !Number.isInteger(billing.amountCents) || billing.amountCents < 0)) return null;
271
+ return {
272
+ id: offering.id,
273
+ kind: offering.kind,
274
+ name: offering.name,
275
+ description: offering.description,
276
+ regions,
277
+ capabilities,
278
+ ...typeof offering.mode === "string" ? { mode: offering.mode } : {},
279
+ ...compute && (compute.tenancy === "virtual-machine" || compute.tenancy === "bare-metal") ? { compute: { tenancy: compute.tenancy } } : {},
280
+ ...solana && (solana.transport === "grpc" || solana.transport === "shredstream") ? { solana: { transport: solana.transport } } : {},
281
+ ...billing && billing.unit === "cents-per-hour" && typeof billing.amountCents === "number" ? {
282
+ billing: {
283
+ amountCents: billing.amountCents,
284
+ unit: billing.unit
285
+ }
286
+ } : {}
287
+ };
288
+ };
289
+ var CloudCatalogClient = class {
290
+ #transport;
291
+ constructor(transport) {
292
+ this.#transport = transport;
293
+ }
294
+ async list(options) {
295
+ const response = await this.#transport.get(
296
+ "/v4/cloud/catalog",
297
+ void 0,
298
+ options
299
+ );
300
+ const envelope = objectValue(response);
301
+ const message = objectValue(envelope?.message);
302
+ if (envelope?.success !== true || !Array.isArray(message?.offerings)) {
303
+ throw new ErpcInvalidResponseError(
304
+ "ERPC returned an invalid Cloud catalog"
305
+ );
306
+ }
307
+ const offerings = message.offerings.map(parseOffering);
308
+ if (offerings.some((offering) => offering === null)) {
309
+ throw new ErpcInvalidResponseError(
310
+ "ERPC returned an invalid Cloud catalog"
311
+ );
312
+ }
313
+ return offerings;
314
+ }
315
+ };
316
+
245
317
  // src/config.ts
246
318
  var DEFAULT_ENDPOINT = "https://edge.erpc.global";
247
319
  var DEFAULT_ACCOUNT_ENDPOINT = "https://solana-rpc.erpc.global";
320
+ var DEFAULT_USER_ENDPOINT = "https://user-api.erpc.global";
248
321
  var DEFAULT_TIMEOUT_MS = 3e4;
249
322
  var requireFetch = (provided) => {
250
323
  const implementation = provided ?? globalThis.fetch;
@@ -260,11 +333,13 @@ var resolveConfig = (config) => {
260
333
  if (!apiKey) throw new ErpcConfigError("apiKey must not be empty");
261
334
  let endpoint;
262
335
  let accountEndpoint;
336
+ let userEndpoint;
263
337
  try {
264
338
  endpoint = new URL(config.endpoint ?? DEFAULT_ENDPOINT);
265
339
  accountEndpoint = new URL(
266
340
  config.accountEndpoint ?? DEFAULT_ACCOUNT_ENDPOINT
267
341
  );
342
+ userEndpoint = new URL(config.userEndpoint ?? DEFAULT_USER_ENDPOINT);
268
343
  } catch {
269
344
  throw new ErpcConfigError("endpoint must be an absolute HTTP(S) URL");
270
345
  }
@@ -274,12 +349,18 @@ var resolveConfig = (config) => {
274
349
  if (accountEndpoint.protocol !== "https:" && accountEndpoint.protocol !== "http:") {
275
350
  throw new ErpcConfigError("accountEndpoint must use HTTP or HTTPS");
276
351
  }
352
+ if (userEndpoint.protocol !== "https:" && userEndpoint.protocol !== "http:") {
353
+ throw new ErpcConfigError("userEndpoint must use HTTP or HTTPS");
354
+ }
277
355
  endpoint.search = "";
278
356
  endpoint.hash = "";
279
357
  endpoint.pathname = endpoint.pathname.replace(/\/+$/, "") || "/";
280
358
  accountEndpoint.search = "";
281
359
  accountEndpoint.hash = "";
282
360
  accountEndpoint.pathname = accountEndpoint.pathname.replace(/\/+$/, "") || "/";
361
+ userEndpoint.search = "";
362
+ userEndpoint.hash = "";
363
+ userEndpoint.pathname = userEndpoint.pathname.replace(/\/+$/, "") || "/";
283
364
  const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
284
365
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
285
366
  throw new ErpcConfigError("timeoutMs must be a positive finite number");
@@ -291,6 +372,7 @@ var resolveConfig = (config) => {
291
372
  fetch: requireFetch(config.fetch),
292
373
  headers: config.headers ?? {},
293
374
  timeoutMs,
375
+ userEndpoint,
294
376
  ...config.webSocket === void 0 ? {} : { webSocket: config.webSocket }
295
377
  };
296
378
  };
@@ -1123,6 +1205,7 @@ var HttpJsonRpcTransport = class {
1123
1205
  }
1124
1206
  throw new ErpcInvalidResponseError("ERPC returned a non-array batch response");
1125
1207
  }
1208
+ const expectedIds = new Set(requests.map((request) => request.id));
1126
1209
  const byId = /* @__PURE__ */ new Map();
1127
1210
  for (const response of raw) {
1128
1211
  if (!isObject2(response) || !("id" in response)) {
@@ -1132,6 +1215,16 @@ var HttpJsonRpcTransport = class {
1132
1215
  if (typeof id !== "number" && typeof id !== "string") {
1133
1216
  throw new ErpcInvalidResponseError("ERPC returned an invalid batch id");
1134
1217
  }
1218
+ if (!expectedIds.has(id)) {
1219
+ throw new ErpcInvalidResponseError(
1220
+ "ERPC returned an unexpected batch response id"
1221
+ );
1222
+ }
1223
+ if (byId.has(id)) {
1224
+ throw new ErpcInvalidResponseError(
1225
+ `ERPC returned duplicate batch response id ${String(id)}`
1226
+ );
1227
+ }
1135
1228
  byId.set(id, response);
1136
1229
  }
1137
1230
  const results = requests.map((request) => {
@@ -1198,6 +1291,91 @@ var HttpJsonRpcTransport = class {
1198
1291
  }
1199
1292
  };
1200
1293
 
1294
+ // src/usage.ts
1295
+ var YEAR_MONTH = /^\d{4}-(0[1-9]|1[0-2])$/;
1296
+ var objectValue2 = (value) => typeof value === "object" && value !== null ? value : null;
1297
+ var isTimestamp = (value) => value === null || typeof value === "string";
1298
+ var parseMethod = (value) => {
1299
+ const method = objectValue2(value);
1300
+ if (method === null || typeof method.count !== "number" || typeof method.creditCost !== "number" || typeof method.credits !== "number" || typeof method.method !== "string" || !isTimestamp(method.updatedAt)) return null;
1301
+ return {
1302
+ count: method.count,
1303
+ creditCost: method.creditCost,
1304
+ credits: method.credits,
1305
+ method: method.method,
1306
+ updatedAt: method.updatedAt
1307
+ };
1308
+ };
1309
+ var parseChain = (value) => {
1310
+ const chain = objectValue2(value);
1311
+ if (chain === null || typeof chain.chain !== "string" || typeof chain.count !== "number" || typeof chain.credits !== "number" || !Array.isArray(chain.methods) || !isTimestamp(chain.updatedAt)) return null;
1312
+ const methods = chain.methods.map(parseMethod);
1313
+ if (methods.some((method) => method === null)) return null;
1314
+ return {
1315
+ chain: chain.chain,
1316
+ count: chain.count,
1317
+ credits: chain.credits,
1318
+ methods,
1319
+ updatedAt: chain.updatedAt
1320
+ };
1321
+ };
1322
+ var parseApiKey = (value) => {
1323
+ const apiKey = objectValue2(value);
1324
+ if (apiKey === null || typeof apiKey.apiKeyLast4 !== "string" || typeof apiKey.apiKeyLength !== "number" || !Array.isArray(apiKey.chains) || typeof apiKey.count !== "number" || typeof apiKey.credits !== "number" || apiKey.keyId !== null && typeof apiKey.keyId !== "number" || !isTimestamp(apiKey.updatedAt)) return null;
1325
+ const chains = apiKey.chains.map(parseChain);
1326
+ if (chains.some((chain) => chain === null)) return null;
1327
+ return {
1328
+ apiKeyLast4: apiKey.apiKeyLast4,
1329
+ apiKeyLength: apiKey.apiKeyLength,
1330
+ chains,
1331
+ count: apiKey.count,
1332
+ credits: apiKey.credits,
1333
+ keyId: apiKey.keyId,
1334
+ updatedAt: apiKey.updatedAt
1335
+ };
1336
+ };
1337
+ var parseMonthlyUsage = (value) => {
1338
+ const usage = objectValue2(value);
1339
+ if (usage === null || !Array.isArray(usage.apiKeys) || !Array.isArray(usage.chains) || typeof usage.hasStrandedUsage !== "boolean" || typeof usage.keyCount !== "number" || typeof usage.totalCount !== "number" || typeof usage.totalCredits !== "number" || !isTimestamp(usage.updatedAt) || typeof usage.yearMonth !== "string" || !YEAR_MONTH.test(usage.yearMonth)) return null;
1340
+ const apiKeys = usage.apiKeys.map(parseApiKey);
1341
+ const chains = usage.chains.map(parseChain);
1342
+ if (apiKeys.some((apiKey) => apiKey === null) || chains.some((chain) => chain === null)) return null;
1343
+ return {
1344
+ apiKeys,
1345
+ chains,
1346
+ hasStrandedUsage: usage.hasStrandedUsage,
1347
+ keyCount: usage.keyCount,
1348
+ totalCount: usage.totalCount,
1349
+ totalCredits: usage.totalCredits,
1350
+ updatedAt: usage.updatedAt,
1351
+ yearMonth: usage.yearMonth
1352
+ };
1353
+ };
1354
+ var UsageClient = class {
1355
+ #transport;
1356
+ constructor(transport) {
1357
+ this.#transport = transport;
1358
+ }
1359
+ async getMonthlyApiKeyUsage(params = {}, options) {
1360
+ if (params.yearMonth !== void 0 && !YEAR_MONTH.test(params.yearMonth)) {
1361
+ throw new ErpcConfigError("yearMonth must use YYYY-MM format");
1362
+ }
1363
+ const response = await this.#transport.get(
1364
+ "/v3/user/api-keys/usage",
1365
+ { yearMonth: params.yearMonth },
1366
+ options
1367
+ );
1368
+ const envelope = objectValue2(response);
1369
+ const usage = envelope?.success === true ? parseMonthlyUsage(envelope.message) : null;
1370
+ if (usage === null) {
1371
+ throw new ErpcInvalidResponseError(
1372
+ "ERPC returned an invalid monthly API key usage response"
1373
+ );
1374
+ }
1375
+ return usage;
1376
+ }
1377
+ };
1378
+
1201
1379
  // src/client.ts
1202
1380
  var createErpcClient = (config) => {
1203
1381
  const resolved = resolveConfig(config);
@@ -1234,6 +1412,10 @@ var createErpcClient = (config) => {
1234
1412
  ...sharedTransport,
1235
1413
  endpoint: resolved.accountEndpoint
1236
1414
  });
1415
+ const userTransport = new RestTransport({
1416
+ ...sharedTransport,
1417
+ endpoint: resolved.userEndpoint
1418
+ });
1237
1419
  const solana = {
1238
1420
  ...createSolanaClient(solanaTransport),
1239
1421
  subscriptions: new SolanaSubscriptions(solanaWebSocket)
@@ -1247,6 +1429,7 @@ var createErpcClient = (config) => {
1247
1429
  ethereum,
1248
1430
  price: new PriceClient(priceTransport),
1249
1431
  account: new AccountClient(accountTransport),
1432
+ usage: new UsageClient(userTransport),
1250
1433
  close: () => {
1251
1434
  solana.subscriptions.close();
1252
1435
  ethereum.subscriptions.close();
@@ -1254,10 +1437,230 @@ var createErpcClient = (config) => {
1254
1437
  };
1255
1438
  };
1256
1439
 
1440
+ // src/credit.ts
1441
+ var alertLevels = [
1442
+ "critical",
1443
+ "normal",
1444
+ "suspended",
1445
+ "warning"
1446
+ ];
1447
+ var objectValue3 = (value) => typeof value === "object" && value !== null ? value : null;
1448
+ var isDateTime = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
1449
+ var parseCredit = (value) => {
1450
+ const credit = objectValue3(value);
1451
+ if (credit === null || typeof credit.balanceCents !== "number" || !Number.isInteger(credit.balanceCents) || typeof credit.burnRateCentsPerHour !== "number" || !Number.isInteger(credit.burnRateCentsPerHour) || credit.burnRateCentsPerHour < 0 || credit.timeToZeroHours !== null && (typeof credit.timeToZeroHours !== "number" || !Number.isFinite(credit.timeToZeroHours) || credit.timeToZeroHours < 0) || typeof credit.alertLevel !== "string" || !alertLevels.includes(credit.alertLevel) || !isDateTime(credit.quoteTimestamp) || !isDateTime(credit.quoteExpiresAt)) return null;
1452
+ return {
1453
+ alertLevel: credit.alertLevel,
1454
+ balanceCents: credit.balanceCents,
1455
+ burnRateCentsPerHour: credit.burnRateCentsPerHour,
1456
+ quoteExpiresAt: credit.quoteExpiresAt,
1457
+ quoteTimestamp: credit.quoteTimestamp,
1458
+ timeToZeroHours: credit.timeToZeroHours
1459
+ };
1460
+ };
1461
+ var CloudCreditClient = class {
1462
+ #transport;
1463
+ constructor(transport) {
1464
+ this.#transport = transport;
1465
+ }
1466
+ async get(options) {
1467
+ const response = await this.#transport.get(
1468
+ "/v4/cloud/credit",
1469
+ void 0,
1470
+ options
1471
+ );
1472
+ const envelope = objectValue3(response);
1473
+ const credit = envelope?.success === true ? parseCredit(envelope.message) : null;
1474
+ if (credit === null) {
1475
+ throw new ErpcInvalidResponseError(
1476
+ "ERPC returned an invalid Cloud credit snapshot"
1477
+ );
1478
+ }
1479
+ return credit;
1480
+ }
1481
+ };
1482
+
1483
+ // src/resources.ts
1484
+ var objectValue4 = (value) => typeof value === "object" && value !== null ? value : null;
1485
+ var resourceKinds2 = [
1486
+ "bare-metal",
1487
+ "solana-grpc",
1488
+ "solana-shredstream",
1489
+ "vps"
1490
+ ];
1491
+ var resourceModes2 = [
1492
+ "dedicated",
1493
+ "direct",
1494
+ "shared"
1495
+ ];
1496
+ var billingStatuses = [
1497
+ "active",
1498
+ "grace-period",
1499
+ "inactive",
1500
+ "suspended"
1501
+ ];
1502
+ var isDateTime2 = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
1503
+ var parseStatusBilling = (value) => {
1504
+ const billing = objectValue4(value);
1505
+ if (billing === null || typeof billing.status !== "string" || !billingStatuses.includes(
1506
+ billing.status
1507
+ ) || billing.hourlyCredits !== void 0 && (typeof billing.hourlyCredits !== "number" || !Number.isFinite(billing.hourlyCredits) || billing.hourlyCredits < 0) || billing.nextChargeAt !== void 0 && !isDateTime2(billing.nextChargeAt) || billing.graceEndsAt !== void 0 && !isDateTime2(billing.graceEndsAt)) return null;
1508
+ return {
1509
+ status: billing.status,
1510
+ ...typeof billing.hourlyCredits === "number" ? { hourlyCredits: billing.hourlyCredits } : {},
1511
+ ...typeof billing.nextChargeAt === "string" ? { nextChargeAt: billing.nextChargeAt } : {},
1512
+ ...typeof billing.graceEndsAt === "string" ? { graceEndsAt: billing.graceEndsAt } : {}
1513
+ };
1514
+ };
1515
+ var parseResourceStatus = (value) => {
1516
+ const status = objectValue4(value);
1517
+ if (status === null || typeof status.id !== "string" || typeof status.status !== "string") return null;
1518
+ const billing = status.billing === void 0 ? void 0 : parseStatusBilling(status.billing);
1519
+ if (status.billing !== void 0 && billing === null) return null;
1520
+ return {
1521
+ id: status.id,
1522
+ status: status.status,
1523
+ ...billing ? { billing } : {}
1524
+ };
1525
+ };
1526
+ var parseResource = (value) => {
1527
+ const resource = objectValue4(value);
1528
+ if (resource === null || typeof resource.id !== "string" || typeof resource.kind !== "string" || !resourceKinds2.includes(resource.kind) || typeof resource.status !== "string" || resource.mode !== void 0 && (typeof resource.mode !== "string" || !resourceModes2.includes(resource.mode)) || resource.name !== void 0 && typeof resource.name !== "string" || resource.region !== void 0 && typeof resource.region !== "string" || resource.createdAt !== void 0 && typeof resource.createdAt !== "string") return null;
1529
+ return {
1530
+ id: resource.id,
1531
+ kind: resource.kind,
1532
+ status: resource.status,
1533
+ ...typeof resource.mode === "string" ? { mode: resource.mode } : {},
1534
+ ...typeof resource.name === "string" ? { name: resource.name } : {},
1535
+ ...typeof resource.region === "string" ? { region: resource.region } : {},
1536
+ ...typeof resource.createdAt === "string" ? { createdAt: resource.createdAt } : {}
1537
+ };
1538
+ };
1539
+ var CloudResourcesClient = class {
1540
+ #transport;
1541
+ constructor(transport) {
1542
+ this.#transport = transport;
1543
+ }
1544
+ async list(options) {
1545
+ const response = await this.#transport.get(
1546
+ "/v4/cloud/resources",
1547
+ void 0,
1548
+ options
1549
+ );
1550
+ const envelope = objectValue4(response);
1551
+ const message = objectValue4(envelope?.message);
1552
+ if (envelope?.success !== true || !Array.isArray(message?.resources)) {
1553
+ throw new ErpcInvalidResponseError(
1554
+ "ERPC returned an invalid Cloud resource list"
1555
+ );
1556
+ }
1557
+ const resources = message.resources.map(parseResource);
1558
+ if (resources.some((resource) => resource === null)) {
1559
+ throw new ErpcInvalidResponseError(
1560
+ "ERPC returned an invalid Cloud resource list"
1561
+ );
1562
+ }
1563
+ return resources;
1564
+ }
1565
+ async get(resourceId, options) {
1566
+ const normalizedId = resourceId.trim();
1567
+ if (!normalizedId) {
1568
+ throw new ErpcConfigError("resourceId must not be empty");
1569
+ }
1570
+ const response = await this.#transport.get(
1571
+ `/v4/cloud/resources/${encodeURIComponent(normalizedId)}`,
1572
+ void 0,
1573
+ options
1574
+ );
1575
+ const envelope = objectValue4(response);
1576
+ const message = objectValue4(envelope?.message);
1577
+ const resource = envelope?.success === true ? parseResource(message?.resource) : null;
1578
+ if (resource === null) {
1579
+ throw new ErpcInvalidResponseError(
1580
+ "ERPC returned an invalid Cloud resource"
1581
+ );
1582
+ }
1583
+ return resource;
1584
+ }
1585
+ async getStatus(resourceId, options) {
1586
+ const normalizedId = resourceId.trim();
1587
+ if (!normalizedId) {
1588
+ throw new ErpcConfigError("resourceId must not be empty");
1589
+ }
1590
+ const response = await this.#transport.get(
1591
+ `/v4/cloud/resources/${encodeURIComponent(normalizedId)}/status`,
1592
+ void 0,
1593
+ options
1594
+ );
1595
+ const envelope = objectValue4(response);
1596
+ const status = envelope?.success === true ? parseResourceStatus(envelope.message) : null;
1597
+ if (status === null) {
1598
+ throw new ErpcInvalidResponseError(
1599
+ "ERPC returned an invalid Cloud resource status"
1600
+ );
1601
+ }
1602
+ return status;
1603
+ }
1604
+ };
1605
+
1606
+ // src/cloud.ts
1607
+ var requireFetch2 = (provided) => {
1608
+ const implementation = provided ?? globalThis.fetch;
1609
+ if (typeof implementation !== "function") {
1610
+ throw new ErpcConfigError(
1611
+ "A Fetch API implementation is required in this runtime"
1612
+ );
1613
+ }
1614
+ return implementation;
1615
+ };
1616
+ var cloudEndpoint = (value) => {
1617
+ let endpoint;
1618
+ try {
1619
+ endpoint = new URL(value ?? DEFAULT_USER_ENDPOINT);
1620
+ } catch {
1621
+ throw new ErpcConfigError("endpoint must be an absolute HTTP(S) URL");
1622
+ }
1623
+ const isLocalHttp = endpoint.protocol === "http:" && ["127.0.0.1", "::1", "[::1]", "localhost"].includes(endpoint.hostname);
1624
+ if (endpoint.protocol !== "https:" && !isLocalHttp) {
1625
+ throw new ErpcConfigError("endpoint must use HTTPS except on localhost");
1626
+ }
1627
+ endpoint.search = "";
1628
+ endpoint.hash = "";
1629
+ endpoint.pathname = endpoint.pathname.replace(/\/+$/, "") || "/";
1630
+ return endpoint;
1631
+ };
1632
+ var createErpcCloudClient = (config) => {
1633
+ const accessToken = config.accessToken.trim();
1634
+ if (!accessToken) {
1635
+ throw new ErpcConfigError("accessToken must not be empty");
1636
+ }
1637
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1638
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1639
+ throw new ErpcConfigError("timeoutMs must be a positive finite number");
1640
+ }
1641
+ const transport = new RestTransport({
1642
+ apiKey: accessToken,
1643
+ endpoint: cloudEndpoint(config.endpoint),
1644
+ fetch: requireFetch2(config.fetch),
1645
+ headers: config.headers ?? {},
1646
+ timeoutMs
1647
+ });
1648
+ return {
1649
+ catalog: new CloudCatalogClient(transport),
1650
+ credit: new CloudCreditClient(transport),
1651
+ resources: new CloudResourcesClient(transport),
1652
+ usage: new UsageClient(transport)
1653
+ };
1654
+ };
1655
+
1257
1656
  exports.AccountClient = AccountClient;
1657
+ exports.CloudCatalogClient = CloudCatalogClient;
1658
+ exports.CloudCreditClient = CloudCreditClient;
1659
+ exports.CloudResourcesClient = CloudResourcesClient;
1258
1660
  exports.DEFAULT_ACCOUNT_ENDPOINT = DEFAULT_ACCOUNT_ENDPOINT;
1259
1661
  exports.DEFAULT_ENDPOINT = DEFAULT_ENDPOINT;
1260
1662
  exports.DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;
1663
+ exports.DEFAULT_USER_ENDPOINT = DEFAULT_USER_ENDPOINT;
1261
1664
  exports.ETHEREUM_RPC_METHODS = ETHEREUM_RPC_METHODS;
1262
1665
  exports.ETHEREUM_SUBSCRIPTION_METHODS = ETHEREUM_SUBSCRIPTION_METHODS;
1263
1666
  exports.ErpcAbortedError = ErpcAbortedError;
@@ -1281,6 +1684,8 @@ exports.SOLANA_HISTORY_METHODS = SOLANA_HISTORY_METHODS;
1281
1684
  exports.SOLANA_LEADER_METHODS = SOLANA_LEADER_METHODS;
1282
1685
  exports.SOLANA_RPC_METHODS = SOLANA_RPC_METHODS;
1283
1686
  exports.SolanaSubscriptions = SolanaSubscriptions;
1687
+ exports.UsageClient = UsageClient;
1284
1688
  exports.createErpcClient = createErpcClient;
1689
+ exports.createErpcCloudClient = createErpcCloudClient;
1285
1690
  //# sourceMappingURL=index.cjs.map
1286
1691
  //# sourceMappingURL=index.cjs.map