lexmount 0.2.7 → 0.5.2

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.d.mts CHANGED
@@ -106,6 +106,12 @@ interface LexmountConfig {
106
106
  * Defaults to `https://api.lexmount.cn`.
107
107
  */
108
108
  baseUrl?: string;
109
+ /**
110
+ * Region ID to select from the public endpoint catalog.
111
+ *
112
+ * If omitted, the SDK uses the catalog default region when available.
113
+ */
114
+ region?: string;
109
115
  /**
110
116
  * Request timeout in milliseconds.
111
117
  *
@@ -117,6 +123,30 @@ interface LexmountConfig {
117
123
  */
118
124
  logLevel?: LogLevel;
119
125
  }
126
+ interface RegionCatalogEntry {
127
+ region_id: string;
128
+ display_name?: string;
129
+ default?: boolean;
130
+ host: string;
131
+ tags?: string[];
132
+ probe_path?: string;
133
+ }
134
+ interface RegionInfo {
135
+ requestedRegion?: string;
136
+ selectedRegion?: string;
137
+ baseUrl: string;
138
+ endpointBaseUrl?: string;
139
+ host?: string;
140
+ resolved: boolean;
141
+ usingRegion: boolean;
142
+ }
143
+ interface CatalogInfo {
144
+ baseUrl: string;
145
+ available: boolean;
146
+ statusCode?: number;
147
+ regions: RegionCatalogEntry[];
148
+ error?: string;
149
+ }
120
150
  /**
121
151
  * Session creation options.
122
152
  */
@@ -141,6 +171,28 @@ interface SessionCreateOptions {
141
171
  * Optional upstream proxy configuration.
142
172
  */
143
173
  proxy?: SessionProxyConfig;
174
+ /**
175
+ * Forward weak_lock to the API when creating sessions with read-write contexts.
176
+ */
177
+ weakLock?: boolean;
178
+ /**
179
+ * Use the async create API (`POST /instance/v2`) and poll until active.
180
+ *
181
+ * Defaults to true. Set to false to use the legacy synchronous `POST /instance`.
182
+ */
183
+ asyncCreate?: boolean;
184
+ /**
185
+ * Delay between async create status polls in milliseconds.
186
+ *
187
+ * Defaults to 1000.
188
+ */
189
+ pollIntervalMs?: number;
190
+ /**
191
+ * Maximum time to wait for async create activation in milliseconds.
192
+ *
193
+ * Defaults to 600000.
194
+ */
195
+ pollTimeoutMs?: number;
144
196
  }
145
197
  /**
146
198
  * Session list options.
@@ -536,6 +588,7 @@ declare class SessionsResource {
536
588
  * Create a new browser session.
537
589
  */
538
590
  create(options?: SessionCreateOptions): Promise<SessionCreateResponse>;
591
+ private createAsync;
539
592
  /**
540
593
  * Fetch one session by id.
541
594
  *
@@ -592,6 +645,12 @@ declare class Lexmount {
592
645
  * API base URL.
593
646
  */
594
647
  readonly baseUrl: string;
648
+ readonly region?: string;
649
+ selectedRegion?: string;
650
+ private endpointBaseUrl?;
651
+ private selectedHost?;
652
+ private regionResolutionAttempted;
653
+ private regionResolutionPromise?;
595
654
  /**
596
655
  * Session operations.
597
656
  */
