@frontmcp/utils 1.8.7 → 1.9.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/env/browser-env.d.ts +1 -0
- package/env/browser-env.js +5 -0
- package/env/browser-runtime-context.d.ts +2 -1
- package/env/browser-runtime-context.js +104 -0
- package/env/index.d.ts +1 -1
- package/env/node-env.d.ts +11 -0
- package/env/node-env.js +8 -2
- package/env/runtime-context.d.ts +7 -4
- package/env/runtime-context.js +192 -0
- package/esm/async-context/browser-async-context.mjs +1 -1
- package/esm/async-context/node-async-context.mjs +1 -1
- package/esm/crypto/browser.mjs +1 -1
- package/esm/crypto/node.mjs +1 -1
- package/esm/env/browser-env.mjs +5 -1
- package/esm/env/browser-runtime-context.mjs +77 -0
- package/esm/env/node-env.mjs +8 -3
- package/esm/env/runtime-context.mjs +172 -0
- package/esm/event-emitter/browser-event-emitter.mjs +1 -1
- package/esm/event-emitter/node-event-emitter.mjs +1 -1
- package/esm/index.mjs +185 -253
- package/esm/path/browser-path.mjs +50 -0
- package/esm/path/node-path.mjs +16 -0
- package/index.d.ts +1 -1
- package/index.js +194 -278
- package/package.json +26 -8
- package/path/browser-path.js +79 -0
- package/path/node-path.js +45 -0
- package/storage/adapters/base.d.ts +6 -1
- package/storage/adapters/cloudflare-kv.d.ts +1 -0
- package/storage/adapters/memory.d.ts +2 -1
- package/storage/adapters/redis.d.ts +1 -0
- package/storage/adapters/upstash.d.ts +2 -1
- package/storage/adapters/vercel-kv.d.ts +2 -1
- package/storage/namespace.d.ts +2 -1
- package/storage/types.d.ts +11 -0
- package/storage/utils/compare-and-delete.d.ts +2 -0
package/index.js
CHANGED
|
@@ -596,9 +596,9 @@ function createSecretData(options) {
|
|
|
596
596
|
}
|
|
597
597
|
async function getOrCreateSecret(options) {
|
|
598
598
|
const cacheKey = resolveSecretPath(options);
|
|
599
|
-
const
|
|
600
|
-
if (
|
|
601
|
-
return
|
|
599
|
+
const cached = secretCache.get(cacheKey);
|
|
600
|
+
if (cached) {
|
|
601
|
+
return cached;
|
|
602
602
|
}
|
|
603
603
|
const existing = generationPromises.get(cacheKey);
|
|
604
604
|
if (existing) {
|
|
@@ -836,8 +836,8 @@ var init_key_persistence = __esm({
|
|
|
836
836
|
*/
|
|
837
837
|
async get(kid) {
|
|
838
838
|
if (this.enableCache) {
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
839
|
+
const cached = this.cache.get(kid);
|
|
840
|
+
if (cached) return cached;
|
|
841
841
|
}
|
|
842
842
|
const raw = await this.storage.get(kid);
|
|
843
843
|
if (!raw) return null;
|
|
@@ -1088,6 +1088,75 @@ var init_errors = __esm({
|
|
|
1088
1088
|
}
|
|
1089
1089
|
});
|
|
1090
1090
|
|
|
1091
|
+
// libs/utils/src/storage/utils/pattern.ts
|
|
1092
|
+
function globToRegex(pattern) {
|
|
1093
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1094
|
+
throw new StoragePatternError(
|
|
1095
|
+
pattern.substring(0, 50) + "...",
|
|
1096
|
+
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1100
|
+
if (wildcardCount > MAX_WILDCARDS) {
|
|
1101
|
+
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1102
|
+
}
|
|
1103
|
+
if (pattern === "" || pattern === "*") {
|
|
1104
|
+
return /^.*$/;
|
|
1105
|
+
}
|
|
1106
|
+
let regexStr = "^";
|
|
1107
|
+
let prevChar = "";
|
|
1108
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1109
|
+
const char = pattern[i];
|
|
1110
|
+
switch (char) {
|
|
1111
|
+
case "*":
|
|
1112
|
+
if (prevChar !== "*") {
|
|
1113
|
+
regexStr += ".*";
|
|
1114
|
+
}
|
|
1115
|
+
break;
|
|
1116
|
+
case "?":
|
|
1117
|
+
regexStr += ".";
|
|
1118
|
+
break;
|
|
1119
|
+
default:
|
|
1120
|
+
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1121
|
+
}
|
|
1122
|
+
prevChar = char;
|
|
1123
|
+
}
|
|
1124
|
+
regexStr += "$";
|
|
1125
|
+
try {
|
|
1126
|
+
return new RegExp(regexStr);
|
|
1127
|
+
} catch {
|
|
1128
|
+
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
function matchesPattern(key, pattern) {
|
|
1132
|
+
const regex = globToRegex(pattern);
|
|
1133
|
+
return regex.test(key);
|
|
1134
|
+
}
|
|
1135
|
+
function validatePattern(pattern) {
|
|
1136
|
+
try {
|
|
1137
|
+
globToRegex(pattern);
|
|
1138
|
+
return { valid: true };
|
|
1139
|
+
} catch (e) {
|
|
1140
|
+
return {
|
|
1141
|
+
valid: false,
|
|
1142
|
+
error: e instanceof Error ? e.message : "Invalid pattern"
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
function escapeGlob(literal) {
|
|
1147
|
+
return literal.replace(/[*?\\]/g, "\\$&");
|
|
1148
|
+
}
|
|
1149
|
+
var MAX_PATTERN_LENGTH, MAX_WILDCARDS, REGEX_SPECIAL_CHARS;
|
|
1150
|
+
var init_pattern = __esm({
|
|
1151
|
+
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1152
|
+
"use strict";
|
|
1153
|
+
init_errors();
|
|
1154
|
+
MAX_PATTERN_LENGTH = 500;
|
|
1155
|
+
MAX_WILDCARDS = 20;
|
|
1156
|
+
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1157
|
+
}
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1091
1160
|
// libs/utils/src/storage/utils/ttl.ts
|
|
1092
1161
|
function validateTTL(ttlSeconds) {
|
|
1093
1162
|
if (typeof ttlSeconds !== "number") {
|
|
@@ -1202,6 +1271,17 @@ var init_base = __esm({
|
|
|
1202
1271
|
const matchedKeys = await this.keys(pattern);
|
|
1203
1272
|
return matchedKeys.length;
|
|
1204
1273
|
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Default: not supported, since a read followed by a delete is not atomic.
|
|
1276
|
+
* Override in adapters whose backend can compare and delete in one step.
|
|
1277
|
+
*/
|
|
1278
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
1279
|
+
throw new StorageNotSupportedError(
|
|
1280
|
+
"deleteIfEquals",
|
|
1281
|
+
this.backendName,
|
|
1282
|
+
"Use the memory, Redis, Upstash or Vercel KV adapter for an atomic compare-and-delete."
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1205
1285
|
// ============================================
|
|
1206
1286
|
// Pub/Sub (default: not supported)
|
|
1207
1287
|
// ============================================
|
|
@@ -1250,85 +1330,16 @@ var init_base = __esm({
|
|
|
1250
1330
|
}
|
|
1251
1331
|
});
|
|
1252
1332
|
|
|
1253
|
-
// libs/utils/src/storage/utils/pattern.ts
|
|
1254
|
-
function globToRegex(pattern) {
|
|
1255
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1256
|
-
throw new StoragePatternError(
|
|
1257
|
-
pattern.substring(0, 50) + "...",
|
|
1258
|
-
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1259
|
-
);
|
|
1260
|
-
}
|
|
1261
|
-
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1262
|
-
if (wildcardCount > MAX_WILDCARDS) {
|
|
1263
|
-
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1264
|
-
}
|
|
1265
|
-
if (pattern === "" || pattern === "*") {
|
|
1266
|
-
return /^.*$/;
|
|
1267
|
-
}
|
|
1268
|
-
let regexStr = "^";
|
|
1269
|
-
let prevChar = "";
|
|
1270
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
1271
|
-
const char = pattern[i];
|
|
1272
|
-
switch (char) {
|
|
1273
|
-
case "*":
|
|
1274
|
-
if (prevChar !== "*") {
|
|
1275
|
-
regexStr += ".*";
|
|
1276
|
-
}
|
|
1277
|
-
break;
|
|
1278
|
-
case "?":
|
|
1279
|
-
regexStr += ".";
|
|
1280
|
-
break;
|
|
1281
|
-
default:
|
|
1282
|
-
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1283
|
-
}
|
|
1284
|
-
prevChar = char;
|
|
1285
|
-
}
|
|
1286
|
-
regexStr += "$";
|
|
1287
|
-
try {
|
|
1288
|
-
return new RegExp(regexStr);
|
|
1289
|
-
} catch {
|
|
1290
|
-
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
function matchesPattern(key, pattern) {
|
|
1294
|
-
const regex = globToRegex(pattern);
|
|
1295
|
-
return regex.test(key);
|
|
1296
|
-
}
|
|
1297
|
-
function validatePattern(pattern) {
|
|
1298
|
-
try {
|
|
1299
|
-
globToRegex(pattern);
|
|
1300
|
-
return { valid: true };
|
|
1301
|
-
} catch (e) {
|
|
1302
|
-
return {
|
|
1303
|
-
valid: false,
|
|
1304
|
-
error: e instanceof Error ? e.message : "Invalid pattern"
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
function escapeGlob(literal) {
|
|
1309
|
-
return literal.replace(/[*?\\]/g, "\\$&");
|
|
1310
|
-
}
|
|
1311
|
-
var MAX_PATTERN_LENGTH, MAX_WILDCARDS, REGEX_SPECIAL_CHARS;
|
|
1312
|
-
var init_pattern = __esm({
|
|
1313
|
-
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1314
|
-
"use strict";
|
|
1315
|
-
init_errors();
|
|
1316
|
-
MAX_PATTERN_LENGTH = 500;
|
|
1317
|
-
MAX_WILDCARDS = 20;
|
|
1318
|
-
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1319
|
-
}
|
|
1320
|
-
});
|
|
1321
|
-
|
|
1322
1333
|
// libs/utils/src/storage/adapters/memory.ts
|
|
1323
1334
|
var import_event_emitter, DEFAULT_SWEEP_INTERVAL_SECONDS, MAX_TIMEOUT_MS, MemoryStorageAdapter;
|
|
1324
1335
|
var init_memory = __esm({
|
|
1325
1336
|
"libs/utils/src/storage/adapters/memory.ts"() {
|
|
1326
1337
|
"use strict";
|
|
1327
1338
|
import_event_emitter = require("#event-emitter");
|
|
1328
|
-
init_base();
|
|
1329
1339
|
init_errors();
|
|
1330
1340
|
init_pattern();
|
|
1331
1341
|
init_ttl();
|
|
1342
|
+
init_base();
|
|
1332
1343
|
DEFAULT_SWEEP_INTERVAL_SECONDS = 60;
|
|
1333
1344
|
MAX_TIMEOUT_MS = 2147483647;
|
|
1334
1345
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
@@ -1420,6 +1431,12 @@ var init_memory = __esm({
|
|
|
1420
1431
|
this.ensureConnected();
|
|
1421
1432
|
return this.deleteEntry(key);
|
|
1422
1433
|
}
|
|
1434
|
+
async deleteIfEquals(key, expectedValue) {
|
|
1435
|
+
this.ensureConnected();
|
|
1436
|
+
const entry = this.store.get(key);
|
|
1437
|
+
if (!entry || isExpired(entry.expiresAt) || entry.value !== expectedValue) return false;
|
|
1438
|
+
return this.deleteEntry(key);
|
|
1439
|
+
}
|
|
1423
1440
|
async exists(key) {
|
|
1424
1441
|
this.ensureConnected();
|
|
1425
1442
|
const entry = this.store.get(key);
|
|
@@ -3008,6 +3025,15 @@ var init_utils = __esm({
|
|
|
3008
3025
|
}
|
|
3009
3026
|
});
|
|
3010
3027
|
|
|
3028
|
+
// libs/utils/src/storage/utils/compare-and-delete.ts
|
|
3029
|
+
var COMPARE_AND_DELETE_SCRIPT;
|
|
3030
|
+
var init_compare_and_delete = __esm({
|
|
3031
|
+
"libs/utils/src/storage/utils/compare-and-delete.ts"() {
|
|
3032
|
+
"use strict";
|
|
3033
|
+
COMPARE_AND_DELETE_SCRIPT = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end return 0`;
|
|
3034
|
+
}
|
|
3035
|
+
});
|
|
3036
|
+
|
|
3011
3037
|
// libs/utils/src/storage/adapters/redis.ts
|
|
3012
3038
|
var redis_exports = {};
|
|
3013
3039
|
__export(redis_exports, {
|
|
@@ -3051,6 +3077,7 @@ var init_redis = __esm({
|
|
|
3051
3077
|
init_errors();
|
|
3052
3078
|
init_redis_error_listener();
|
|
3053
3079
|
init_utils();
|
|
3080
|
+
init_compare_and_delete();
|
|
3054
3081
|
init_base();
|
|
3055
3082
|
RedisStorageAdapter = class extends BaseStorageAdapter {
|
|
3056
3083
|
backendName = "redis";
|
|
@@ -3205,6 +3232,15 @@ var init_redis = __esm({
|
|
|
3205
3232
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3206
3233
|
return result > 0;
|
|
3207
3234
|
}
|
|
3235
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3236
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3237
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3238
|
+
1,
|
|
3239
|
+
this.prefixKey(key),
|
|
3240
|
+
expectedValue
|
|
3241
|
+
);
|
|
3242
|
+
return deleted === 1;
|
|
3243
|
+
}
|
|
3208
3244
|
async exists(key) {
|
|
3209
3245
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3210
3246
|
return result > 0;
|
|
@@ -3413,9 +3449,12 @@ var vercel_kv_exports = {};
|
|
|
3413
3449
|
__export(vercel_kv_exports, {
|
|
3414
3450
|
VercelKvStorageAdapter: () => VercelKvStorageAdapter
|
|
3415
3451
|
});
|
|
3416
|
-
function
|
|
3452
|
+
async function loadVercelKv() {
|
|
3417
3453
|
try {
|
|
3418
|
-
|
|
3454
|
+
const mod = await import("@vercel/kv");
|
|
3455
|
+
const resolved = typeof mod.createClient === "function" ? mod : mod.default;
|
|
3456
|
+
if (!resolved || typeof resolved.createClient !== "function") throw new Error("createClient missing");
|
|
3457
|
+
return resolved;
|
|
3419
3458
|
} catch {
|
|
3420
3459
|
throw new Error("@vercel/kv is required for Vercel KV storage adapter. Install it with: npm install @vercel/kv");
|
|
3421
3460
|
}
|
|
@@ -3424,9 +3463,10 @@ var VercelKvStorageAdapter;
|
|
|
3424
3463
|
var init_vercel_kv = __esm({
|
|
3425
3464
|
"libs/utils/src/storage/adapters/vercel-kv.ts"() {
|
|
3426
3465
|
"use strict";
|
|
3427
|
-
init_base();
|
|
3428
3466
|
init_errors();
|
|
3467
|
+
init_compare_and_delete();
|
|
3429
3468
|
init_ttl();
|
|
3469
|
+
init_base();
|
|
3430
3470
|
VercelKvStorageAdapter = class extends BaseStorageAdapter {
|
|
3431
3471
|
backendName = "vercel-kv";
|
|
3432
3472
|
client;
|
|
@@ -3451,17 +3491,13 @@ var init_vercel_kv = __esm({
|
|
|
3451
3491
|
async connect() {
|
|
3452
3492
|
if (this.connected) return;
|
|
3453
3493
|
try {
|
|
3454
|
-
const { createClient
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
const token = this.options.token;
|
|
3460
|
-
if (!url || !token) {
|
|
3461
|
-
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3462
|
-
}
|
|
3463
|
-
this.client = createClient({ url, token });
|
|
3494
|
+
const { createClient } = await loadVercelKv();
|
|
3495
|
+
const url = this.options.url;
|
|
3496
|
+
const token = this.options.token;
|
|
3497
|
+
if (!url || !token) {
|
|
3498
|
+
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3464
3499
|
}
|
|
3500
|
+
this.client = createClient({ url, token, cache: void 0 });
|
|
3465
3501
|
await this.client.exists("__healthcheck__");
|
|
3466
3502
|
this.connected = true;
|
|
3467
3503
|
} catch (e) {
|
|
@@ -3523,6 +3559,14 @@ var init_vercel_kv = __esm({
|
|
|
3523
3559
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3524
3560
|
return result > 0;
|
|
3525
3561
|
}
|
|
3562
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3563
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3564
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3565
|
+
[this.prefixKey(key)],
|
|
3566
|
+
[expectedValue]
|
|
3567
|
+
);
|
|
3568
|
+
return deleted === 1;
|
|
3569
|
+
}
|
|
3526
3570
|
async exists(key) {
|
|
3527
3571
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3528
3572
|
return result > 0;
|
|
@@ -3640,9 +3684,10 @@ var PUBSUB_POLL_INTERVAL_MS, UpstashStorageAdapter;
|
|
|
3640
3684
|
var init_upstash = __esm({
|
|
3641
3685
|
"libs/utils/src/storage/adapters/upstash.ts"() {
|
|
3642
3686
|
"use strict";
|
|
3643
|
-
init_base();
|
|
3644
3687
|
init_errors();
|
|
3688
|
+
init_compare_and_delete();
|
|
3645
3689
|
init_ttl();
|
|
3690
|
+
init_base();
|
|
3646
3691
|
PUBSUB_POLL_INTERVAL_MS = 100;
|
|
3647
3692
|
UpstashStorageAdapter = class extends BaseStorageAdapter {
|
|
3648
3693
|
backendName = "upstash";
|
|
@@ -3747,6 +3792,14 @@ var init_upstash = __esm({
|
|
|
3747
3792
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3748
3793
|
return result > 0;
|
|
3749
3794
|
}
|
|
3795
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3796
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3797
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3798
|
+
[this.prefixKey(key)],
|
|
3799
|
+
[expectedValue]
|
|
3800
|
+
);
|
|
3801
|
+
return deleted === 1;
|
|
3802
|
+
}
|
|
3750
3803
|
async exists(key) {
|
|
3751
3804
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3752
3805
|
return result > 0;
|
|
@@ -3936,7 +3989,9 @@ var init_cloudflare_kv = __esm({
|
|
|
3936
3989
|
constructor(options) {
|
|
3937
3990
|
super();
|
|
3938
3991
|
if (!options?.namespace) {
|
|
3939
|
-
throw new Error(
|
|
3992
|
+
throw new Error(
|
|
3993
|
+
"CloudflareKvStorageAdapter: a bound KV `namespace` is required (resolve it from the Worker `env`)."
|
|
3994
|
+
);
|
|
3940
3995
|
}
|
|
3941
3996
|
this.kv = options.namespace;
|
|
3942
3997
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
@@ -4030,6 +4085,13 @@ var init_cloudflare_kv = __esm({
|
|
|
4030
4085
|
"Cloudflare KV has no atomic increment (a get+put is racy under eventual consistency). Use a Durable Object for atomic counters."
|
|
4031
4086
|
);
|
|
4032
4087
|
}
|
|
4088
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
4089
|
+
throw new StorageNotSupportedError(
|
|
4090
|
+
"deleteIfEquals",
|
|
4091
|
+
this.backendName,
|
|
4092
|
+
"Cloudflare KV has no compare-and-set; use a Durable Object for an atomic compare-and-delete."
|
|
4093
|
+
);
|
|
4094
|
+
}
|
|
4033
4095
|
// ── Pub/Sub (unsupported) ────────────────────────────────────────────────
|
|
4034
4096
|
getPubSubSuggestion() {
|
|
4035
4097
|
return "Cloudflare KV does not support pub/sub. Use a Durable Object (or Queues) for fan-out.";
|
|
@@ -4104,11 +4166,11 @@ __export(index_exports, {
|
|
|
4104
4166
|
base64Encode: () => base64Encode,
|
|
4105
4167
|
base64urlDecode: () => base64urlDecode,
|
|
4106
4168
|
base64urlEncode: () => base64urlEncode,
|
|
4107
|
-
basename: () =>
|
|
4169
|
+
basename: () => import_path2.basename,
|
|
4108
4170
|
buildPrefix: () => buildPrefix,
|
|
4109
4171
|
buildSetCookie: () => buildSetCookie,
|
|
4110
4172
|
bytesToHex: () => bytesToHex,
|
|
4111
|
-
checkEntryAvailability: () => checkEntryAvailability,
|
|
4173
|
+
checkEntryAvailability: () => import_runtime_context.checkEntryAvailability,
|
|
4112
4174
|
classifyIpAddress: () => classifyIpAddress,
|
|
4113
4175
|
clearCachedSecret: () => clearCachedSecret,
|
|
4114
4176
|
collapseChar: () => collapseChar,
|
|
@@ -4129,15 +4191,15 @@ __export(index_exports, {
|
|
|
4129
4191
|
deleteSecret: () => deleteSecret,
|
|
4130
4192
|
deserializeAndDecrypt: () => deserializeAndDecrypt,
|
|
4131
4193
|
deserializeBlob: () => deserializeBlob,
|
|
4132
|
-
detectRuntimeContext: () => detectRuntimeContext,
|
|
4133
|
-
dirname: () =>
|
|
4194
|
+
detectRuntimeContext: () => import_runtime_context.detectRuntimeContext,
|
|
4195
|
+
dirname: () => import_path2.dirname,
|
|
4134
4196
|
encryptAesGcm: () => encryptAesGcm,
|
|
4135
4197
|
encryptAndSerialize: () => encryptAndSerialize,
|
|
4136
4198
|
encryptValue: () => encryptValue,
|
|
4137
4199
|
ensureDir: () => ensureDir,
|
|
4138
4200
|
ensureDirSync: () => ensureDirSync,
|
|
4139
4201
|
ensureMaxLen: () => ensureMaxLen,
|
|
4140
|
-
entryAvailabilitySchema: () => entryAvailabilitySchema,
|
|
4202
|
+
entryAvailabilitySchema: () => import_runtime_context.entryAvailabilitySchema,
|
|
4141
4203
|
escapeGlob: () => escapeGlob,
|
|
4142
4204
|
escapeHtml: () => escapeHtml,
|
|
4143
4205
|
escapeHtmlAttr: () => escapeHtmlAttr,
|
|
@@ -4147,7 +4209,7 @@ __export(index_exports, {
|
|
|
4147
4209
|
expandTemplate: () => expandTemplate,
|
|
4148
4210
|
expandUriTemplate: () => expandUriTemplate,
|
|
4149
4211
|
expiresAtToTTL: () => expiresAtToTTL,
|
|
4150
|
-
extname: () =>
|
|
4212
|
+
extname: () => import_path2.extname,
|
|
4151
4213
|
extractBracedParams: () => extractBracedParams,
|
|
4152
4214
|
extractEmbeddedIpv4: () => extractEmbeddedIpv4,
|
|
4153
4215
|
extractTemplateParams: () => extractTemplateParams,
|
|
@@ -4162,13 +4224,14 @@ __export(index_exports, {
|
|
|
4162
4224
|
getAsyncContextMode: () => import_async_context.getAsyncContextMode,
|
|
4163
4225
|
getCookie: () => getCookie,
|
|
4164
4226
|
getCrypto: () => getCrypto,
|
|
4165
|
-
getCwd: () =>
|
|
4227
|
+
getCwd: () => import_env2.getCwd,
|
|
4166
4228
|
getDetectedStorageType: () => getDetectedStorageType,
|
|
4167
|
-
getEnv: () =>
|
|
4168
|
-
getEnvFlag: () =>
|
|
4229
|
+
getEnv: () => import_env2.getEnv,
|
|
4230
|
+
getEnvFlag: () => import_env2.getEnvFlag,
|
|
4169
4231
|
getMachineId: () => getMachineId,
|
|
4232
|
+
getNodeEnv: () => import_env2.getNodeEnv,
|
|
4170
4233
|
getOrCreateSecret: () => getOrCreateSecret,
|
|
4171
|
-
getRuntimeContext: () => getRuntimeContext,
|
|
4234
|
+
getRuntimeContext: () => import_runtime_context.getRuntimeContext,
|
|
4172
4235
|
getSpawnFn: () => getSpawnFn,
|
|
4173
4236
|
globToRegex: () => globToRegex,
|
|
4174
4237
|
hasTemplatePlaceholders: () => hasTemplatePlaceholders,
|
|
@@ -4176,27 +4239,27 @@ __export(index_exports, {
|
|
|
4176
4239
|
hmacSha256: () => hmacSha256,
|
|
4177
4240
|
idFromString: () => idFromString,
|
|
4178
4241
|
inferMimeType: () => inferMimeType,
|
|
4179
|
-
isAbsolute: () =>
|
|
4242
|
+
isAbsolute: () => import_path2.isAbsolute,
|
|
4180
4243
|
isAsymmetricKeyData: () => isAsymmetricKeyData,
|
|
4181
4244
|
isBrowser: () => isBrowser,
|
|
4182
|
-
isDebug: () =>
|
|
4183
|
-
isDevelopment: () =>
|
|
4245
|
+
isDebug: () => import_env2.isDebug,
|
|
4246
|
+
isDevelopment: () => import_env2.isDevelopment,
|
|
4184
4247
|
isDirEmpty: () => isDirEmpty,
|
|
4185
|
-
isEdgeRuntime: () =>
|
|
4186
|
-
isEntryAvailable: () => isEntryAvailable,
|
|
4248
|
+
isEdgeRuntime: () => import_env2.isEdgeRuntime,
|
|
4249
|
+
isEntryAvailable: () => import_runtime_context.isEntryAvailable,
|
|
4187
4250
|
isExpired: () => isExpired,
|
|
4188
4251
|
isInputLengthSafe: () => isInputLengthSafe,
|
|
4189
4252
|
isLocalhost: () => isLocalhost,
|
|
4190
4253
|
isNode: () => isNode,
|
|
4191
4254
|
isPatternSafe: () => isPatternSafe,
|
|
4192
|
-
isProduction: () =>
|
|
4255
|
+
isProduction: () => import_env2.isProduction,
|
|
4193
4256
|
isRedirectResponse: () => isRedirectResponse,
|
|
4194
4257
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
4195
4258
|
isSecretCached: () => isSecretCached,
|
|
4196
4259
|
isSecretKeyData: () => isSecretKeyData,
|
|
4197
4260
|
isSecretPersistenceEnabled: () => isSecretPersistenceEnabled,
|
|
4198
4261
|
isSecureRequest: () => isSecureRequest,
|
|
4199
|
-
isServerless: () =>
|
|
4262
|
+
isServerless: () => import_env2.isServerless,
|
|
4200
4263
|
isSignedData: () => isSignedData,
|
|
4201
4264
|
isUriTemplate: () => isUriTemplate,
|
|
4202
4265
|
isValidCodeChallenge: () => isValidCodeChallenge,
|
|
@@ -4217,9 +4280,9 @@ __export(index_exports, {
|
|
|
4217
4280
|
parseKeyData: () => parseKeyData,
|
|
4218
4281
|
parseSecretData: () => parseSecretData,
|
|
4219
4282
|
parseUriTemplate: () => parseUriTemplate,
|
|
4220
|
-
pathJoin: () =>
|
|
4221
|
-
pathResolve: () =>
|
|
4222
|
-
pathToFileURL: () =>
|
|
4283
|
+
pathJoin: () => import_path2.join,
|
|
4284
|
+
pathResolve: () => import_path2.resolve,
|
|
4285
|
+
pathToFileURL: () => import_path2.pathToFileURL,
|
|
4223
4286
|
pemToPublicJwk: () => pemToPublicJwk2,
|
|
4224
4287
|
processPlatformToolCalls: () => processPlatformToolCalls,
|
|
4225
4288
|
randomBytes: () => randomBytes,
|
|
@@ -4232,7 +4295,7 @@ __export(index_exports, {
|
|
|
4232
4295
|
readdirSync: () => readdirSync,
|
|
4233
4296
|
realpath: () => realpath,
|
|
4234
4297
|
rename: () => rename,
|
|
4235
|
-
resetRuntimeContext: () => resetRuntimeContext,
|
|
4298
|
+
resetRuntimeContext: () => import_runtime_context.resetRuntimeContext,
|
|
4236
4299
|
resolveSecretPath: () => resolveSecretPath,
|
|
4237
4300
|
rm: () => rm,
|
|
4238
4301
|
rsaSignBase64Url: () => rsaSignBase64Url2,
|
|
@@ -4250,10 +4313,10 @@ __export(index_exports, {
|
|
|
4250
4313
|
saveSecret: () => saveSecret,
|
|
4251
4314
|
secretDataSchema: () => secretDataSchema,
|
|
4252
4315
|
secretKeyDataSchema: () => secretKeyDataSchema,
|
|
4253
|
-
sep: () =>
|
|
4316
|
+
sep: () => import_path2.sep,
|
|
4254
4317
|
sepFor: () => sepFor,
|
|
4255
4318
|
serializeBlob: () => serializeBlob,
|
|
4256
|
-
setEnv: () =>
|
|
4319
|
+
setEnv: () => import_env2.setEnv,
|
|
4257
4320
|
setMachineIdOverride: () => setMachineIdOverride,
|
|
4258
4321
|
sha256: () => sha256,
|
|
4259
4322
|
sha256Base64url: () => sha256Base64url,
|
|
@@ -4262,7 +4325,7 @@ __export(index_exports, {
|
|
|
4262
4325
|
signData: () => signData,
|
|
4263
4326
|
splitWords: () => splitWords,
|
|
4264
4327
|
stat: () => stat,
|
|
4265
|
-
supportsAnsi: () =>
|
|
4328
|
+
supportsAnsi: () => import_env2.supportsAnsi,
|
|
4266
4329
|
symlink: () => symlink,
|
|
4267
4330
|
timingSafeEqual: () => timingSafeEqual,
|
|
4268
4331
|
toCase: () => toCase,
|
|
@@ -4692,9 +4755,8 @@ function joinPath(...parts) {
|
|
|
4692
4755
|
return cleaned.length ? `/${cleaned.join("/")}` : "";
|
|
4693
4756
|
}
|
|
4694
4757
|
|
|
4695
|
-
// libs/utils/src/path/
|
|
4696
|
-
var
|
|
4697
|
-
var import_url = require("url");
|
|
4758
|
+
// libs/utils/src/path/index.ts
|
|
4759
|
+
var import_path2 = require("#path");
|
|
4698
4760
|
|
|
4699
4761
|
// libs/utils/src/content/content.ts
|
|
4700
4762
|
function sanitizeToJson(value) {
|
|
@@ -5112,167 +5174,14 @@ var import_async_context = require("#async-context");
|
|
|
5112
5174
|
var import_event_emitter2 = require("#event-emitter");
|
|
5113
5175
|
|
|
5114
5176
|
// libs/utils/src/env/index.ts
|
|
5115
|
-
var import_env3 = require("#env");
|
|
5116
|
-
|
|
5117
|
-
// libs/utils/src/env/runtime-context.ts
|
|
5118
|
-
var import_lazy_zod3 = require("@frontmcp/lazy-zod");
|
|
5119
5177
|
var import_env2 = require("#env");
|
|
5120
|
-
|
|
5121
|
-
// libs/utils/src/env/build-target.ts
|
|
5122
|
-
var cached;
|
|
5123
|
-
function getBuildTarget() {
|
|
5124
|
-
if (cached) return cached;
|
|
5125
|
-
cached = resolveBuildTarget();
|
|
5126
|
-
return cached;
|
|
5127
|
-
}
|
|
5128
|
-
function resolveBuildTarget() {
|
|
5129
|
-
const globalAny = globalThis;
|
|
5130
|
-
const fromGlobal = globalAny.FRONTMCP_BUILD_TARGET;
|
|
5131
|
-
if (typeof fromGlobal === "string" && isKnownTarget(fromGlobal)) return fromGlobal;
|
|
5132
|
-
const fromEnv = typeof process !== "undefined" ? process.env?.["FRONTMCP_BUILD_TARGET"] : void 0;
|
|
5133
|
-
if (typeof fromEnv === "string" && isKnownTarget(fromEnv)) return fromEnv;
|
|
5134
|
-
return "unknown";
|
|
5135
|
-
}
|
|
5136
|
-
function isKnownTarget(value) {
|
|
5137
|
-
return value === "unknown" || value === "node" || value === "distributed" || value === "cli" || value === "vercel" || value === "lambda" || value === "cloudflare" || value === "browser" || value === "sdk" || value === "mcpb";
|
|
5138
|
-
}
|
|
5139
|
-
|
|
5140
|
-
// libs/utils/src/env/provider.ts
|
|
5141
|
-
var cached2;
|
|
5142
|
-
function detectProvider() {
|
|
5143
|
-
if (cached2) return cached2;
|
|
5144
|
-
cached2 = detectProviderUncached();
|
|
5145
|
-
return cached2;
|
|
5146
|
-
}
|
|
5147
|
-
function detectProviderUncached() {
|
|
5148
|
-
const explicit = process.env["FRONTMCP_PROVIDER"];
|
|
5149
|
-
if (explicit && isKnownProvider(explicit)) return explicit;
|
|
5150
|
-
if (process.env["VERCEL"]) return "vercel";
|
|
5151
|
-
if (process.env["AWS_LAMBDA_FUNCTION_NAME"]) return "lambda";
|
|
5152
|
-
if (process.env["CF_PAGES"]) return "cloudflare";
|
|
5153
|
-
if (process.env["NETLIFY"]) return "netlify";
|
|
5154
|
-
if (process.env["AZURE_FUNCTIONS_ENVIRONMENT"]) return "azure";
|
|
5155
|
-
if (process.env["K_SERVICE"]) return "gcp";
|
|
5156
|
-
if (process.env["FLY_APP_NAME"]) return "fly";
|
|
5157
|
-
if (process.env["RENDER"]) return "render";
|
|
5158
|
-
if (process.env["RAILWAY_ENVIRONMENT"]) return "railway";
|
|
5159
|
-
try {
|
|
5160
|
-
const nodeFs = require("node:fs");
|
|
5161
|
-
if (nodeFs.existsSync("/.dockerenv")) return "docker";
|
|
5162
|
-
} catch {
|
|
5163
|
-
}
|
|
5164
|
-
return "bare";
|
|
5165
|
-
}
|
|
5166
|
-
function isKnownProvider(value) {
|
|
5167
|
-
return value === "bare" || value === "docker" || value === "vercel" || value === "lambda" || value === "cloudflare" || value === "netlify" || value === "azure" || value === "gcp" || value === "fly" || value === "render" || value === "railway";
|
|
5168
|
-
}
|
|
5169
|
-
|
|
5170
|
-
// libs/utils/src/env/runtime-context.ts
|
|
5171
|
-
var entryAvailabilitySchema = import_lazy_zod3.z.object({
|
|
5172
|
-
os: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5173
|
-
platform: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5174
|
-
runtime: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5175
|
-
deployment: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5176
|
-
provider: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5177
|
-
target: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional(),
|
|
5178
|
-
surface: import_lazy_zod3.z.array(import_lazy_zod3.z.enum(["mcp", "cli", "http-trigger", "job", "agent"])).optional(),
|
|
5179
|
-
env: import_lazy_zod3.z.array(import_lazy_zod3.z.string().min(1)).optional()
|
|
5180
|
-
}).strict();
|
|
5181
|
-
var PROCESS_AXES = [
|
|
5182
|
-
// `os` and `platform` both compare against the same RuntimeContext value
|
|
5183
|
-
// — keeping `platform` as a deprecated alias lets pre-#417 metadata
|
|
5184
|
-
// continue to match without any code change.
|
|
5185
|
-
{ key: "os", ctxKey: "os" },
|
|
5186
|
-
{ key: "platform", ctxKey: "platform" },
|
|
5187
|
-
{ key: "runtime", ctxKey: "runtime" },
|
|
5188
|
-
{ key: "deployment", ctxKey: "deployment" },
|
|
5189
|
-
{ key: "provider", ctxKey: "provider" },
|
|
5190
|
-
{ key: "target", ctxKey: "target" },
|
|
5191
|
-
{ key: "env", ctxKey: "env" }
|
|
5192
|
-
];
|
|
5193
|
-
function isEntryAvailable(availability, ctx, callCtx) {
|
|
5194
|
-
if (!availability) return true;
|
|
5195
|
-
for (const { key, ctxKey } of PROCESS_AXES) {
|
|
5196
|
-
const allowed = availability[key];
|
|
5197
|
-
if (allowed === void 0) continue;
|
|
5198
|
-
if (allowed.length === 0) return false;
|
|
5199
|
-
if (!allowed.includes(ctx[ctxKey])) return false;
|
|
5200
|
-
}
|
|
5201
|
-
if (availability.surface !== void 0) {
|
|
5202
|
-
if (availability.surface.length === 0) return false;
|
|
5203
|
-
if (callCtx?.surface !== void 0 && !availability.surface.includes(callCtx.surface)) {
|
|
5204
|
-
return false;
|
|
5205
|
-
}
|
|
5206
|
-
}
|
|
5207
|
-
return true;
|
|
5208
|
-
}
|
|
5209
|
-
function checkEntryAvailability(availability, ctx, callCtx) {
|
|
5210
|
-
if (!availability) return { available: true, missingAxes: [] };
|
|
5211
|
-
const missing = [];
|
|
5212
|
-
for (const { key, ctxKey } of PROCESS_AXES) {
|
|
5213
|
-
const allowed = availability[key];
|
|
5214
|
-
if (allowed === void 0) continue;
|
|
5215
|
-
if (allowed.length === 0 || !allowed.includes(ctx[ctxKey])) {
|
|
5216
|
-
missing.push(key);
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5219
|
-
if (availability.surface !== void 0) {
|
|
5220
|
-
if (availability.surface.length === 0) {
|
|
5221
|
-
missing.push("surface");
|
|
5222
|
-
} else if (callCtx?.surface !== void 0 && !availability.surface.includes(callCtx.surface)) {
|
|
5223
|
-
missing.push("surface");
|
|
5224
|
-
}
|
|
5225
|
-
}
|
|
5226
|
-
return { available: missing.length === 0, missingAxes: missing };
|
|
5227
|
-
}
|
|
5228
|
-
function detectRuntime() {
|
|
5229
|
-
if (typeof globalThis !== "undefined" && "Bun" in globalThis) return "bun";
|
|
5230
|
-
if (typeof globalThis !== "undefined" && "Deno" in globalThis) return "deno";
|
|
5231
|
-
if ((0, import_env2.isEdgeRuntime)()) return "edge";
|
|
5232
|
-
return "node";
|
|
5233
|
-
}
|
|
5234
|
-
function detectDeployment(runtime) {
|
|
5235
|
-
const explicit = process.env["FRONTMCP_DEPLOYMENT_MODE"];
|
|
5236
|
-
if (explicit === "distributed") return "distributed";
|
|
5237
|
-
if (explicit === "serverless") return "serverless";
|
|
5238
|
-
if (runtime === "browser") return "browser";
|
|
5239
|
-
if ((0, import_env2.isServerless)()) return "serverless";
|
|
5240
|
-
return "standalone";
|
|
5241
|
-
}
|
|
5242
|
-
function detectRuntimeContext() {
|
|
5243
|
-
const runtime = detectRuntime();
|
|
5244
|
-
const os = process.platform;
|
|
5245
|
-
return {
|
|
5246
|
-
os,
|
|
5247
|
-
platform: os,
|
|
5248
|
-
runtime,
|
|
5249
|
-
deployment: detectDeployment(runtime),
|
|
5250
|
-
provider: detectProvider(),
|
|
5251
|
-
target: getBuildTarget(),
|
|
5252
|
-
env: process.env["NODE_ENV"] || "development"
|
|
5253
|
-
};
|
|
5254
|
-
}
|
|
5255
|
-
var cached3;
|
|
5256
|
-
function getRuntimeContext() {
|
|
5257
|
-
if (!cached3) {
|
|
5258
|
-
const detected = detectRuntimeContext();
|
|
5259
|
-
Object.defineProperty(detected, "env", {
|
|
5260
|
-
get: () => process.env["NODE_ENV"] || "development",
|
|
5261
|
-
enumerable: true,
|
|
5262
|
-
configurable: true
|
|
5263
|
-
});
|
|
5264
|
-
cached3 = detected;
|
|
5265
|
-
}
|
|
5266
|
-
return cached3;
|
|
5267
|
-
}
|
|
5268
|
-
function resetRuntimeContext() {
|
|
5269
|
-
cached3 = void 0;
|
|
5270
|
-
}
|
|
5178
|
+
var import_runtime_context = require("#runtime-context");
|
|
5271
5179
|
|
|
5272
5180
|
// libs/utils/src/storage/factory.ts
|
|
5273
5181
|
init_errors();
|
|
5274
5182
|
|
|
5275
5183
|
// libs/utils/src/storage/namespace.ts
|
|
5184
|
+
init_errors();
|
|
5276
5185
|
var NAMESPACE_SEPARATOR = ":";
|
|
5277
5186
|
function buildPrefix(name, id) {
|
|
5278
5187
|
if (id) {
|
|
@@ -5404,6 +5313,12 @@ var NamespacedStorageImpl = class _NamespacedStorageImpl {
|
|
|
5404
5313
|
async incrBy(key, amount) {
|
|
5405
5314
|
return this.adapter.incrBy(this.prefixKey(key), amount);
|
|
5406
5315
|
}
|
|
5316
|
+
async deleteIfEquals(key, expectedValue) {
|
|
5317
|
+
if (!this.adapter.deleteIfEquals) {
|
|
5318
|
+
throw new StorageNotSupportedError("deleteIfEquals", "this storage adapter");
|
|
5319
|
+
}
|
|
5320
|
+
return this.adapter.deleteIfEquals(this.prefixKey(key), expectedValue);
|
|
5321
|
+
}
|
|
5407
5322
|
// ============================================
|
|
5408
5323
|
// Pub/Sub (with channel prefixing)
|
|
5409
5324
|
// ============================================
|
|
@@ -5432,15 +5347,15 @@ function createNamespacedStorage(adapter, prefix) {
|
|
|
5432
5347
|
|
|
5433
5348
|
// libs/utils/src/storage/factory.ts
|
|
5434
5349
|
init_memory();
|
|
5435
|
-
var
|
|
5350
|
+
var import_env3 = require("#env");
|
|
5436
5351
|
function detectStorageType() {
|
|
5437
|
-
if ((0,
|
|
5352
|
+
if ((0, import_env3.getEnv)("UPSTASH_REDIS_REST_URL") && (0, import_env3.getEnv)("UPSTASH_REDIS_REST_TOKEN")) {
|
|
5438
5353
|
return "upstash";
|
|
5439
5354
|
}
|
|
5440
|
-
if ((0,
|
|
5355
|
+
if ((0, import_env3.getEnv)("KV_REST_API_URL") && (0, import_env3.getEnv)("KV_REST_API_TOKEN")) {
|
|
5441
5356
|
return "vercel-kv";
|
|
5442
5357
|
}
|
|
5443
|
-
if ((0,
|
|
5358
|
+
if ((0, import_env3.getEnv)("REDIS_URL") || (0, import_env3.getEnv)("REDIS_HOST")) {
|
|
5444
5359
|
return "redis";
|
|
5445
5360
|
}
|
|
5446
5361
|
return "memory";
|
|
@@ -5480,10 +5395,10 @@ async function createAdapter(type, config) {
|
|
|
5480
5395
|
}
|
|
5481
5396
|
async function createStorage(config = {}) {
|
|
5482
5397
|
let type = config.type ?? "auto";
|
|
5483
|
-
const fallback = config.fallback ?? ((0,
|
|
5398
|
+
const fallback = config.fallback ?? ((0, import_env3.isProduction)() ? "error" : "memory");
|
|
5484
5399
|
if (type === "auto") {
|
|
5485
5400
|
type = detectStorageType();
|
|
5486
|
-
if (type === "memory" && (0,
|
|
5401
|
+
if (type === "memory" && (0, import_env3.isProduction)()) {
|
|
5487
5402
|
console.warn(
|
|
5488
5403
|
"[storage] Warning: No distributed storage backend detected in production. Using in-memory storage. Set REDIS_URL, UPSTASH_REDIS_REST_URL, or KV_REST_API_URL."
|
|
5489
5404
|
);
|
|
@@ -6290,6 +6205,7 @@ function setMachineIdOverride(id) {
|
|
|
6290
6205
|
getEnv,
|
|
6291
6206
|
getEnvFlag,
|
|
6292
6207
|
getMachineId,
|
|
6208
|
+
getNodeEnv,
|
|
6293
6209
|
getOrCreateSecret,
|
|
6294
6210
|
getRuntimeContext,
|
|
6295
6211
|
getSpawnFn,
|