made-refine 0.2.0 → 0.2.1-beta.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/README.md +1 -1
- package/dist/cli.cjs +0 -177
- package/dist/index.js +314 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +314 -23
- package/dist/index.mjs.map +1 -1
- package/dist/vite.mjs +18 -1
- package/dist/vite.mjs.map +1 -1
- package/package.json +6 -10
- package/dist/mcp.cjs +0 -21328
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ This detects your framework, installs the package, previews file changes, and ap
|
|
|
31
31
|
- Renders inside Shadow DOM for full CSS isolation from your app
|
|
32
32
|
- Babel/Vite plugin adds source location metadata to every JSX element
|
|
33
33
|
- Hooks into React DevTools fiber tree for component name resolution
|
|
34
|
-
-
|
|
34
|
+
- Integrates with the desktop app MCP broker for hands-free agent workflows
|
|
35
35
|
|
|
36
36
|
## Supported frameworks
|
|
37
37
|
|
package/dist/cli.cjs
CHANGED
|
@@ -8435,185 +8435,8 @@ function installPackage(cwd) {
|
|
|
8435
8435
|
console.log(import_picocolors.default.dim(` ${cmd}`));
|
|
8436
8436
|
}
|
|
8437
8437
|
}
|
|
8438
|
-
var BABEL_JSON_CONFIG_FILES = [".babelrc", ".babelrc.json", "babel.config.json"];
|
|
8439
|
-
var BABEL_JS_CONFIG_FILES = [
|
|
8440
|
-
".babelrc.js",
|
|
8441
|
-
".babelrc.cjs",
|
|
8442
|
-
".babelrc.mjs",
|
|
8443
|
-
"babel.config.js",
|
|
8444
|
-
"babel.config.cjs",
|
|
8445
|
-
"babel.config.mjs"
|
|
8446
|
-
];
|
|
8447
|
-
function findBabelConfigFile(cwd) {
|
|
8448
|
-
for (const file of BABEL_JSON_CONFIG_FILES) {
|
|
8449
|
-
const absolutePath = import_path2.default.join(cwd, file);
|
|
8450
|
-
if (import_fs2.default.existsSync(absolutePath)) {
|
|
8451
|
-
return {
|
|
8452
|
-
absolutePath,
|
|
8453
|
-
relativePath: file,
|
|
8454
|
-
kind: "json"
|
|
8455
|
-
};
|
|
8456
|
-
}
|
|
8457
|
-
}
|
|
8458
|
-
for (const file of BABEL_JS_CONFIG_FILES) {
|
|
8459
|
-
const absolutePath = import_path2.default.join(cwd, file);
|
|
8460
|
-
if (import_fs2.default.existsSync(absolutePath)) {
|
|
8461
|
-
return {
|
|
8462
|
-
absolutePath,
|
|
8463
|
-
relativePath: file,
|
|
8464
|
-
kind: "js"
|
|
8465
|
-
};
|
|
8466
|
-
}
|
|
8467
|
-
}
|
|
8468
|
-
const packageJsonPath = import_path2.default.join(cwd, "package.json");
|
|
8469
|
-
if (import_fs2.default.existsSync(packageJsonPath)) {
|
|
8470
|
-
try {
|
|
8471
|
-
const packageJson = JSON.parse(import_fs2.default.readFileSync(packageJsonPath, "utf-8"));
|
|
8472
|
-
if (packageJson.babel !== void 0) {
|
|
8473
|
-
return {
|
|
8474
|
-
absolutePath: packageJsonPath,
|
|
8475
|
-
relativePath: "package.json#babel",
|
|
8476
|
-
kind: "package-json"
|
|
8477
|
-
};
|
|
8478
|
-
}
|
|
8479
|
-
} catch {
|
|
8480
|
-
}
|
|
8481
|
-
}
|
|
8482
|
-
return null;
|
|
8483
|
-
}
|
|
8484
|
-
function isMadeRefinePlugin(plugin) {
|
|
8485
|
-
if (typeof plugin === "string") {
|
|
8486
|
-
return plugin === "made-refine/babel";
|
|
8487
|
-
}
|
|
8488
|
-
if (Array.isArray(plugin) && typeof plugin[0] === "string") {
|
|
8489
|
-
return plugin[0] === "made-refine/babel";
|
|
8490
|
-
}
|
|
8491
|
-
return false;
|
|
8492
|
-
}
|
|
8493
|
-
function hasMadeRefinePlugin(plugins) {
|
|
8494
|
-
if (!Array.isArray(plugins)) return false;
|
|
8495
|
-
return plugins.some((plugin) => isMadeRefinePlugin(plugin));
|
|
8496
|
-
}
|
|
8497
|
-
function ensureMadeRefineInDevelopmentEnv(config) {
|
|
8498
|
-
if (hasMadeRefinePlugin(config.plugins)) {
|
|
8499
|
-
return "already-configured";
|
|
8500
|
-
}
|
|
8501
|
-
const existingEnv = config.env;
|
|
8502
|
-
if (existingEnv !== void 0 && (typeof existingEnv !== "object" || existingEnv === null || Array.isArray(existingEnv))) {
|
|
8503
|
-
return "unsupported-shape";
|
|
8504
|
-
}
|
|
8505
|
-
if (!config.env) {
|
|
8506
|
-
config.env = {};
|
|
8507
|
-
}
|
|
8508
|
-
const env = config.env;
|
|
8509
|
-
const existingDevelopment = env.development;
|
|
8510
|
-
if (existingDevelopment !== void 0 && (typeof existingDevelopment !== "object" || existingDevelopment === null || Array.isArray(existingDevelopment))) {
|
|
8511
|
-
return "unsupported-shape";
|
|
8512
|
-
}
|
|
8513
|
-
if (!env.development) {
|
|
8514
|
-
env.development = {};
|
|
8515
|
-
}
|
|
8516
|
-
const development = env.development;
|
|
8517
|
-
if (hasMadeRefinePlugin(development.plugins)) {
|
|
8518
|
-
return "already-configured";
|
|
8519
|
-
}
|
|
8520
|
-
if (development.plugins === void 0) {
|
|
8521
|
-
development.plugins = ["made-refine/babel"];
|
|
8522
|
-
return "updated";
|
|
8523
|
-
}
|
|
8524
|
-
if (!Array.isArray(development.plugins)) {
|
|
8525
|
-
return "unsupported-shape";
|
|
8526
|
-
}
|
|
8527
|
-
development.plugins = [...development.plugins, "made-refine/babel"];
|
|
8528
|
-
return "updated";
|
|
8529
|
-
}
|
|
8530
|
-
function printManualNextBabelInstructions() {
|
|
8531
|
-
console.log(
|
|
8532
|
-
import_picocolors.default.dim(
|
|
8533
|
-
" env: { development: { plugins: ['made-refine/babel'] } }\n (or add 'made-refine/babel' in your existing Babel plugin list)"
|
|
8534
|
-
)
|
|
8535
|
-
);
|
|
8536
|
-
}
|
|
8537
|
-
function configureNextBabel(cwd) {
|
|
8538
|
-
const configFile = findBabelConfigFile(cwd);
|
|
8539
|
-
if (!configFile) {
|
|
8540
|
-
console.log(
|
|
8541
|
-
import_picocolors.default.yellow(" \u26A0 No existing Babel config found \u2014 skipping Babel config to preserve SWC/Turbopack defaults.")
|
|
8542
|
-
);
|
|
8543
|
-
console.log(import_picocolors.default.dim(" Source detection will use React fiber fallback (less precise than Babel attributes)."));
|
|
8544
|
-
return;
|
|
8545
|
-
}
|
|
8546
|
-
if (configFile.kind === "js") {
|
|
8547
|
-
console.log(import_picocolors.default.yellow(` \u26A0 Found ${configFile.relativePath} (JS Babel config) \u2014 verify/add plugin manually:`));
|
|
8548
|
-
printManualNextBabelInstructions();
|
|
8549
|
-
return;
|
|
8550
|
-
}
|
|
8551
|
-
if (configFile.kind === "package-json") {
|
|
8552
|
-
let packageJson;
|
|
8553
|
-
try {
|
|
8554
|
-
packageJson = JSON.parse(import_fs2.default.readFileSync(configFile.absolutePath, "utf-8"));
|
|
8555
|
-
} catch {
|
|
8556
|
-
console.log(import_picocolors.default.yellow(" \u26A0 Could not parse package.json \u2014 add plugin manually:"));
|
|
8557
|
-
printManualNextBabelInstructions();
|
|
8558
|
-
return;
|
|
8559
|
-
}
|
|
8560
|
-
if (typeof packageJson !== "object" || packageJson === null || Array.isArray(packageJson)) {
|
|
8561
|
-
console.log(import_picocolors.default.yellow(" \u26A0 package.json has unsupported shape \u2014 add plugin manually:"));
|
|
8562
|
-
printManualNextBabelInstructions();
|
|
8563
|
-
return;
|
|
8564
|
-
}
|
|
8565
|
-
const pkg = packageJson;
|
|
8566
|
-
if (typeof pkg.babel !== "object" || pkg.babel === null || Array.isArray(pkg.babel)) {
|
|
8567
|
-
console.log(import_picocolors.default.yellow(" \u26A0 package.json#babel has unsupported shape \u2014 add plugin manually:"));
|
|
8568
|
-
printManualNextBabelInstructions();
|
|
8569
|
-
return;
|
|
8570
|
-
}
|
|
8571
|
-
const result2 = ensureMadeRefineInDevelopmentEnv(pkg.babel);
|
|
8572
|
-
if (result2 === "already-configured") {
|
|
8573
|
-
console.log(import_picocolors.default.dim(" package.json#babel \u2014 already configured"));
|
|
8574
|
-
return;
|
|
8575
|
-
}
|
|
8576
|
-
if (result2 === "unsupported-shape") {
|
|
8577
|
-
console.log(import_picocolors.default.yellow(" \u26A0 package.json#babel has unsupported shape \u2014 add plugin manually:"));
|
|
8578
|
-
printManualNextBabelInstructions();
|
|
8579
|
-
return;
|
|
8580
|
-
}
|
|
8581
|
-
import_fs2.default.writeFileSync(configFile.absolutePath, `${JSON.stringify(pkg, null, 2)}
|
|
8582
|
-
`, "utf-8");
|
|
8583
|
-
console.log(import_picocolors.default.green(' \u2713 Updated package.json#babel (added "made-refine/babel" in development env)'));
|
|
8584
|
-
return;
|
|
8585
|
-
}
|
|
8586
|
-
const content = import_fs2.default.readFileSync(configFile.absolutePath, "utf-8");
|
|
8587
|
-
let parsed;
|
|
8588
|
-
try {
|
|
8589
|
-
parsed = JSON.parse(content);
|
|
8590
|
-
} catch {
|
|
8591
|
-
console.log(import_picocolors.default.yellow(` \u26A0 Could not parse ${configFile.relativePath} as JSON \u2014 add plugin manually:`));
|
|
8592
|
-
printManualNextBabelInstructions();
|
|
8593
|
-
return;
|
|
8594
|
-
}
|
|
8595
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
8596
|
-
console.log(import_picocolors.default.yellow(` \u26A0 ${configFile.relativePath} has unsupported shape \u2014 add plugin manually:`));
|
|
8597
|
-
printManualNextBabelInstructions();
|
|
8598
|
-
return;
|
|
8599
|
-
}
|
|
8600
|
-
const result = ensureMadeRefineInDevelopmentEnv(parsed);
|
|
8601
|
-
if (result === "already-configured") {
|
|
8602
|
-
console.log(import_picocolors.default.dim(` ${configFile.relativePath} \u2014 already configured`));
|
|
8603
|
-
return;
|
|
8604
|
-
}
|
|
8605
|
-
if (result === "unsupported-shape") {
|
|
8606
|
-
console.log(import_picocolors.default.yellow(` \u26A0 ${configFile.relativePath} has unsupported shape \u2014 add plugin manually:`));
|
|
8607
|
-
printManualNextBabelInstructions();
|
|
8608
|
-
return;
|
|
8609
|
-
}
|
|
8610
|
-
import_fs2.default.writeFileSync(configFile.absolutePath, `${JSON.stringify(parsed, null, 2)}
|
|
8611
|
-
`, "utf-8");
|
|
8612
|
-
console.log(import_picocolors.default.green(` \u2713 Updated ${configFile.relativePath} (added "made-refine/babel" in development env)`));
|
|
8613
|
-
}
|
|
8614
8438
|
async function setupNextJs(cwd) {
|
|
8615
8439
|
console.log(import_picocolors.default.bold("\nConfiguring for Next.js...\n"));
|
|
8616
|
-
configureNextBabel(cwd);
|
|
8617
8440
|
const preloadSrc = import_path2.default.join(cwd, "node_modules/made-refine/dist/preload/preload.js");
|
|
8618
8441
|
const publicDir = import_path2.default.join(cwd, "public");
|
|
8619
8442
|
const preloadDest = import_path2.default.join(publicDir, "made-refine-preload.js");
|
package/dist/index.js
CHANGED
|
@@ -2425,44 +2425,335 @@ function hslToRgb(h, s, l) {
|
|
|
2425
2425
|
}
|
|
2426
2426
|
|
|
2427
2427
|
// src/mcp-client.ts
|
|
2428
|
-
var
|
|
2429
|
-
var
|
|
2430
|
-
|
|
2431
|
-
|
|
2428
|
+
var PROTOCOL_VERSION = 1;
|
|
2429
|
+
var BOOTSTRAP_TIMEOUT_MS = 2500;
|
|
2430
|
+
var REQUEST_TIMEOUT_MS = 3e3;
|
|
2431
|
+
var SESSION_EXPIRY_SKEW_MS = 5e3;
|
|
2432
|
+
var CLIENT_NAME = "made-refine";
|
|
2433
|
+
var DEFAULT_CLIENT_VERSION = "unknown";
|
|
2434
|
+
var BOOTSTRAP_ENV_KEYS = [
|
|
2435
|
+
"MADE_REFINE_MCP_BOOTSTRAP_URL",
|
|
2436
|
+
"VITE_MADE_REFINE_MCP_BOOTSTRAP_URL",
|
|
2437
|
+
"NEXT_PUBLIC_MADE_REFINE_MCP_BOOTSTRAP_URL"
|
|
2438
|
+
];
|
|
2439
|
+
var CLIENT_VERSION_ENV_KEYS = [
|
|
2440
|
+
"MADE_REFINE_VERSION",
|
|
2441
|
+
"VITE_MADE_REFINE_VERSION",
|
|
2442
|
+
"NEXT_PUBLIC_MADE_REFINE_VERSION"
|
|
2443
|
+
];
|
|
2444
|
+
var cachedSession = null;
|
|
2445
|
+
function getTimeoutSignal(timeoutMs) {
|
|
2446
|
+
const timeout = AbortSignal.timeout;
|
|
2447
|
+
return typeof timeout === "function" ? timeout(timeoutMs) : void 0;
|
|
2448
|
+
}
|
|
2449
|
+
function getRuntimeMcpConfig() {
|
|
2450
|
+
if (typeof window === "undefined") return null;
|
|
2451
|
+
const config = window.__MADE_REFINE_CONFIG__;
|
|
2452
|
+
const bootstrapUrl = config?.mcp?.bootstrapUrl ?? config?.mcpBootstrapUrl ?? window.__MADE_REFINE_MCP_BOOTSTRAP_URL__;
|
|
2453
|
+
if (!config?.mcp && typeof bootstrapUrl !== "string") return null;
|
|
2454
|
+
return {
|
|
2455
|
+
...config?.mcp ?? {},
|
|
2456
|
+
...typeof bootstrapUrl === "string" ? { bootstrapUrl } : {}
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
function toNonEmptyString(value) {
|
|
2460
|
+
if (typeof value !== "string") return null;
|
|
2461
|
+
const trimmed = value.trim();
|
|
2462
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2463
|
+
}
|
|
2464
|
+
function getStaticProcessEnvValue(key) {
|
|
2465
|
+
switch (key) {
|
|
2466
|
+
case "MADE_REFINE_MCP_BOOTSTRAP_URL":
|
|
2467
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.MADE_REFINE_MCP_BOOTSTRAP_URL : void 0);
|
|
2468
|
+
case "VITE_MADE_REFINE_MCP_BOOTSTRAP_URL":
|
|
2469
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.VITE_MADE_REFINE_MCP_BOOTSTRAP_URL : void 0);
|
|
2470
|
+
case "NEXT_PUBLIC_MADE_REFINE_MCP_BOOTSTRAP_URL":
|
|
2471
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_MADE_REFINE_MCP_BOOTSTRAP_URL : void 0);
|
|
2472
|
+
case "MADE_REFINE_VERSION":
|
|
2473
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.MADE_REFINE_VERSION : void 0);
|
|
2474
|
+
case "VITE_MADE_REFINE_VERSION":
|
|
2475
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.VITE_MADE_REFINE_VERSION : void 0);
|
|
2476
|
+
case "NEXT_PUBLIC_MADE_REFINE_VERSION":
|
|
2477
|
+
return toNonEmptyString(typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_MADE_REFINE_VERSION : void 0);
|
|
2478
|
+
default:
|
|
2479
|
+
return null;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
function getDynamicProcessEnvValue(keys) {
|
|
2483
|
+
const processLike = globalThis.process;
|
|
2484
|
+
const env = processLike?.env;
|
|
2485
|
+
if (!env) return null;
|
|
2486
|
+
for (const key of keys) {
|
|
2487
|
+
const value = toNonEmptyString(env[key]);
|
|
2488
|
+
if (value) return value;
|
|
2489
|
+
}
|
|
2490
|
+
return null;
|
|
2491
|
+
}
|
|
2492
|
+
function getEnvValue(keys) {
|
|
2493
|
+
for (const key of keys) {
|
|
2494
|
+
const processValue = getStaticProcessEnvValue(key);
|
|
2495
|
+
if (processValue) return processValue;
|
|
2496
|
+
}
|
|
2497
|
+
return getDynamicProcessEnvValue(keys);
|
|
2498
|
+
}
|
|
2499
|
+
function normalizeUrl(value) {
|
|
2500
|
+
if (typeof value !== "string") return null;
|
|
2501
|
+
const trimmed = value.trim();
|
|
2502
|
+
if (!trimmed) return null;
|
|
2503
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
2504
|
+
return trimmed.replace(/\/+$/, "");
|
|
2505
|
+
}
|
|
2506
|
+
if (typeof window === "undefined" || !window.location?.origin) return null;
|
|
2432
2507
|
try {
|
|
2433
|
-
|
|
2434
|
-
if (!res.ok) return null;
|
|
2435
|
-
const data = await res.json();
|
|
2436
|
-
cachedToken = typeof data.sessionToken === "string" ? data.sessionToken : null;
|
|
2437
|
-
return cachedToken;
|
|
2508
|
+
return new URL(trimmed, window.location.origin).toString().replace(/\/+$/, "");
|
|
2438
2509
|
} catch {
|
|
2439
2510
|
return null;
|
|
2440
2511
|
}
|
|
2441
2512
|
}
|
|
2442
|
-
|
|
2443
|
-
const
|
|
2513
|
+
function normalizeBootstrapUrl(value) {
|
|
2514
|
+
const normalized = normalizeUrl(value);
|
|
2515
|
+
if (!normalized) return null;
|
|
2516
|
+
try {
|
|
2517
|
+
const url = new URL(normalized);
|
|
2518
|
+
const normalizedPathname = url.pathname.replace(/\/+$/, "");
|
|
2519
|
+
url.pathname = normalizedPathname.endsWith("/v1/bootstrap") ? normalizedPathname : `${normalizedPathname}/v1/bootstrap`;
|
|
2520
|
+
return url.toString();
|
|
2521
|
+
} catch {
|
|
2522
|
+
return normalized.endsWith("/v1/bootstrap") ? normalized : `${normalized}/v1/bootstrap`;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
function toSafeBootstrapUrl(value) {
|
|
2526
|
+
const normalized = normalizeBootstrapUrl(value);
|
|
2527
|
+
if (!normalized) return null;
|
|
2528
|
+
return isLoopbackHttpUrl(normalized) ? normalized : null;
|
|
2529
|
+
}
|
|
2530
|
+
function joinUrl(base, path) {
|
|
2531
|
+
return `${base.replace(/\/+$/, "")}${path}`;
|
|
2532
|
+
}
|
|
2533
|
+
function readString(record, key) {
|
|
2534
|
+
const value = record?.[key];
|
|
2535
|
+
if (typeof value !== "string") return null;
|
|
2536
|
+
const trimmed = value.trim();
|
|
2537
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2538
|
+
}
|
|
2539
|
+
function parseExpiresAt(value) {
|
|
2540
|
+
if (typeof value !== "string") return null;
|
|
2541
|
+
const timestamp = Date.parse(value);
|
|
2542
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
2543
|
+
}
|
|
2544
|
+
function readNumber(record, key) {
|
|
2545
|
+
const value = record?.[key];
|
|
2546
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
2547
|
+
return value;
|
|
2548
|
+
}
|
|
2549
|
+
function isLoopbackIpv4(hostname) {
|
|
2550
|
+
if (!/^127(?:\.\d{1,3}){3}$/.test(hostname)) return false;
|
|
2551
|
+
const segments = hostname.split(".");
|
|
2552
|
+
return segments.every((segment) => {
|
|
2553
|
+
const value = Number(segment);
|
|
2554
|
+
return Number.isInteger(value) && value >= 0 && value <= 255;
|
|
2555
|
+
});
|
|
2556
|
+
}
|
|
2557
|
+
function isLoopbackHostname(hostname) {
|
|
2558
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost")) return true;
|
|
2559
|
+
if (hostname === "::1" || hostname === "[::1]") return true;
|
|
2560
|
+
return isLoopbackIpv4(hostname);
|
|
2561
|
+
}
|
|
2562
|
+
function isLoopbackHttpUrl(value) {
|
|
2563
|
+
try {
|
|
2564
|
+
const url = new URL(value);
|
|
2565
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
2566
|
+
return isLoopbackHostname(url.hostname);
|
|
2567
|
+
} catch {
|
|
2568
|
+
return false;
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
function buildBootstrapRequestBody(runtimeConfig) {
|
|
2572
|
+
const locationPath = typeof window !== "undefined" ? window.location.pathname : "";
|
|
2573
|
+
const locationOrigin = typeof window !== "undefined" ? window.location.origin : null;
|
|
2574
|
+
return {
|
|
2575
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
2576
|
+
projectFingerprint: {
|
|
2577
|
+
path: runtimeConfig?.projectFingerprint?.path || locationPath || "unknown",
|
|
2578
|
+
gitRemoteHash: runtimeConfig?.projectFingerprint?.gitRemoteHash ?? null
|
|
2579
|
+
},
|
|
2580
|
+
...runtimeConfig?.workspaceId ? {
|
|
2581
|
+
workspaceId: runtimeConfig.workspaceId
|
|
2582
|
+
} : {},
|
|
2583
|
+
client: {
|
|
2584
|
+
name: CLIENT_NAME,
|
|
2585
|
+
version: runtimeConfig?.clientVersion ?? getEnvValue(CLIENT_VERSION_ENV_KEYS) ?? DEFAULT_CLIENT_VERSION,
|
|
2586
|
+
origin: locationOrigin
|
|
2587
|
+
}
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
function resolveBootstrapUrl() {
|
|
2591
|
+
const runtimeConfig = getRuntimeMcpConfig();
|
|
2592
|
+
const runtimeUrl = toSafeBootstrapUrl(runtimeConfig?.bootstrapUrl);
|
|
2593
|
+
if (runtimeUrl) return runtimeUrl;
|
|
2594
|
+
const envUrl = toSafeBootstrapUrl(getEnvValue(BOOTSTRAP_ENV_KEYS));
|
|
2595
|
+
if (envUrl) return envUrl;
|
|
2596
|
+
return null;
|
|
2597
|
+
}
|
|
2598
|
+
function isSessionUsable(session, bootstrapUrl) {
|
|
2599
|
+
if (!session) return false;
|
|
2600
|
+
if (session.bootstrapUrl !== bootstrapUrl) return false;
|
|
2601
|
+
if (session.expiresAt == null) return true;
|
|
2602
|
+
return Date.now() < session.expiresAt - SESSION_EXPIRY_SKEW_MS;
|
|
2603
|
+
}
|
|
2604
|
+
async function readJsonRecord(response) {
|
|
2605
|
+
try {
|
|
2606
|
+
const data = await response.json();
|
|
2607
|
+
if (!data || typeof data !== "object") return null;
|
|
2608
|
+
return data;
|
|
2609
|
+
} catch {
|
|
2610
|
+
return null;
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
async function bootstrapSession(force = false) {
|
|
2614
|
+
const bootstrapUrl = resolveBootstrapUrl();
|
|
2615
|
+
if (!bootstrapUrl) {
|
|
2616
|
+
cachedSession = null;
|
|
2617
|
+
return null;
|
|
2618
|
+
}
|
|
2619
|
+
if (!force && isSessionUsable(cachedSession, bootstrapUrl)) {
|
|
2620
|
+
return cachedSession;
|
|
2621
|
+
}
|
|
2622
|
+
const runtimeConfig = getRuntimeMcpConfig();
|
|
2623
|
+
try {
|
|
2624
|
+
const response = await fetch(bootstrapUrl, {
|
|
2625
|
+
method: "POST",
|
|
2626
|
+
headers: { "Content-Type": "application/json" },
|
|
2627
|
+
body: JSON.stringify(buildBootstrapRequestBody(runtimeConfig)),
|
|
2628
|
+
signal: getTimeoutSignal(BOOTSTRAP_TIMEOUT_MS)
|
|
2629
|
+
});
|
|
2630
|
+
if (!response.ok) {
|
|
2631
|
+
cachedSession = null;
|
|
2632
|
+
return null;
|
|
2633
|
+
}
|
|
2634
|
+
const data = await readJsonRecord(response);
|
|
2635
|
+
const protocolVersion = readNumber(data, "protocolVersion");
|
|
2636
|
+
if (protocolVersion !== PROTOCOL_VERSION) {
|
|
2637
|
+
cachedSession = null;
|
|
2638
|
+
return null;
|
|
2639
|
+
}
|
|
2640
|
+
const ingestBaseUrl = normalizeUrl(readString(data, "ingestBaseUrl"));
|
|
2641
|
+
if (!ingestBaseUrl || !isLoopbackHttpUrl(ingestBaseUrl)) {
|
|
2642
|
+
cachedSession = null;
|
|
2643
|
+
return null;
|
|
2644
|
+
}
|
|
2645
|
+
const nextSession = {
|
|
2646
|
+
bootstrapUrl,
|
|
2647
|
+
ingestBaseUrl,
|
|
2648
|
+
serverInstanceId: readString(data, "serverInstanceId"),
|
|
2649
|
+
projectId: readString(data, "projectId"),
|
|
2650
|
+
sessionId: readString(data, "sessionId"),
|
|
2651
|
+
accessToken: readString(data, "accessToken"),
|
|
2652
|
+
expiresAt: parseExpiresAt(data?.expiresAt)
|
|
2653
|
+
};
|
|
2654
|
+
cachedSession = nextSession;
|
|
2655
|
+
return nextSession;
|
|
2656
|
+
} catch {
|
|
2657
|
+
cachedSession = null;
|
|
2658
|
+
return null;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
async function refreshSessionToken(session) {
|
|
2662
|
+
try {
|
|
2444
2663
|
const headers = { "Content-Type": "application/json" };
|
|
2445
|
-
if (
|
|
2446
|
-
|
|
2664
|
+
if (session.accessToken) {
|
|
2665
|
+
headers.Authorization = `Bearer ${session.accessToken}`;
|
|
2666
|
+
}
|
|
2667
|
+
const response = await fetch(joinUrl(session.ingestBaseUrl, "/v1/sessions/refresh"), {
|
|
2447
2668
|
method: "POST",
|
|
2448
2669
|
headers,
|
|
2449
|
-
body: JSON.stringify(
|
|
2670
|
+
body: JSON.stringify({
|
|
2671
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
2672
|
+
projectId: session.projectId,
|
|
2673
|
+
sessionId: session.sessionId
|
|
2674
|
+
}),
|
|
2675
|
+
signal: getTimeoutSignal(REQUEST_TIMEOUT_MS)
|
|
2450
2676
|
});
|
|
2677
|
+
if (response.status === 404 || response.status === 405) {
|
|
2678
|
+
return null;
|
|
2679
|
+
}
|
|
2680
|
+
if (!response.ok) {
|
|
2681
|
+
return null;
|
|
2682
|
+
}
|
|
2683
|
+
const data = await readJsonRecord(response);
|
|
2684
|
+
const nextToken = readString(data, "accessToken");
|
|
2685
|
+
if (!nextToken) {
|
|
2686
|
+
return null;
|
|
2687
|
+
}
|
|
2688
|
+
const refreshedSession = {
|
|
2689
|
+
...session,
|
|
2690
|
+
accessToken: nextToken,
|
|
2691
|
+
expiresAt: parseExpiresAt(data?.expiresAt) ?? session.expiresAt
|
|
2692
|
+
};
|
|
2693
|
+
cachedSession = refreshedSession;
|
|
2694
|
+
return refreshedSession;
|
|
2695
|
+
} catch {
|
|
2696
|
+
return null;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
function createIdempotencyKey() {
|
|
2700
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
2701
|
+
return crypto.randomUUID();
|
|
2702
|
+
}
|
|
2703
|
+
const timestamp = Date.now().toString(36);
|
|
2704
|
+
const random = Math.random().toString(36).slice(2, 12);
|
|
2705
|
+
return `${timestamp}-${random}`;
|
|
2706
|
+
}
|
|
2707
|
+
async function sendAnnotationRequest(session, path, payload, idempotencyKey) {
|
|
2708
|
+
const headers = {
|
|
2709
|
+
"Content-Type": "application/json",
|
|
2710
|
+
"X-Idempotency-Key": idempotencyKey
|
|
2451
2711
|
};
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2712
|
+
if (session.accessToken) {
|
|
2713
|
+
headers.Authorization = `Bearer ${session.accessToken}`;
|
|
2714
|
+
}
|
|
2715
|
+
return fetch(joinUrl(session.ingestBaseUrl, path), {
|
|
2716
|
+
method: "POST",
|
|
2717
|
+
headers,
|
|
2718
|
+
body: JSON.stringify(payload),
|
|
2719
|
+
signal: getTimeoutSignal(REQUEST_TIMEOUT_MS)
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
async function toClientResponse(response) {
|
|
2723
|
+
const data = await readJsonRecord(response);
|
|
2724
|
+
const bodyOk = data?.ok;
|
|
2725
|
+
const parsedOk = typeof bodyOk === "boolean" ? bodyOk : response.ok;
|
|
2726
|
+
return {
|
|
2727
|
+
ok: parsedOk && response.ok,
|
|
2728
|
+
id: readString(data, "id") ?? ""
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
async function postWithSessionToken(path, payload) {
|
|
2732
|
+
const idempotencyKey = createIdempotencyKey();
|
|
2733
|
+
let session = await bootstrapSession();
|
|
2734
|
+
if (!session) return { ok: false, id: "" };
|
|
2735
|
+
let response;
|
|
2736
|
+
try {
|
|
2737
|
+
response = await sendAnnotationRequest(session, path, payload, idempotencyKey);
|
|
2738
|
+
} catch {
|
|
2739
|
+
return { ok: false, id: "" };
|
|
2740
|
+
}
|
|
2741
|
+
if (response.status === 401 || response.status === 403) {
|
|
2742
|
+
session = await refreshSessionToken(session) ?? await bootstrapSession(true);
|
|
2743
|
+
if (!session) return { ok: false, id: "" };
|
|
2744
|
+
try {
|
|
2745
|
+
response = await sendAnnotationRequest(session, path, payload, idempotencyKey);
|
|
2746
|
+
} catch {
|
|
2747
|
+
return { ok: false, id: "" };
|
|
2748
|
+
}
|
|
2458
2749
|
}
|
|
2459
|
-
return
|
|
2750
|
+
return toClientResponse(response);
|
|
2460
2751
|
}
|
|
2461
2752
|
async function sendEditToAgent(edit) {
|
|
2462
|
-
return postWithSessionToken("/
|
|
2753
|
+
return postWithSessionToken("/v1/annotations/edit", edit);
|
|
2463
2754
|
}
|
|
2464
2755
|
async function sendCommentToAgent(comment) {
|
|
2465
|
-
return postWithSessionToken("/
|
|
2756
|
+
return postWithSessionToken("/v1/annotations/comment", comment);
|
|
2466
2757
|
}
|
|
2467
2758
|
|
|
2468
2759
|
// src/provider.tsx
|