lexmount 0.2.7 → 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 +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +145 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +146 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
|
-
import {
|
|
3
|
-
isAxiosError
|
|
4
|
-
} from "axios";
|
|
2
|
+
import { isAxiosError } from "axios";
|
|
5
3
|
import axios from "axios";
|
|
6
4
|
import * as dotenv from "dotenv";
|
|
7
5
|
|
|
@@ -1095,6 +1093,7 @@ var SessionsResource = class {
|
|
|
1095
1093
|
dotenv.config();
|
|
1096
1094
|
var Lexmount = class {
|
|
1097
1095
|
constructor(config2 = {}) {
|
|
1096
|
+
this.regionResolutionAttempted = false;
|
|
1098
1097
|
this.apiKey = config2.apiKey ?? process.env.LEXMOUNT_API_KEY ?? "";
|
|
1099
1098
|
if (!this.apiKey) {
|
|
1100
1099
|
throw new ValidationError(
|
|
@@ -1108,6 +1107,7 @@ var Lexmount = class {
|
|
|
1108
1107
|
);
|
|
1109
1108
|
}
|
|
1110
1109
|
this.baseUrl = (config2.baseUrl ?? process.env.LEXMOUNT_BASE_URL ?? "https://api.lexmount.cn").replace(/\/$/, "");
|
|
1110
|
+
this.region = config2.region;
|
|
1111
1111
|
if (config2.logLevel) {
|
|
1112
1112
|
setLogLevel(config2.logLevel);
|
|
1113
1113
|
}
|
|
@@ -1125,6 +1125,7 @@ var Lexmount = class {
|
|
|
1125
1125
|
* @internal
|
|
1126
1126
|
*/
|
|
1127
1127
|
async _post(url, data, config2 = {}) {
|
|
1128
|
+
await this.ensureRegionResolved();
|
|
1128
1129
|
return this.request("POST", url, { ...config2, data });
|
|
1129
1130
|
}
|
|
1130
1131
|
/**
|
|
@@ -1133,6 +1134,7 @@ var Lexmount = class {
|
|
|
1133
1134
|
* @internal
|
|
1134
1135
|
*/
|
|
1135
1136
|
async _get(url, params, config2 = {}) {
|
|
1137
|
+
await this.ensureRegionResolved();
|
|
1136
1138
|
return this.request("GET", url, { ...config2, params });
|
|
1137
1139
|
}
|
|
1138
1140
|
/**
|
|
@@ -1141,8 +1143,51 @@ var Lexmount = class {
|
|
|
1141
1143
|
* @internal
|
|
1142
1144
|
*/
|
|
1143
1145
|
async _delete(url, data, config2 = {}) {
|
|
1146
|
+
await this.ensureRegionResolved();
|
|
1144
1147
|
return this.request("DELETE", url, { ...config2, data });
|
|
1145
1148
|
}
|
|
1149
|
+
async regionInfo() {
|
|
1150
|
+
await this.ensureRegionResolved();
|
|
1151
|
+
return {
|
|
1152
|
+
requestedRegion: this.region,
|
|
1153
|
+
selectedRegion: this.selectedRegion,
|
|
1154
|
+
baseUrl: this.baseUrl,
|
|
1155
|
+
endpointBaseUrl: this.endpointBaseUrl,
|
|
1156
|
+
host: this.selectedHost,
|
|
1157
|
+
resolved: this.regionResolutionAttempted,
|
|
1158
|
+
usingRegion: this.selectedRegion !== void 0
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
async catalogInfo() {
|
|
1162
|
+
try {
|
|
1163
|
+
const response = await this.httpClient.get(
|
|
1164
|
+
`${this.baseUrl}/v1/regions/catalog`
|
|
1165
|
+
);
|
|
1166
|
+
if (response.status !== 200) {
|
|
1167
|
+
return {
|
|
1168
|
+
baseUrl: this.baseUrl,
|
|
1169
|
+
available: false,
|
|
1170
|
+
statusCode: response.status,
|
|
1171
|
+
regions: []
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
const regions = Array.isArray(response.data?.regions) ? response.data.regions : [];
|
|
1175
|
+
return {
|
|
1176
|
+
baseUrl: this.baseUrl,
|
|
1177
|
+
available: Array.isArray(response.data?.regions),
|
|
1178
|
+
statusCode: response.status,
|
|
1179
|
+
regions,
|
|
1180
|
+
error: Array.isArray(response.data?.regions) ? void 0 : "invalid catalog regions"
|
|
1181
|
+
};
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
return {
|
|
1184
|
+
baseUrl: this.baseUrl,
|
|
1185
|
+
available: false,
|
|
1186
|
+
regions: [],
|
|
1187
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1146
1191
|
/**
|
|
1147
1192
|
* Close the client.
|
|
1148
1193
|
*
|
|
@@ -1160,7 +1205,8 @@ var Lexmount = class {
|
|
|
1160
1205
|
async request(method, url, config2) {
|
|
1161
1206
|
const logger2 = getLogger();
|
|
1162
1207
|
const startTime = Date.now();
|
|
1163
|
-
|
|
1208
|
+
const requestUrl = this.rewriteUrl(url);
|
|
1209
|
+
logger2.debug(`${method} request to ${requestUrl}`);
|
|
1164
1210
|
try {
|
|
1165
1211
|
const headers = {
|
|
1166
1212
|
api_key: this.apiKey,
|
|
@@ -1170,12 +1216,14 @@ var Lexmount = class {
|
|
|
1170
1216
|
};
|
|
1171
1217
|
const response = await this.httpClient.request({
|
|
1172
1218
|
method,
|
|
1173
|
-
url,
|
|
1219
|
+
url: requestUrl,
|
|
1174
1220
|
...config2,
|
|
1175
1221
|
headers
|
|
1176
1222
|
});
|
|
1177
1223
|
const elapsed = Date.now() - startTime;
|
|
1178
|
-
logger2.debug(
|
|
1224
|
+
logger2.debug(
|
|
1225
|
+
`${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`
|
|
1226
|
+
);
|
|
1179
1227
|
return response;
|
|
1180
1228
|
} catch (error) {
|
|
1181
1229
|
const elapsed = Date.now() - startTime;
|
|
@@ -1214,10 +1262,101 @@ var Lexmount = class {
|
|
|
1214
1262
|
"Content-Type": "application/json"
|
|
1215
1263
|
};
|
|
1216
1264
|
}
|
|
1265
|
+
async ensureRegionResolved() {
|
|
1266
|
+
if (this.regionResolutionAttempted) {
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
if (!this.regionResolutionPromise) {
|
|
1270
|
+
this.regionResolutionPromise = this.resolveRegion().finally(() => {
|
|
1271
|
+
this.regionResolutionAttempted = true;
|
|
1272
|
+
this.regionResolutionPromise = void 0;
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
await this.regionResolutionPromise;
|
|
1276
|
+
}
|
|
1277
|
+
async resolveRegion() {
|
|
1278
|
+
const logger2 = getLogger();
|
|
1279
|
+
try {
|
|
1280
|
+
const response = await this.httpClient.get(
|
|
1281
|
+
`${this.baseUrl}/v1/regions/catalog`
|
|
1282
|
+
);
|
|
1283
|
+
if (response.status !== 200 || !Array.isArray(response.data?.regions)) {
|
|
1284
|
+
logger2.debug(
|
|
1285
|
+
`Region catalog unavailable, falling back to baseUrl: status=${response.status}`
|
|
1286
|
+
);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
const selected = this.selectCatalogRegion(response.data.regions);
|
|
1290
|
+
if (!selected) {
|
|
1291
|
+
if (this.region) {
|
|
1292
|
+
logger2.warn(`Requested region not found in catalog: ${this.region}`);
|
|
1293
|
+
} else {
|
|
1294
|
+
logger2.debug("No default catalog region, falling back to baseUrl");
|
|
1295
|
+
}
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
const endpointBaseUrl = await this.probeRegionHost(selected);
|
|
1299
|
+
if (!endpointBaseUrl) {
|
|
1300
|
+
logger2.debug("Region probe failed, falling back to baseUrl");
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
this.selectedRegion = selected.region_id;
|
|
1304
|
+
this.selectedHost = selected.host;
|
|
1305
|
+
this.endpointBaseUrl = endpointBaseUrl;
|
|
1306
|
+
} catch (error) {
|
|
1307
|
+
logger2.debug("Region resolution failed, falling back to baseUrl:", error);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
selectCatalogRegion(regions) {
|
|
1311
|
+
if (this.region) {
|
|
1312
|
+
return regions.find((region) => region.region_id === this.region);
|
|
1313
|
+
}
|
|
1314
|
+
const defaultRegions = regions.filter((region) => region.default === true);
|
|
1315
|
+
return defaultRegions.length === 1 ? defaultRegions[0] : void 0;
|
|
1316
|
+
}
|
|
1317
|
+
async probeRegionHost(region) {
|
|
1318
|
+
const logger2 = getLogger();
|
|
1319
|
+
const host = String(region.host || "").trim();
|
|
1320
|
+
if (!host) {
|
|
1321
|
+
return void 0;
|
|
1322
|
+
}
|
|
1323
|
+
if (!this.isAllowedCatalogHost(host)) {
|
|
1324
|
+
logger2.warn(`Ignoring invalid region catalog host: ${host}`);
|
|
1325
|
+
return void 0;
|
|
1326
|
+
}
|
|
1327
|
+
const endpointBaseUrl = `https://${host}`;
|
|
1328
|
+
const probePath = String(region.probe_path || "/v1/region/probe").replace(/^(?!\/)/, "/");
|
|
1329
|
+
try {
|
|
1330
|
+
const response = await this.httpClient.get(`${endpointBaseUrl}${probePath}`);
|
|
1331
|
+
return response.status === 200 ? endpointBaseUrl : void 0;
|
|
1332
|
+
} catch {
|
|
1333
|
+
return void 0;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
isAllowedCatalogHost(host) {
|
|
1337
|
+
let parsed;
|
|
1338
|
+
try {
|
|
1339
|
+
parsed = new URL(`https://${host}`);
|
|
1340
|
+
} catch {
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1343
|
+
if (parsed.username || parsed.password || parsed.port || parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
1344
|
+
return false;
|
|
1345
|
+
}
|
|
1346
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
1347
|
+
const allowedDomains = ["lexmount.cn", "lexmount.com", "lexmount.net"];
|
|
1348
|
+
return allowedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
|
|
1349
|
+
}
|
|
1350
|
+
rewriteUrl(url) {
|
|
1351
|
+
if (!this.endpointBaseUrl || !url.startsWith(this.baseUrl)) {
|
|
1352
|
+
return url;
|
|
1353
|
+
}
|
|
1354
|
+
return `${this.endpointBaseUrl}${url.slice(this.baseUrl.length)}`;
|
|
1355
|
+
}
|
|
1217
1356
|
};
|
|
1218
1357
|
|
|
1219
1358
|
// src/index.ts
|
|
1220
|
-
var VERSION = "0.
|
|
1359
|
+
var VERSION = "0.5.1";
|
|
1221
1360
|
export {
|
|
1222
1361
|
APIError,
|
|
1223
1362
|
AuthenticationError,
|