made-refine 0.1.13 → 0.2.1-beta.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/README.md +1 -1
- package/dist/cli.cjs +0 -177
- package/dist/index.js +305 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +305 -33
- package/dist/index.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,302 @@ 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 getProcessEnvValue(keys) {
|
|
2460
|
+
const processLike = globalThis.process;
|
|
2461
|
+
const env = processLike?.env;
|
|
2462
|
+
if (!env) return null;
|
|
2463
|
+
for (const key of keys) {
|
|
2464
|
+
const value = env[key];
|
|
2465
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
2466
|
+
return value.trim();
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
return null;
|
|
2470
|
+
}
|
|
2471
|
+
function normalizeUrl(value) {
|
|
2472
|
+
if (typeof value !== "string") return null;
|
|
2473
|
+
const trimmed = value.trim();
|
|
2474
|
+
if (!trimmed) return null;
|
|
2475
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
2476
|
+
return trimmed.replace(/\/+$/, "");
|
|
2477
|
+
}
|
|
2478
|
+
if (typeof window === "undefined" || !window.location?.origin) return null;
|
|
2432
2479
|
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;
|
|
2480
|
+
return new URL(trimmed, window.location.origin).toString().replace(/\/+$/, "");
|
|
2438
2481
|
} catch {
|
|
2439
2482
|
return null;
|
|
2440
2483
|
}
|
|
2441
2484
|
}
|
|
2442
|
-
|
|
2443
|
-
const
|
|
2485
|
+
function normalizeBootstrapUrl(value) {
|
|
2486
|
+
const normalized = normalizeUrl(value);
|
|
2487
|
+
if (!normalized) return null;
|
|
2488
|
+
try {
|
|
2489
|
+
const url = new URL(normalized);
|
|
2490
|
+
const normalizedPathname = url.pathname.replace(/\/+$/, "");
|
|
2491
|
+
url.pathname = normalizedPathname.endsWith("/v1/bootstrap") ? normalizedPathname : `${normalizedPathname}/v1/bootstrap`;
|
|
2492
|
+
return url.toString();
|
|
2493
|
+
} catch {
|
|
2494
|
+
return normalized.endsWith("/v1/bootstrap") ? normalized : `${normalized}/v1/bootstrap`;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
function joinUrl(base, path) {
|
|
2498
|
+
return `${base.replace(/\/+$/, "")}${path}`;
|
|
2499
|
+
}
|
|
2500
|
+
function readString(record, key) {
|
|
2501
|
+
const value = record?.[key];
|
|
2502
|
+
if (typeof value !== "string") return null;
|
|
2503
|
+
const trimmed = value.trim();
|
|
2504
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2505
|
+
}
|
|
2506
|
+
function parseExpiresAt(value) {
|
|
2507
|
+
if (typeof value !== "string") return null;
|
|
2508
|
+
const timestamp = Date.parse(value);
|
|
2509
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
2510
|
+
}
|
|
2511
|
+
function readNumber(record, key) {
|
|
2512
|
+
const value = record?.[key];
|
|
2513
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
2514
|
+
return value;
|
|
2515
|
+
}
|
|
2516
|
+
function isLoopbackIpv4(hostname) {
|
|
2517
|
+
if (!/^127(?:\.\d{1,3}){3}$/.test(hostname)) return false;
|
|
2518
|
+
const segments = hostname.split(".");
|
|
2519
|
+
return segments.every((segment) => {
|
|
2520
|
+
const value = Number(segment);
|
|
2521
|
+
return Number.isInteger(value) && value >= 0 && value <= 255;
|
|
2522
|
+
});
|
|
2523
|
+
}
|
|
2524
|
+
function isLoopbackHostname(hostname) {
|
|
2525
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost")) return true;
|
|
2526
|
+
if (hostname === "::1" || hostname === "[::1]") return true;
|
|
2527
|
+
return isLoopbackIpv4(hostname);
|
|
2528
|
+
}
|
|
2529
|
+
function isLoopbackHttpUrl(value) {
|
|
2530
|
+
try {
|
|
2531
|
+
const url = new URL(value);
|
|
2532
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
2533
|
+
return isLoopbackHostname(url.hostname);
|
|
2534
|
+
} catch {
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
function buildBootstrapRequestBody(runtimeConfig) {
|
|
2539
|
+
const locationPath = typeof window !== "undefined" ? window.location.pathname : "";
|
|
2540
|
+
const locationOrigin = typeof window !== "undefined" ? window.location.origin : null;
|
|
2541
|
+
return {
|
|
2542
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
2543
|
+
projectFingerprint: {
|
|
2544
|
+
path: runtimeConfig?.projectFingerprint?.path || locationPath || "unknown",
|
|
2545
|
+
gitRemoteHash: runtimeConfig?.projectFingerprint?.gitRemoteHash ?? null
|
|
2546
|
+
},
|
|
2547
|
+
...runtimeConfig?.workspaceId ? {
|
|
2548
|
+
workspaceId: runtimeConfig.workspaceId
|
|
2549
|
+
} : {},
|
|
2550
|
+
client: {
|
|
2551
|
+
name: CLIENT_NAME,
|
|
2552
|
+
version: runtimeConfig?.clientVersion ?? getProcessEnvValue(CLIENT_VERSION_ENV_KEYS) ?? DEFAULT_CLIENT_VERSION,
|
|
2553
|
+
origin: locationOrigin
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
function resolveBootstrapUrl() {
|
|
2558
|
+
const runtimeConfig = getRuntimeMcpConfig();
|
|
2559
|
+
const runtimeUrl = normalizeBootstrapUrl(runtimeConfig?.bootstrapUrl);
|
|
2560
|
+
if (runtimeUrl) return runtimeUrl;
|
|
2561
|
+
const envUrl = normalizeBootstrapUrl(getProcessEnvValue(BOOTSTRAP_ENV_KEYS));
|
|
2562
|
+
if (envUrl) return envUrl;
|
|
2563
|
+
return null;
|
|
2564
|
+
}
|
|
2565
|
+
function isSessionUsable(session, bootstrapUrl) {
|
|
2566
|
+
if (!session) return false;
|
|
2567
|
+
if (session.bootstrapUrl !== bootstrapUrl) return false;
|
|
2568
|
+
if (session.expiresAt == null) return true;
|
|
2569
|
+
return Date.now() < session.expiresAt - SESSION_EXPIRY_SKEW_MS;
|
|
2570
|
+
}
|
|
2571
|
+
async function readJsonRecord(response) {
|
|
2572
|
+
try {
|
|
2573
|
+
const data = await response.json();
|
|
2574
|
+
if (!data || typeof data !== "object") return null;
|
|
2575
|
+
return data;
|
|
2576
|
+
} catch {
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
async function bootstrapSession(force = false) {
|
|
2581
|
+
const bootstrapUrl = resolveBootstrapUrl();
|
|
2582
|
+
if (!bootstrapUrl) {
|
|
2583
|
+
cachedSession = null;
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
if (!force && isSessionUsable(cachedSession, bootstrapUrl)) {
|
|
2587
|
+
return cachedSession;
|
|
2588
|
+
}
|
|
2589
|
+
const runtimeConfig = getRuntimeMcpConfig();
|
|
2590
|
+
try {
|
|
2591
|
+
const response = await fetch(bootstrapUrl, {
|
|
2592
|
+
method: "POST",
|
|
2593
|
+
headers: { "Content-Type": "application/json" },
|
|
2594
|
+
body: JSON.stringify(buildBootstrapRequestBody(runtimeConfig)),
|
|
2595
|
+
signal: getTimeoutSignal(BOOTSTRAP_TIMEOUT_MS)
|
|
2596
|
+
});
|
|
2597
|
+
if (!response.ok) {
|
|
2598
|
+
cachedSession = null;
|
|
2599
|
+
return null;
|
|
2600
|
+
}
|
|
2601
|
+
const data = await readJsonRecord(response);
|
|
2602
|
+
const protocolVersion = readNumber(data, "protocolVersion");
|
|
2603
|
+
if (protocolVersion !== PROTOCOL_VERSION) {
|
|
2604
|
+
cachedSession = null;
|
|
2605
|
+
return null;
|
|
2606
|
+
}
|
|
2607
|
+
const ingestBaseUrl = normalizeUrl(readString(data, "ingestBaseUrl"));
|
|
2608
|
+
if (!ingestBaseUrl || !isLoopbackHttpUrl(ingestBaseUrl)) {
|
|
2609
|
+
cachedSession = null;
|
|
2610
|
+
return null;
|
|
2611
|
+
}
|
|
2612
|
+
const nextSession = {
|
|
2613
|
+
bootstrapUrl,
|
|
2614
|
+
ingestBaseUrl,
|
|
2615
|
+
serverInstanceId: readString(data, "serverInstanceId"),
|
|
2616
|
+
projectId: readString(data, "projectId"),
|
|
2617
|
+
sessionId: readString(data, "sessionId"),
|
|
2618
|
+
accessToken: readString(data, "accessToken"),
|
|
2619
|
+
expiresAt: parseExpiresAt(data?.expiresAt)
|
|
2620
|
+
};
|
|
2621
|
+
cachedSession = nextSession;
|
|
2622
|
+
return nextSession;
|
|
2623
|
+
} catch {
|
|
2624
|
+
cachedSession = null;
|
|
2625
|
+
return null;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
async function refreshSessionToken(session) {
|
|
2629
|
+
try {
|
|
2444
2630
|
const headers = { "Content-Type": "application/json" };
|
|
2445
|
-
if (
|
|
2446
|
-
|
|
2631
|
+
if (session.accessToken) {
|
|
2632
|
+
headers.Authorization = `Bearer ${session.accessToken}`;
|
|
2633
|
+
}
|
|
2634
|
+
const response = await fetch(joinUrl(session.ingestBaseUrl, "/v1/sessions/refresh"), {
|
|
2447
2635
|
method: "POST",
|
|
2448
2636
|
headers,
|
|
2449
|
-
body: JSON.stringify(
|
|
2637
|
+
body: JSON.stringify({
|
|
2638
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
2639
|
+
projectId: session.projectId,
|
|
2640
|
+
sessionId: session.sessionId
|
|
2641
|
+
}),
|
|
2642
|
+
signal: getTimeoutSignal(REQUEST_TIMEOUT_MS)
|
|
2450
2643
|
});
|
|
2644
|
+
if (response.status === 404 || response.status === 405) {
|
|
2645
|
+
return null;
|
|
2646
|
+
}
|
|
2647
|
+
if (!response.ok) {
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
const data = await readJsonRecord(response);
|
|
2651
|
+
const nextToken = readString(data, "accessToken");
|
|
2652
|
+
if (!nextToken) {
|
|
2653
|
+
return null;
|
|
2654
|
+
}
|
|
2655
|
+
const refreshedSession = {
|
|
2656
|
+
...session,
|
|
2657
|
+
accessToken: nextToken,
|
|
2658
|
+
expiresAt: parseExpiresAt(data?.expiresAt) ?? session.expiresAt
|
|
2659
|
+
};
|
|
2660
|
+
cachedSession = refreshedSession;
|
|
2661
|
+
return refreshedSession;
|
|
2662
|
+
} catch {
|
|
2663
|
+
return null;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function createIdempotencyKey() {
|
|
2667
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
2668
|
+
return crypto.randomUUID();
|
|
2669
|
+
}
|
|
2670
|
+
const timestamp = Date.now().toString(36);
|
|
2671
|
+
const random = Math.random().toString(36).slice(2, 12);
|
|
2672
|
+
return `${timestamp}-${random}`;
|
|
2673
|
+
}
|
|
2674
|
+
async function sendAnnotationRequest(session, path, payload, idempotencyKey) {
|
|
2675
|
+
const headers = {
|
|
2676
|
+
"Content-Type": "application/json",
|
|
2677
|
+
"X-Idempotency-Key": idempotencyKey
|
|
2678
|
+
};
|
|
2679
|
+
if (session.accessToken) {
|
|
2680
|
+
headers.Authorization = `Bearer ${session.accessToken}`;
|
|
2681
|
+
}
|
|
2682
|
+
return fetch(joinUrl(session.ingestBaseUrl, path), {
|
|
2683
|
+
method: "POST",
|
|
2684
|
+
headers,
|
|
2685
|
+
body: JSON.stringify(payload),
|
|
2686
|
+
signal: getTimeoutSignal(REQUEST_TIMEOUT_MS)
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
async function toClientResponse(response) {
|
|
2690
|
+
const data = await readJsonRecord(response);
|
|
2691
|
+
const bodyOk = data?.ok;
|
|
2692
|
+
const parsedOk = typeof bodyOk === "boolean" ? bodyOk : response.ok;
|
|
2693
|
+
return {
|
|
2694
|
+
ok: parsedOk && response.ok,
|
|
2695
|
+
id: readString(data, "id") ?? ""
|
|
2451
2696
|
};
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2697
|
+
}
|
|
2698
|
+
async function postWithSessionToken(path, payload) {
|
|
2699
|
+
const idempotencyKey = createIdempotencyKey();
|
|
2700
|
+
let session = await bootstrapSession();
|
|
2701
|
+
if (!session) return { ok: false, id: "" };
|
|
2702
|
+
let response;
|
|
2703
|
+
try {
|
|
2704
|
+
response = await sendAnnotationRequest(session, path, payload, idempotencyKey);
|
|
2705
|
+
} catch {
|
|
2706
|
+
return { ok: false, id: "" };
|
|
2707
|
+
}
|
|
2708
|
+
if (response.status === 401 || response.status === 403) {
|
|
2709
|
+
session = await refreshSessionToken(session) ?? await bootstrapSession(true);
|
|
2710
|
+
if (!session) return { ok: false, id: "" };
|
|
2711
|
+
try {
|
|
2712
|
+
response = await sendAnnotationRequest(session, path, payload, idempotencyKey);
|
|
2713
|
+
} catch {
|
|
2714
|
+
return { ok: false, id: "" };
|
|
2715
|
+
}
|
|
2458
2716
|
}
|
|
2459
|
-
return
|
|
2717
|
+
return toClientResponse(response);
|
|
2460
2718
|
}
|
|
2461
2719
|
async function sendEditToAgent(edit) {
|
|
2462
|
-
return postWithSessionToken("/
|
|
2720
|
+
return postWithSessionToken("/v1/annotations/edit", edit);
|
|
2463
2721
|
}
|
|
2464
2722
|
async function sendCommentToAgent(comment) {
|
|
2465
|
-
return postWithSessionToken("/
|
|
2723
|
+
return postWithSessionToken("/v1/annotations/comment", comment);
|
|
2466
2724
|
}
|
|
2467
2725
|
|
|
2468
2726
|
// src/provider.tsx
|
|
@@ -4128,7 +4386,7 @@ function MeasurementOverlay({
|
|
|
4128
4386
|
children: [
|
|
4129
4387
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ElementHighlight, { element: selectedElement, color: BLUE }),
|
|
4130
4388
|
hoveredElement && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ElementHighlight, { element: hoveredElement, color: TOMATO, isDashed: true }),
|
|
4131
|
-
measurements.map((line
|
|
4389
|
+
measurements.map((line) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MeasurementLineComponent, { line }, `${line.direction}-${line.x1}-${line.y1}-${line.x2}-${line.y2}`))
|
|
4132
4390
|
]
|
|
4133
4391
|
}
|
|
4134
4392
|
);
|
|
@@ -4699,7 +4957,7 @@ function SelectionOverlay({
|
|
|
4699
4957
|
onDoubleClick: handleDoubleClick,
|
|
4700
4958
|
onMouseMove: handleMouseMove,
|
|
4701
4959
|
onMouseLeave: handleMouseLeave,
|
|
4702
|
-
children: moveHandleRects.map((targetRect
|
|
4960
|
+
children: moveHandleRects.map((targetRect) => {
|
|
4703
4961
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4704
4962
|
"button",
|
|
4705
4963
|
{
|
|
@@ -4726,7 +4984,7 @@ function SelectionOverlay({
|
|
|
4726
4984
|
},
|
|
4727
4985
|
onPointerDown: handleMoveHandlePointerDown(targetRect.target)
|
|
4728
4986
|
},
|
|
4729
|
-
`${
|
|
4987
|
+
`${targetRect.left}-${targetRect.top}-${targetRect.width}-${targetRect.height}`
|
|
4730
4988
|
);
|
|
4731
4989
|
})
|
|
4732
4990
|
}
|
|
@@ -4869,10 +5127,12 @@ function CommentPin({
|
|
|
4869
5127
|
}
|
|
4870
5128
|
),
|
|
4871
5129
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4872
|
-
"
|
|
5130
|
+
"button",
|
|
4873
5131
|
{
|
|
5132
|
+
type: "button",
|
|
4874
5133
|
"data-direct-edit": "comment-pin",
|
|
4875
|
-
|
|
5134
|
+
"aria-label": `Comment ${index}`,
|
|
5135
|
+
className: "group/pin fixed z-[99998] flex size-3 cursor-pointer items-center justify-center rounded-full border-none bg-blue-500 p-0 shadow-md ring-2 ring-white transition-transform hover:scale-[1.67] hover:shadow-lg",
|
|
4876
5136
|
style: {
|
|
4877
5137
|
left: position.x - 6,
|
|
4878
5138
|
top: position.y - 6,
|
|
@@ -4952,6 +5212,7 @@ function NewCommentInput({
|
|
|
4952
5212
|
"div",
|
|
4953
5213
|
{
|
|
4954
5214
|
ref: cardRef,
|
|
5215
|
+
role: "presentation",
|
|
4955
5216
|
"data-direct-edit": "comment-card",
|
|
4956
5217
|
className: cn(
|
|
4957
5218
|
"fixed z-[99999] flex items-center gap-1.5 rounded-xl outline outline-1 outline-foreground/10 bg-background p-1.5 shadow-lg",
|
|
@@ -5069,6 +5330,7 @@ function CommentThread({
|
|
|
5069
5330
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
5070
5331
|
"div",
|
|
5071
5332
|
{
|
|
5333
|
+
role: "presentation",
|
|
5072
5334
|
"data-direct-edit": "comment-card",
|
|
5073
5335
|
className: "fixed z-[99999] w-[280px] overflow-hidden rounded-xl outline outline-1 outline-foreground/10 bg-background shadow-lg",
|
|
5074
5336
|
style: {
|
|
@@ -5166,13 +5428,13 @@ function CommentThread({
|
|
|
5166
5428
|
] }),
|
|
5167
5429
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs leading-relaxed text-foreground", children: comment.text })
|
|
5168
5430
|
] }),
|
|
5169
|
-
comment.replies.map((reply
|
|
5431
|
+
comment.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "border-t border-border/30 px-3 py-2.5", children: [
|
|
5170
5432
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mb-1 flex items-center gap-2", children: [
|
|
5171
5433
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-blue-500 text-[10px] font-bold text-white", children: index }),
|
|
5172
5434
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[10px] text-muted-foreground", children: formatRelativeTime(reply.createdAt) })
|
|
5173
5435
|
] }),
|
|
5174
5436
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-xs leading-relaxed text-foreground", children: reply.text })
|
|
5175
|
-
] },
|
|
5437
|
+
] }, reply.createdAt))
|
|
5176
5438
|
] }),
|
|
5177
5439
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1.5 border-t border-border/50 px-2 py-1.5", children: [
|
|
5178
5440
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
@@ -7675,6 +7937,7 @@ function DirectEditPanelContent() {
|
|
|
7675
7937
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
7676
7938
|
"div",
|
|
7677
7939
|
{
|
|
7940
|
+
role: "presentation",
|
|
7678
7941
|
"data-direct-edit": "overlay",
|
|
7679
7942
|
className: cn("fixed inset-0 z-[99990] cursor-default"),
|
|
7680
7943
|
style: { pointerEvents: textEditingElement ? "none" : "auto" },
|
|
@@ -7756,7 +8019,7 @@ function DirectEditPanelContent() {
|
|
|
7756
8019
|
strokeWidth: 1,
|
|
7757
8020
|
strokeDasharray: "4 2"
|
|
7758
8021
|
},
|
|
7759
|
-
|
|
8022
|
+
`${r.left}-${r.top}-${r.width}-${r.height}`
|
|
7760
8023
|
);
|
|
7761
8024
|
})
|
|
7762
8025
|
]
|
|
@@ -8998,10 +9261,19 @@ ${text}`);
|
|
|
8998
9261
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
8999
9262
|
"div",
|
|
9000
9263
|
{
|
|
9264
|
+
role: "button",
|
|
9265
|
+
tabIndex: 0,
|
|
9001
9266
|
className: "group flex cursor-pointer items-start justify-between rounded-md px-1.5 py-1.5 text-xs transition-colors hover:bg-muted/50",
|
|
9002
9267
|
onClick: () => {
|
|
9003
9268
|
void handleCopyItem(item);
|
|
9004
9269
|
},
|
|
9270
|
+
onKeyDown: (e) => {
|
|
9271
|
+
if (e.target !== e.currentTarget) return;
|
|
9272
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
9273
|
+
e.preventDefault();
|
|
9274
|
+
void handleCopyItem(item);
|
|
9275
|
+
}
|
|
9276
|
+
},
|
|
9005
9277
|
children: [
|
|
9006
9278
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col items-start gap-[4px]", children: [
|
|
9007
9279
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Badge, { variant: "secondary", className: "h-6 shrink-0 px-1.5 text-xs", children: [
|
|
@@ -9033,7 +9305,7 @@ ${text}`);
|
|
|
9033
9305
|
)
|
|
9034
9306
|
]
|
|
9035
9307
|
},
|
|
9036
|
-
i
|
|
9308
|
+
item.type === "comment" ? item.comment.id : `edit-${i}`
|
|
9037
9309
|
);
|
|
9038
9310
|
}) })
|
|
9039
9311
|
]
|
|
@@ -9121,7 +9393,7 @@ ${text}`);
|
|
|
9121
9393
|
{ label: "Back / Exit", keys: ["Esc"] }
|
|
9122
9394
|
].map(({ label, keys }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex h-8 w-full items-center justify-between rounded-md px-2 text-xs text-muted-foreground", children: [
|
|
9123
9395
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: label }),
|
|
9124
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "flex items-center gap-0.5", children: keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("kbd", { className: popupKbdClass, children: k }, i)) })
|
|
9396
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "flex items-center gap-0.5", children: keys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("kbd", { className: popupKbdClass, children: k }, typeof k === "string" ? k : i)) })
|
|
9125
9397
|
] }, label)) })
|
|
9126
9398
|
]
|
|
9127
9399
|
}
|