lexmount 0.2.6 → 0.5.1

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
  */
@@ -269,6 +299,19 @@ interface SessionDownloadsDeleteResponseShape {
269
299
  status: string;
270
300
  deletedCount: number;
271
301
  }
302
+ /**
303
+ * Session target metadata returned by `/json`.
304
+ */
305
+ interface SessionTargetInfoShape {
306
+ id: string;
307
+ title: string;
308
+ type: string;
309
+ url: string;
310
+ description: string;
311
+ inspectUrl: string | null;
312
+ webSocketDebuggerUrl: string | null;
313
+ webSocketDebuggerUrlTransformed: string | null;
314
+ }
272
315
  /**
273
316
  * Session pagination metadata.
274
317
  */
@@ -482,6 +525,20 @@ declare class SessionDownloadsDeleteResponse implements SessionDownloadsDeleteRe
482
525
  readonly deletedCount: number;
483
526
  constructor(shape: SessionDownloadsDeleteResponseShape);
484
527
  }
528
+ /**
529
+ * Session target metadata returned by `/json`.
530
+ */
531
+ declare class SessionTargetInfo implements SessionTargetInfoShape {
532
+ readonly id: string;
533
+ readonly title: string;
534
+ readonly type: string;
535
+ readonly url: string;
536
+ readonly description: string;
537
+ readonly inspectUrl: string | null;
538
+ readonly webSocketDebuggerUrl: string | null;
539
+ readonly webSocketDebuggerUrlTransformed: string | null;
540
+ constructor(shape: SessionTargetInfoShape);
541
+ }
485
542
  /**
486
543
  * Session download operations.
487
544
  */