@@ -624,6 +683,8 @@ declare class Lexmount {
624
683
  * @internal
625
684
  */
626
685
  _delete<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
686
+ regionInfo(): Promise<RegionInfo>;
687
+ catalogInfo(): Promise<CatalogInfo>;
627
688
  /**
628
689
  * Close the client.
629
690
  *
@@ -637,6 +698,12 @@ declare class Lexmount {
637
698
  private request;
638
699
  private normalizeRequestError;
639
700
  private getDefaultHeaders;
701
+ private ensureRegionResolved;
702
+ private resolveRegion;
703
+ private selectCatalogRegion;
704
+ private probeRegionHost;
705
+ private isAllowedCatalogHost;
706
+ private rewriteUrl;
640
707
  }
641
708
 
642
709
  /**
@@ -704,6 +771,6 @@ declare class TimeoutError extends LexmountError {
704
771
  /**
705
772
  * Lexmount Node.js SDK.
706
773
  */
707
- declare const VERSION = "0.2.5";
774
+ declare const VERSION = "0.5.2";
708
775
 
709
- export { APIError, AuthenticationError, type BrowserMode, type ContextAccessMode, type ContextCreateOptions, ContextInfo, type ContextListOptions, ContextListResponse, ContextLockedError, type ContextMetadata, ContextNotFoundError, type ContextStatus, ContextsResource, ExtensionInfo, type ExtensionInfoShape, type ExtensionListOptions, type ExtensionUploadOptions, ExtensionsResource, type ForceReleaseResponse, Lexmount, type LexmountConfig, LexmountError, LexmountLogger, type LogLevel, NetworkError, PaginationInfo, type PaginationInfoShape, type SessionContext, type SessionCreateOptions, type SessionCreateResponse, type SessionDeleteOptions, SessionDownloadInfo, type SessionDownloadInfoShape, SessionDownloadsDeleteResponse, type SessionDownloadsDeleteResponseShape, SessionDownloadsListResponse, type SessionDownloadsListResponseShape, SessionDownloadsResource, SessionInfo, type SessionListOptions, SessionListResponse, SessionNotFoundError, type SessionProxyConfig, type SessionStatus, SessionTargetInfo, type SessionTargetInfoShape, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
776
+ export { APIError, AuthenticationError, type BrowserMode, type CatalogInfo, type ContextAccessMode, type ContextCreateOptions, ContextInfo, type ContextListOptions, ContextListResponse, ContextLockedError, type ContextMetadata, ContextNotFoundError, type ContextStatus, ContextsResource, ExtensionInfo, type ExtensionInfoShape, type ExtensionListOptions, type ExtensionUploadOptions, ExtensionsResource, type ForceReleaseResponse, Lexmount, type LexmountConfig, LexmountError, LexmountLogger, type LogLevel, NetworkError, PaginationInfo, type PaginationInfoShape, type RegionCatalogEntry, type RegionInfo, type SessionContext, type SessionCreateOptions, type SessionCreateResponse, type SessionDeleteOptions, SessionDownloadInfo, type SessionDownloadInfoShape, SessionDownloadsDeleteResponse, type SessionDownloadsDeleteResponseShape, SessionDownloadsListResponse, type SessionDownloadsListResponseShape, SessionDownloadsResource, SessionInfo, type SessionListOptions, SessionListResponse, SessionNotFoundError, type SessionProxyConfig, type SessionStatus, SessionTargetInfo, type SessionTargetInfoShape, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
package/dist/index.d.ts CHANGED
@@ -106,6 +106,12 @@ interface LexmountConfig {
106
106
  * Defaults to `https://api.lexmount.cn`.
107
107
  */
108
108
  baseUrl?: string;
109
+ /**
110
+ * Region ID to select from the public endpoint catalog.
111
+ *
112
+ * If omitted, the SDK uses the catalog default region when available.
113
+ */
114
+ region?: string;
109
115
  /**
110
116
  * Request timeout in milliseconds.
111
117
  *
@@ -117,6 +123,30 @@ interface LexmountConfig {
117
123
  */
118
124
  logLevel?: LogLevel;
119
125
  }
126
+ interface RegionCatalogEntry {
127
+ region_id: string;
128
+ display_name?: string;
129
+ default?: boolean;
130
+ host: string;
131
+ tags?: string[];
132
+ probe_path?: string;
133
+ }
134
+ interface RegionInfo {
135
+ requestedRegion?: string;
136
+ selectedRegion?: string;
137
+ baseUrl: string;
138
+ endpointBaseUrl?: string;
139
+ host?: string;
140
+ resolved: boolean;
141
+ usingRegion: boolean;
142
+ }
143
+ interface CatalogInfo {
144
+ baseUrl: string;
145
+ available: boolean;
146
+ statusCode?: number;
147
+ regions: RegionCatalogEntry[];
148
+ error?: string;
149
+ }
120
150
  /**
121
151
  * Session creation options.
122
152
  */
@@ -141,6 +171,28 @@ interface SessionCreateOptions {
141
171
  * Optional upstream proxy configuration.
142
172
  */
143
173
  proxy?: SessionProxyConfig;
174
+ /**
175
+ * Forward weak_lock to the API when creating sessions with read-write contexts.
176
+ */
177
+ weakLock?: boolean;
178
+ /**
179
+ * Use the async create API (`POST /instance/v2`) and poll until active.
180
+ *
181
+ * Defaults to true. Set to false to use the legacy synchronous `POST /instance`.
182
+ */
183
+ asyncCreate?: boolean;
184
+ /**
185
+ * Delay between async create status polls in milliseconds.
186
+ *
187
+ * Defaults to 1000.
188
+ */
189
+ pollIntervalMs?: number;
190
+ /**
191
+ * Maximum time to wait for async create activation in milliseconds.
192
+ *
193
+ * Defaults to 600000.
194
+ */
195
+ pollTimeoutMs?: number;
144
196
  }
145
197
  /**
146
198
  * Session list options.
@@ -536,6 +588,7 @@ declare class SessionsResource {
536
588
  * Create a new browser session.
537
589
  */
538
590
  create(options?: SessionCreateOptions): Promise<SessionCreateResponse>;
591
+ private createAsync;
539
592
  /**
540
593
  * Fetch one session by id.
541
594
  *
@@ -592,6 +645,12 @@ declare class Lexmount {
592
645
  * API base URL.
593
646
  */
594
647
  readonly baseUrl: string;
648
+ readonly region?: string;
649
+ selectedRegion?: string;
650
+ private endpointBaseUrl?;
651
+ private selectedHost?;
652
+ private regionResolutionAttempted;
653
+ private regionResolutionPromise?;
595
654
  /**
596
655
  * Session operations.
597
656
  */
@@ -624,6 +683,8 @@ declare class Lexmount {
624
683
  * @internal
625
684
  */
626
685
  _delete<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
686
+ regionInfo(): Promise<RegionInfo>;
687
+ catalogInfo(): Promise<CatalogInfo>;
627
688
  /**
628
689
  * Close the client.
629
690
  *
@@ -637,6 +698,12 @@ declare class Lexmount {
637
698
  private request;
638
699
  private normalizeRequestError;
639
700
  private getDefaultHeaders;
701
+ private ensureRegionResolved;
702
+ private resolveRegion;
703
+ private selectCatalogRegion;
704
+ private probeRegionHost;
705
+ private isAllowedCatalogHost;
706
+ private rewriteUrl;
640
707
  }
641
708
 
642
709
  /**
@@ -704,6 +771,6 @@ declare class TimeoutError extends LexmountError {
704
771
  /**
705
772
  * Lexmount Node.js SDK.
706
773
  */
707
- declare const VERSION = "0.2.5";
774
+ declare const VERSION = "0.5.2";
708
775
 
709
- export { APIError, AuthenticationError, type BrowserMode, type ContextAccessMode, type ContextCreateOptions, ContextInfo, type ContextListOptions, ContextListResponse, ContextLockedError, type ContextMetadata, ContextNotFoundError, type ContextStatus, ContextsResource, ExtensionInfo, type ExtensionInfoShape, type ExtensionListOptions, type ExtensionUploadOptions, ExtensionsResource, type ForceReleaseResponse, Lexmount, type LexmountConfig, LexmountError, LexmountLogger, type LogLevel, NetworkError, PaginationInfo, type PaginationInfoShape, type SessionContext, type SessionCreateOptions, type SessionCreateResponse, type SessionDeleteOptions, SessionDownloadInfo, type SessionDownloadInfoShape, SessionDownloadsDeleteResponse, type SessionDownloadsDeleteResponseShape, SessionDownloadsListResponse, type SessionDownloadsListResponseShape, SessionDownloadsResource, SessionInfo, type SessionListOptions, SessionListResponse, SessionNotFoundError, type SessionProxyConfig, type SessionStatus, SessionTargetInfo, type SessionTargetInfoShape, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
776
+ export { APIError, AuthenticationError, type BrowserMode, type CatalogInfo, type ContextAccessMode, type ContextCreateOptions, ContextInfo, type ContextListOptions, ContextListResponse, ContextLockedError, type ContextMetadata, ContextNotFoundError, type ContextStatus, ContextsResource, ExtensionInfo, type ExtensionInfoShape, type ExtensionListOptions, type ExtensionUploadOptions, ExtensionsResource, type ForceReleaseResponse, Lexmount, type LexmountConfig, LexmountError, LexmountLogger, type LogLevel, NetworkError, PaginationInfo, type PaginationInfoShape, type RegionCatalogEntry, type RegionInfo, type SessionContext, type SessionCreateOptions, type SessionCreateResponse, type SessionDeleteOptions, SessionDownloadInfo, type SessionDownloadInfoShape, SessionDownloadsDeleteResponse, type SessionDownloadsDeleteResponseShape, SessionDownloadsListResponse, type SessionDownloadsListResponseShape, SessionDownloadsResource, SessionInfo, type SessionListOptions, SessionListResponse, SessionNotFoundError, type SessionProxyConfig, type SessionStatus, SessionTargetInfo, type SessionTargetInfoShape, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
package/dist/index.js CHANGED
@@ -620,6 +620,11 @@ function normalizeContextMode(mode) {
620
620
  }
621
621
  return "read_only";
622
622
  }
623
+ function delay(ms) {
624
+ return new Promise((resolve) => {
625
+ setTimeout(resolve, ms);
626
+ });
627
+ }
623
628
  var PaginationInfo = class {
624
629
  constructor(shape) {
625
630
  this.currentPage = shape.currentPage;
@@ -851,7 +856,6 @@ var SessionsResource = class {
851
856
  * Create a new browser session.
852
857
  */
853
858
  async create(options = {}) {
854
- const url = `${this.client.baseUrl}/instance`;
855
859
  const payload = {
856
860
  api_key: this.client.apiKey,
857
861
  project_id: options.projectId ?? this.client.projectId,
@@ -875,6 +879,13 @@ var SessionsResource = class {
875
879
  if (options.proxy) {
876
880
  payload.proxy = this.normalizeProxy(options.proxy);
877
881
  }
882
+ if (options.weakLock) {
883
+ payload.weak_lock = true;
884
+ }
885
+ if (options.asyncCreate !== false) {
886
+ return this.createAsync(payload, options);
887
+ }
888
+ const url = `${this.client.baseUrl}/instance`;
878
889
  const response = await this.client._post(url, payload);
879
890
  if (response.status >= 400) {
880
891
  this.handleCreateError(response);
@@ -905,6 +916,59 @@ var SessionsResource = class {
905
916
  client: this.client
906
917
  });
907
918
  }
919
+ async createAsync(payload, options) {
920
+ const response = await this.client._post(`${this.client.baseUrl}/instance/v2`, payload);
921
+ if (response.status >= 400) {
922
+ this.handleCreateError(response);
923
+ }
924
+ const result = asRecord3(response.data);
925
+ const sessionId = getString3(result.session_id);
926
+ if (!sessionId) {
927
+ throw new APIError("Failed to create session: session_id missing from response", {
928
+ statusCode: response.status,
929
+ response: response.data
930
+ });
931
+ }
932
+ const projectId = options.projectId ?? this.client.projectId;
933
+ const pollIntervalMs = options.pollIntervalMs ?? 1e3;
934
+ const pollTimeoutMs = options.pollTimeoutMs ?? 6e5;
935
+ const deadline = Date.now() + pollTimeoutMs;
936
+ while (Date.now() < deadline) {
937
+ const info = await this.get(sessionId, projectId);
938
+ if (info.status === "active") {
939
+ const wsUrl = await this._getWebSocketDebuggerUrl(sessionId);
940
+ getLogger().info(`Session created successfully (async): id=${sessionId}`);
941
+ return new SessionInfo({
942
+ id: sessionId,
943
+ status: "active",
944
+ apiKey: this.client.apiKey,
945
+ projectId,
946
+ browserType: info.browserType || (options.browserMode ?? "normal"),
947
+ createdAt: info.createdAt,
948
+ inspectUrl: info.inspectUrl,
949
+ containerId: info.containerId,
950
+ ws: wsUrl ?? info.ws,
951
+ client: this.client
952
+ });
953
+ }
954
+ if (info.status === "create_failed") {
955
+ throw new APIError("Session creation failed", {
956
+ statusCode: 500,
957
+ response: { session_id: sessionId, status: info.status }
958
+ });
959
+ }
960
+ if (info.status === "closed") {
961
+ throw new APIError("Session closed before activation", {
962
+ statusCode: 500,
963
+ response: { session_id: sessionId, status: info.status }
964
+ });
965
+ }
966
+ await delay(pollIntervalMs);
967
+ }
968
+ throw new TimeoutError(
969
+ `Timed out waiting for session ${sessionId} to become active after ${pollTimeoutMs}ms`
970
+ );
971
+ }
908
972
  /**
909
973
  * Fetch one session by id.
910
974
  *
@@ -1159,6 +1223,7 @@ var SessionsResource = class {
1159
1223
  dotenv.config();
1160
1224
  var Lexmount = class {
1161
1225
  constructor(config2 = {}) {
1226
+ this.regionResolutionAttempted = false;
1162
1227
  this.apiKey = config2.apiKey ?? process.env.LEXMOUNT_API_KEY ?? "";
1163
1228
  if (!this.apiKey) {
1164
1229
  throw new ValidationError(
@@ -1172,6 +1237,7 @@ var Lexmount = class {
1172
1237
  );
1173
1238
  }
1174
1239
  this.baseUrl = (config2.baseUrl ?? process.env.LEXMOUNT_BASE_URL ?? "https://api.lexmount.cn").replace(/\/$/, "");
1240
+ this.region = config2.region;
1175
1241
  if (config2.logLevel) {
1176
1242
  setLogLevel(config2.logLevel);
1177
1243
  }
@@ -1189,6 +1255,7 @@ var Lexmount = class {
1189
1255
  * @internal
1190
1256
  */
1191
1257
  async _post(url, data, config2 = {}) {
1258
+ await this.ensureRegionResolved();
1192
1259
  return this.request("POST", url, { ...config2, data });
1193
1260
  }
1194
1261
  /**
@@ -1197,6 +1264,7 @@ var Lexmount = class {
1197
1264
  * @internal
1198
1265
  */
1199
1266
  async _get(url, params, config2 = {}) {
1267
+ await this.ensureRegionResolved();
1200
1268
  return this.request("GET", url, { ...config2, params });
1201
1269
  }
1202
1270
  /**
@@ -1205,8 +1273,51 @@ var Lexmount = class {
1205
1273
  * @internal
1206
1274
  */
1207
1275
  async _delete(url, data, config2 = {}) {
1276
+ await this.ensureRegionResolved();
1208
1277
  return this.request("DELETE", url, { ...config2, data });
1209
1278
  }
1279
+ async regionInfo() {
1280
+ await this.ensureRegionResolved();
1281
+ return {
1282
+ requestedRegion: this.region,
1283
+ selectedRegion: this.selectedRegion,
1284
+ baseUrl: this.baseUrl,
1285
+ endpointBaseUrl: this.endpointBaseUrl,
1286
+ host: this.selectedHost,
1287
+ resolved: this.regionResolutionAttempted,
1288
+ usingRegion: this.selectedRegion !== void 0
1289
+ };
1290
+ }
1291
+ async catalogInfo() {
1292
+ try {
1293
+ const response = await this.httpClient.get(
1294
+ `${this.baseUrl}/v1/regions/catalog`
1295
+ );
1296
+ if (response.status !== 200) {
1297
+ return {
1298
+ baseUrl: this.baseUrl,
1299
+ available: false,
1300
+ statusCode: response.status,
1301
+ regions: []
1302
+ };
1303
+ }
1304
+ const regions = Array.isArray(response.data?.regions) ? response.data.regions : [];
1305
+ return {
1306
+ baseUrl: this.baseUrl,
1307
+ available: Array.isArray(response.data?.regions),
1308
+ statusCode: response.status,
1309
+ regions,
1310
+ error: Array.isArray(response.data?.regions) ? void 0 : "invalid catalog regions"
1311
+ };
1312
+ } catch (error) {
1313
+ return {
1314
+ baseUrl: this.baseUrl,
1315
+ available: false,
1316
+ regions: [],
1317
+ error: error instanceof Error ? error.message : String(error)
1318
+ };
1319
+ }
1320
+ }
1210
1321
  /**
1211
1322
  * Close the client.
1212
1323
  *
@@ -1224,7 +1335,8 @@ var Lexmount = class {
1224
1335
  async request(method, url, config2) {
1225
1336
  const logger2 = getLogger();
1226
1337
  const startTime = Date.now();
1227
- logger2.debug(`${method} request to ${url}`);
1338
+ const requestUrl = this.rewriteUrl(url);
1339
+ logger2.debug(`${method} request to ${requestUrl}`);
1228
1340
  try {
1229
1341
  const headers = {
1230
1342
  api_key: this.apiKey,
@@ -1234,12 +1346,14 @@ var Lexmount = class {
1234
1346
  };
1235
1347
  const response = await this.httpClient.request({
1236
1348
  method,
1237
- url,
1349
+ url: requestUrl,
1238
1350
  ...config2,
1239
1351
  headers
1240
1352
  });
1241
1353
  const elapsed = Date.now() - startTime;
1242
- logger2.debug(`${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`);
1354
+ logger2.debug(
1355
+ `${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`
1356
+ );
1243
1357
  return response;
1244
1358
  } catch (error) {
1245
1359
  const elapsed = Date.now() - startTime;
@@ -1278,10 +1392,101 @@ var Lexmount = class {
1278
1392
  "Content-Type": "application/json"
1279
1393
  };
1280
1394
  }
1395
+ async ensureRegionResolved() {
1396
+ if (this.regionResolutionAttempted) {
1397
+ return;
1398
+ }
1399
+ if (!this.regionResolutionPromise) {
1400
+ this.regionResolutionPromise = this.resolveRegion().finally(() => {
1401
+ this.regionResolutionAttempted = true;
1402
+ this.regionResolutionPromise = void 0;
1403
+ });
1404
+ }
1405
+ await this.regionResolutionPromise;
1406
+ }
1407
+ async resolveRegion() {
1408
+ const logger2 = getLogger();
1409
+ try {
1410
+ const response = await this.httpClient.get(
1411
+ `${this.baseUrl}/v1/regions/catalog`
1412
+ );
1413
+ if (response.status !== 200 || !Array.isArray(response.data?.regions)) {
1414
+ logger2.debug(
1415
+ `Region catalog unavailable, falling back to baseUrl: status=${response.status}`
1416
+ );
1417
+ return;
1418
+ }
1419
+ const selected = this.selectCatalogRegion(response.data.regions);
1420
+ if (!selected) {
1421
+ if (this.region) {
1422
+ logger2.warn(`Requested region not found in catalog: ${this.region}`);
1423
+ } else {
1424
+ logger2.debug("No default catalog region, falling back to baseUrl");
1425
+ }
1426
+ return;
1427
+ }
1428
+ const endpointBaseUrl = await this.probeRegionHost(selected);
1429
+ if (!endpointBaseUrl) {
1430
+ logger2.debug("Region probe failed, falling back to baseUrl");
1431
+ return;
1432
+ }
1433
+ this.selectedRegion = selected.region_id;
1434
+ this.selectedHost = selected.host;
1435
+ this.endpointBaseUrl = endpointBaseUrl;
1436
+ } catch (error) {
1437
+ logger2.debug("Region resolution failed, falling back to baseUrl:", error);
1438
+ }
1439
+ }
1440
+ selectCatalogRegion(regions) {
1441
+ if (this.region) {
1442
+ return regions.find((region) => region.region_id === this.region);
1443
+ }
1444
+ const defaultRegions = regions.filter((region) => region.default === true);
1445
+ return defaultRegions.length === 1 ? defaultRegions[0] : void 0;
1446
+ }
1447
+ async probeRegionHost(region) {
1448
+ const logger2 = getLogger();
1449
+ const host = String(region.host || "").trim();
1450
+ if (!host) {
1451
+ return void 0;
1452
+ }
1453
+ if (!this.isAllowedCatalogHost(host)) {
1454
+ logger2.warn(`Ignoring invalid region catalog host: ${host}`);
1455
+ return void 0;
1456
+ }
1457
+ const endpointBaseUrl = `https://${host}`;
1458
+ const probePath = String(region.probe_path || "/v1/region/probe").replace(/^(?!\/)/, "/");
1459
+ try {
1460
+ const response = await this.httpClient.get(`${endpointBaseUrl}${probePath}`);
1461
+ return response.status === 200 ? endpointBaseUrl : void 0;
1462
+ } catch {
1463
+ return void 0;
1464
+ }
1465
+ }
1466
+ isAllowedCatalogHost(host) {
1467
+ let parsed;
1468
+ try {
1469
+ parsed = new URL(`https://${host}`);
1470
+ } catch {
1471
+ return false;
1472
+ }
1473
+ if (parsed.username || parsed.password || parsed.port || parsed.pathname !== "/" || parsed.search || parsed.hash) {
1474
+ return false;
1475
+ }
1476
+ const hostname = parsed.hostname.toLowerCase();
1477
+ const allowedDomains = ["lexmount.cn", "lexmount.com", "lexmount.net"];
1478
+ return allowedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
1479
+ }
1480
+ rewriteUrl(url) {
1481
+ if (!this.endpointBaseUrl || !url.startsWith(this.baseUrl)) {
1482
+ return url;
1483
+ }
1484
+ return `${this.endpointBaseUrl}${url.slice(this.baseUrl.length)}`;
1485
+ }
1281
1486
  };
1282
1487
 
1283
1488
  // src/index.ts
1284
- var VERSION = "0.2.5";
1489
+ var VERSION = "0.5.2";
1285
1490
  // Annotate the CommonJS export names for ESM import in node:
1286
1491
  0 && (module.exports = {
1287
1492
  APIError,