@@ -524,6 +581,10 @@ declare class SessionsResource {
524
581
  * Delete a browser session.
525
582
  */
526
583
  delete(options: SessionDeleteOptions): Promise<void>;
584
+ /**
585
+ * List target/page metadata for a session via `/json`.
586
+ */
587
+ listTargets(sessionId: string): Promise<SessionTargetInfo[]>;
527
588
  /**
528
589
  * Fetch the debugger WebSocket URL for a session.
529
590
  *
@@ -534,8 +595,10 @@ declare class SessionsResource {
534
595
  private handleCreateError;
535
596
  private handleGetError;
536
597
  private handleListError;
598
+ private handleListTargetsError;
537
599
  private handleDeleteError;
538
600
  private mapSessionInfo;
601
+ private mapSessionTarget;
539
602
  private _getCreatedSession;
540
603
  }
541
604
 
@@ -559,6 +622,12 @@ declare class Lexmount {
559
622
  * API base URL.
560
623
  */
561
624
  readonly baseUrl: string;
625
+ readonly region?: string;
626
+ selectedRegion?: string;
627
+ private endpointBaseUrl?;
628
+ private selectedHost?;
629
+ private regionResolutionAttempted;
630
+ private regionResolutionPromise?;
562
631
  /**
563
632
  * Session operations.
564
633
  */
@@ -591,6 +660,8 @@ declare class Lexmount {
591
660
  * @internal
592
661
  */
593
662
  _delete<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
663
+ regionInfo(): Promise<RegionInfo>;
664
+ catalogInfo(): Promise<CatalogInfo>;
594
665
  /**
595
666
  * Close the client.
596
667
  *
@@ -604,6 +675,12 @@ declare class Lexmount {
604
675
  private request;
605
676
  private normalizeRequestError;
606
677
  private getDefaultHeaders;
678
+ private ensureRegionResolved;
679
+ private resolveRegion;
680
+ private selectCatalogRegion;
681
+ private probeRegionHost;
682
+ private isAllowedCatalogHost;
683
+ private rewriteUrl;
607
684
  }
608
685
 
609
686
  /**
@@ -671,6 +748,6 @@ declare class TimeoutError extends LexmountError {
671
748
  /**
672
749
  * Lexmount Node.js SDK.
673
750
  */
674
- declare const VERSION = "0.2.5";
751
+ declare const VERSION = "0.5.1";
675
752
 
676
- 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, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
753
+ 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
  */
@@ -269,6 +299,19 @@ interface SessionDownloadsDeleteResponseShape {
269
299
  status: string;
270
300
  deletedCount: number;
271
301
  }
302
+ /**
303
+ * Session target metadata returned by `/json`.
304
+ */
305
+ interface SessionTargetInfoShape {
306
+ id: string;
307
+ title: string;
308
+ type: string;
309
+ url: string;
310
+ description: string;
311
+ inspectUrl: string | null;
312
+ webSocketDebuggerUrl: string | null;
313
+ webSocketDebuggerUrlTransformed: string | null;
314
+ }
272
315
  /**
273
316
  * Session pagination metadata.
274
317
  */
@@ -482,6 +525,20 @@ declare class SessionDownloadsDeleteResponse implements SessionDownloadsDeleteRe
482
525
  readonly deletedCount: number;
483
526
  constructor(shape: SessionDownloadsDeleteResponseShape);
484
527
  }
528
+ /**
529
+ * Session target metadata returned by `/json`.
530
+ */
531
+ declare class SessionTargetInfo implements SessionTargetInfoShape {
532
+ readonly id: string;
533
+ readonly title: string;
534
+ readonly type: string;
535
+ readonly url: string;
536
+ readonly description: string;
537
+ readonly inspectUrl: string | null;
538
+ readonly webSocketDebuggerUrl: string | null;
539
+ readonly webSocketDebuggerUrlTransformed: string | null;
540
+ constructor(shape: SessionTargetInfoShape);
541
+ }
485
542
  /**
486
543
  * Session download operations.
487
544
  */
@@ -524,6 +581,10 @@ declare class SessionsResource {
524
581
  * Delete a browser session.
525
582
  */
526
583
  delete(options: SessionDeleteOptions): Promise<void>;
584
+ /**
585
+ * List target/page metadata for a session via `/json`.
586
+ */
587
+ listTargets(sessionId: string): Promise<SessionTargetInfo[]>;
527
588
  /**
528
589
  * Fetch the debugger WebSocket URL for a session.
529
590
  *
@@ -534,8 +595,10 @@ declare class SessionsResource {
534
595
  private handleCreateError;
535
596
  private handleGetError;
536
597
  private handleListError;
598
+ private handleListTargetsError;
537
599
  private handleDeleteError;
538
600
  private mapSessionInfo;
601
+ private mapSessionTarget;
539
602
  private _getCreatedSession;
540
603
  }
541
604
 
@@ -559,6 +622,12 @@ declare class Lexmount {
559
622
  * API base URL.
560
623
  */
561
624
  readonly baseUrl: string;
625
+ readonly region?: string;
626
+ selectedRegion?: string;
627
+ private endpointBaseUrl?;
628
+ private selectedHost?;
629
+ private regionResolutionAttempted;
630
+ private regionResolutionPromise?;
562
631
  /**
563
632
  * Session operations.
564
633
  */
@@ -591,6 +660,8 @@ declare class Lexmount {
591
660
  * @internal
592
661
  */
593
662
  _delete<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
663
+ regionInfo(): Promise<RegionInfo>;
664
+ catalogInfo(): Promise<CatalogInfo>;
594
665
  /**
595
666
  * Close the client.
596
667
  *
@@ -604,6 +675,12 @@ declare class Lexmount {
604
675
  private request;
605
676
  private normalizeRequestError;
606
677
  private getDefaultHeaders;
678
+ private ensureRegionResolved;
679
+ private resolveRegion;
680
+ private selectCatalogRegion;
681
+ private probeRegionHost;
682
+ private isAllowedCatalogHost;
683
+ private rewriteUrl;
607
684
  }
608
685
 
609
686
  /**
@@ -671,6 +748,6 @@ declare class TimeoutError extends LexmountError {
671
748
  /**
672
749
  * Lexmount Node.js SDK.
673
750
  */
674
- declare const VERSION = "0.2.5";
751
+ declare const VERSION = "0.5.1";
675
752
 
676
- 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, SessionsResource, TimeoutError, VERSION, ValidationError, Lexmount as default, disableLogging, enableLogging, getLogger, setLogLevel };
753
+ 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
@@ -51,6 +51,7 @@ __export(index_exports, {
51
51
  SessionInfo: () => SessionInfo,
52
52
  SessionListResponse: () => SessionListResponse,
53
53
  SessionNotFoundError: () => SessionNotFoundError,
54
+ SessionTargetInfo: () => SessionTargetInfo,
54
55
  SessionsResource: () => SessionsResource,
55
56
  TimeoutError: () => TimeoutError,
56
57
  VERSION: () => VERSION,
@@ -728,6 +729,18 @@ var SessionDownloadsDeleteResponse = class {
728
729
  this.deletedCount = shape.deletedCount;
729
730
  }
730
731
  };
732
+ var SessionTargetInfo = class {
733
+ constructor(shape) {
734
+ this.id = shape.id;
735
+ this.title = shape.title;
736
+ this.type = shape.type;
737
+ this.url = shape.url;
738
+ this.description = shape.description;
739
+ this.inspectUrl = shape.inspectUrl;
740
+ this.webSocketDebuggerUrl = shape.webSocketDebuggerUrl;
741
+ this.webSocketDebuggerUrlTransformed = shape.webSocketDebuggerUrlTransformed;
742
+ }
743
+ };
731
744
  var SessionDownloadsResource = class {
732
745
  constructor(client) {
733
746
  this.client = client;
@@ -958,6 +971,19 @@ var SessionsResource = class {
958
971
  }
959
972
  getLogger().info(`Session deleted successfully: ${options.sessionId}`);
960
973
  }
974
+ /**
975
+ * List target/page metadata for a session via `/json`.
976
+ */
977
+ async listTargets(sessionId) {
978
+ const response = await this.client._get(`${this.client.baseUrl}/json`, {
979
+ session_id: sessionId
980
+ });
981
+ if (response.status >= 400) {
982
+ this.handleListTargetsError(response, sessionId);
983
+ }
984
+ const result = Array.isArray(response.data) ? response.data : [];
985
+ return result.map((item) => this.mapSessionTarget(asRecord3(item)));
986
+ }
961
987
  /**
962
988
  * Fetch the debugger WebSocket URL for a session.
963
989
  *
@@ -1053,6 +1079,24 @@ var SessionsResource = class {
1053
1079
  response: response.data
1054
1080
  });
1055
1081
  }
1082
+ handleListTargetsError(response, sessionId) {
1083
+ const errorData = asRecord3(response.data);
1084
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
1085
+ if (response.status === 401) {
1086
+ throw new AuthenticationError(
1087
+ `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
1088
+ );
1089
+ }
1090
+ if (response.status === 404) {
1091
+ throw new SessionNotFoundError(
1092
+ `Session not found: ${errorMessage}. Session ID '${sessionId}' may not exist in this project.`
1093
+ );
1094
+ }
1095
+ throw new APIError(`Failed to list session targets: ${errorMessage}`, {
1096
+ statusCode: response.status,
1097
+ response: response.data
1098
+ });
1099
+ }
1056
1100
  handleDeleteError(response, sessionId) {
1057
1101
  const errorData = asRecord3(response.data);
1058
1102
  const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
@@ -1086,6 +1130,18 @@ var SessionsResource = class {
1086
1130
  client: this.client
1087
1131
  });
1088
1132
  }
1133
+ mapSessionTarget(raw) {
1134
+ return new SessionTargetInfo({
1135
+ id: getString3(raw.id) ?? "",
1136
+ title: getString3(raw.title) ?? "",
1137
+ type: getString3(raw.type) ?? "",
1138
+ url: getString3(raw.url) ?? "",
1139
+ description: getString3(raw.description) ?? "",
1140
+ inspectUrl: getString3(raw.inspectUrl) ?? getString3(raw.inspect_url) ?? null,
1141
+ webSocketDebuggerUrl: getString3(raw.webSocketDebuggerUrl) ?? getString3(raw.web_socket_debugger_url) ?? null,
1142
+ webSocketDebuggerUrlTransformed: getString3(raw.webSocketDebuggerUrlTransformed) ?? getString3(raw.web_socket_debugger_url_transformed) ?? null
1143
+ });
1144
+ }
1089
1145
  async _getCreatedSession(sessionId, projectId) {
1090
1146
  try {
1091
1147
  return await this.get(sessionId, projectId);
@@ -1103,6 +1159,7 @@ var SessionsResource = class {
1103
1159
  dotenv.config();
1104
1160
  var Lexmount = class {
1105
1161
  constructor(config2 = {}) {
1162
+ this.regionResolutionAttempted = false;
1106
1163
  this.apiKey = config2.apiKey ?? process.env.LEXMOUNT_API_KEY ?? "";
1107
1164
  if (!this.apiKey) {
1108
1165
  throw new ValidationError(
@@ -1116,6 +1173,7 @@ var Lexmount = class {
1116
1173
  );
1117
1174
  }
1118
1175
  this.baseUrl = (config2.baseUrl ?? process.env.LEXMOUNT_BASE_URL ?? "https://api.lexmount.cn").replace(/\/$/, "");
1176
+ this.region = config2.region;
1119
1177
  if (config2.logLevel) {
1120
1178
  setLogLevel(config2.logLevel);
1121
1179
  }
@@ -1133,6 +1191,7 @@ var Lexmount = class {
1133
1191
  * @internal
1134
1192
  */
1135
1193
  async _post(url, data, config2 = {}) {
1194
+ await this.ensureRegionResolved();
1136
1195
  return this.request("POST", url, { ...config2, data });
1137
1196
  }
1138
1197
  /**
@@ -1141,6 +1200,7 @@ var Lexmount = class {
1141
1200
  * @internal
1142
1201
  */
1143
1202
  async _get(url, params, config2 = {}) {
1203
+ await this.ensureRegionResolved();
1144
1204
  return this.request("GET", url, { ...config2, params });
1145
1205
  }
1146
1206
  /**
@@ -1149,8 +1209,51 @@ var Lexmount = class {
1149
1209
  * @internal
1150
1210
  */
1151
1211
  async _delete(url, data, config2 = {}) {
1212
+ await this.ensureRegionResolved();
1152
1213
  return this.request("DELETE", url, { ...config2, data });
1153
1214
  }
1215
+ async regionInfo() {
1216
+ await this.ensureRegionResolved();
1217
+ return {
1218
+ requestedRegion: this.region,
1219
+ selectedRegion: this.selectedRegion,
1220
+ baseUrl: this.baseUrl,
1221
+ endpointBaseUrl: this.endpointBaseUrl,
1222
+ host: this.selectedHost,
1223
+ resolved: this.regionResolutionAttempted,
1224
+ usingRegion: this.selectedRegion !== void 0
1225
+ };
1226
+ }
1227
+ async catalogInfo() {
1228
+ try {
1229
+ const response = await this.httpClient.get(
1230
+ `${this.baseUrl}/v1/regions/catalog`
1231
+ );
1232
+ if (response.status !== 200) {
1233
+ return {
1234
+ baseUrl: this.baseUrl,
1235
+ available: false,
1236
+ statusCode: response.status,
1237
+ regions: []
1238
+ };
1239
+ }
1240
+ const regions = Array.isArray(response.data?.regions) ? response.data.regions : [];
1241
+ return {
1242
+ baseUrl: this.baseUrl,
1243
+ available: Array.isArray(response.data?.regions),
1244
+ statusCode: response.status,
1245
+ regions,
1246
+ error: Array.isArray(response.data?.regions) ? void 0 : "invalid catalog regions"
1247
+ };
1248
+ } catch (error) {
1249
+ return {
1250
+ baseUrl: this.baseUrl,
1251
+ available: false,
1252
+ regions: [],
1253
+ error: error instanceof Error ? error.message : String(error)
1254
+ };
1255
+ }
1256
+ }
1154
1257
  /**
1155
1258
  * Close the client.
1156
1259
  *
@@ -1168,7 +1271,8 @@ var Lexmount = class {
1168
1271
  async request(method, url, config2) {
1169
1272
  const logger2 = getLogger();
1170
1273
  const startTime = Date.now();
1171
- logger2.debug(`${method} request to ${url}`);
1274
+ const requestUrl = this.rewriteUrl(url);
1275
+ logger2.debug(`${method} request to ${requestUrl}`);
1172
1276
  try {
1173
1277
  const headers = {
1174
1278
  api_key: this.apiKey,
@@ -1178,12 +1282,14 @@ var Lexmount = class {
1178
1282
  };
1179
1283
  const response = await this.httpClient.request({
1180
1284
  method,
1181
- url,
1285
+ url: requestUrl,
1182
1286
  ...config2,
1183
1287
  headers
1184
1288
  });
1185
1289
  const elapsed = Date.now() - startTime;
1186
- logger2.debug(`${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`);
1290
+ logger2.debug(
1291
+ `${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`
1292
+ );
1187
1293
  return response;
1188
1294
  } catch (error) {
1189
1295
  const elapsed = Date.now() - startTime;
@@ -1222,10 +1328,101 @@ var Lexmount = class {
1222
1328
  "Content-Type": "application/json"
1223
1329
  };
1224
1330
  }
1331
+ async ensureRegionResolved() {
1332
+ if (this.regionResolutionAttempted) {
1333
+ return;
1334
+ }
1335
+ if (!this.regionResolutionPromise) {
1336
+ this.regionResolutionPromise = this.resolveRegion().finally(() => {
1337
+ this.regionResolutionAttempted = true;
1338
+ this.regionResolutionPromise = void 0;
1339
+ });
1340
+ }
1341
+ await this.regionResolutionPromise;
1342
+ }
1343
+ async resolveRegion() {
1344
+ const logger2 = getLogger();
1345
+ try {
1346
+ const response = await this.httpClient.get(
1347
+ `${this.baseUrl}/v1/regions/catalog`
1348
+ );
1349
+ if (response.status !== 200 || !Array.isArray(response.data?.regions)) {
1350
+ logger2.debug(
1351
+ `Region catalog unavailable, falling back to baseUrl: status=${response.status}`
1352
+ );
1353
+ return;
1354
+ }
1355
+ const selected = this.selectCatalogRegion(response.data.regions);
1356
+ if (!selected) {
1357
+ if (this.region) {
1358
+ logger2.warn(`Requested region not found in catalog: ${this.region}`);
1359
+ } else {
1360
+ logger2.debug("No default catalog region, falling back to baseUrl");
1361
+ }
1362
+ return;
1363
+ }
1364
+ const endpointBaseUrl = await this.probeRegionHost(selected);
1365
+ if (!endpointBaseUrl) {
1366
+ logger2.debug("Region probe failed, falling back to baseUrl");
1367
+ return;
1368
+ }
1369
+ this.selectedRegion = selected.region_id;
1370
+ this.selectedHost = selected.host;
1371
+ this.endpointBaseUrl = endpointBaseUrl;
1372
+ } catch (error) {
1373
+ logger2.debug("Region resolution failed, falling back to baseUrl:", error);
1374
+ }
1375
+ }
1376
+ selectCatalogRegion(regions) {
1377
+ if (this.region) {
1378
+ return regions.find((region) => region.region_id === this.region);
1379
+ }
1380
+ const defaultRegions = regions.filter((region) => region.default === true);
1381
+ return defaultRegions.length === 1 ? defaultRegions[0] : void 0;
1382
+ }
1383
+ async probeRegionHost(region) {
1384
+ const logger2 = getLogger();
1385
+ const host = String(region.host || "").trim();
1386
+ if (!host) {
1387
+ return void 0;
1388
+ }
1389
+ if (!this.isAllowedCatalogHost(host)) {
1390
+ logger2.warn(`Ignoring invalid region catalog host: ${host}`);
1391
+ return void 0;
1392
+ }
1393
+ const endpointBaseUrl = `https://${host}`;
1394
+ const probePath = String(region.probe_path || "/v1/region/probe").replace(/^(?!\/)/, "/");
1395
+ try {
1396
+ const response = await this.httpClient.get(`${endpointBaseUrl}${probePath}`);
1397
+ return response.status === 200 ? endpointBaseUrl : void 0;
1398
+ } catch {
1399
+ return void 0;
1400
+ }
1401
+ }
1402
+ isAllowedCatalogHost(host) {
1403
+ let parsed;
1404
+ try {
1405
+ parsed = new URL(`https://${host}`);
1406
+ } catch {
1407
+ return false;
1408
+ }
1409
+ if (parsed.username || parsed.password || parsed.port || parsed.pathname !== "/" || parsed.search || parsed.hash) {
1410
+ return false;
1411
+ }
1412
+ const hostname = parsed.hostname.toLowerCase();
1413
+ const allowedDomains = ["lexmount.cn", "lexmount.com", "lexmount.net"];
1414
+ return allowedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
1415
+ }
1416
+ rewriteUrl(url) {
1417
+ if (!this.endpointBaseUrl || !url.startsWith(this.baseUrl)) {
1418
+ return url;
1419
+ }
1420
+ return `${this.endpointBaseUrl}${url.slice(this.baseUrl.length)}`;
1421
+ }
1225
1422
  };
1226
1423
 
1227
1424
  // src/index.ts
1228
- var VERSION = "0.2.5";
1425
+ var VERSION = "0.5.1";
1229
1426
  // Annotate the CommonJS export names for ESM import in node:
1230
1427
  0 && (module.exports = {
1231
1428
  APIError,
@@ -1249,6 +1446,7 @@ var VERSION = "0.2.5";
1249
1446
  SessionInfo,
1250
1447
  SessionListResponse,
1251
1448
  SessionNotFoundError,
1449
+ SessionTargetInfo,
1252
1450
  SessionsResource,
1253
1451
  TimeoutError,
1254
1452
  VERSION,