frameshot-mcp 0.11.1 → 0.12.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/dist/{chunk-SP7UAIQL.js → chunk-J5JI2IC5.js} +44 -7
- package/dist/{chunk-RXVC5ZDW.js → chunk-SPOPEVPM.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.js +32 -16
- package/dist/renderer.d.ts +16 -0
- package/dist/renderer.js +1 -1
- package/dist/stubs/next-headers.js +21 -4
- package/dist/stubs/orm-proxy.js +66 -0
- package/dist/stubs/stubs/next-headers.js +21 -4
- package/dist/stubs/stubs/orm-proxy.js +66 -0
- package/package.json +1 -1
|
@@ -1058,6 +1058,23 @@ document.getElementById("app").innerHTML = html;
|
|
|
1058
1058
|
}
|
|
1059
1059
|
const adapterPlugins = await adapter.getPlugins(project.root);
|
|
1060
1060
|
const adapterAliases = adapter.getAliases(project.root, STUBS_DIR);
|
|
1061
|
+
const ORM_PACKAGES = [
|
|
1062
|
+
"@prisma/client",
|
|
1063
|
+
"drizzle-orm",
|
|
1064
|
+
"mongoose",
|
|
1065
|
+
"typeorm",
|
|
1066
|
+
"@mikro-orm/core",
|
|
1067
|
+
"sequelize",
|
|
1068
|
+
"knex",
|
|
1069
|
+
"objection",
|
|
1070
|
+
"bookshelf"
|
|
1071
|
+
];
|
|
1072
|
+
const ormStub = join18(STUBS_DIR, "orm-proxy.js");
|
|
1073
|
+
for (const pkg of ORM_PACKAGES) {
|
|
1074
|
+
if (existsSync4(join18(project.root, "node_modules", ...pkg.split("/")))) {
|
|
1075
|
+
adapterAliases[pkg] = ormStub;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1061
1078
|
const aliasEntries = [];
|
|
1062
1079
|
for (const [key, value] of Object.entries(project.pathAliases)) {
|
|
1063
1080
|
aliasEntries.push({
|
|
@@ -1411,7 +1428,7 @@ var DiffUseCase = class {
|
|
|
1411
1428
|
};
|
|
1412
1429
|
|
|
1413
1430
|
// src/use-cases/render.ts
|
|
1414
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
1431
|
+
import { readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
1415
1432
|
import { extname as extname2 } from "path";
|
|
1416
1433
|
|
|
1417
1434
|
// src/infrastructure/page-utils.ts
|
|
@@ -1510,9 +1527,10 @@ var RenderUseCase = class {
|
|
|
1510
1527
|
css: opts.css,
|
|
1511
1528
|
tailwindVersion: opts.tailwindVersion
|
|
1512
1529
|
});
|
|
1513
|
-
|
|
1530
|
+
const results = await Promise.all(
|
|
1514
1531
|
opts.engines.map((engine) => this.renderHtml(engine, html, opts))
|
|
1515
1532
|
);
|
|
1533
|
+
return this.maybeSave(results, opts.outputPath);
|
|
1516
1534
|
}
|
|
1517
1535
|
async renderFile(filePath, options = {}) {
|
|
1518
1536
|
const opts = this.resolveOptions(options);
|
|
@@ -1525,10 +1543,10 @@ var RenderUseCase = class {
|
|
|
1525
1543
|
props: options.props,
|
|
1526
1544
|
projectRoot: options.projectRoot
|
|
1527
1545
|
});
|
|
1528
|
-
const
|
|
1546
|
+
const raw2 = await Promise.all(
|
|
1529
1547
|
opts.engines.map((engine) => this.renderUrl(engine, url, opts))
|
|
1530
1548
|
);
|
|
1531
|
-
return { results:
|
|
1549
|
+
return { results: this.maybeSave(raw2, opts.outputPath), mode: "vite" };
|
|
1532
1550
|
} catch (err) {
|
|
1533
1551
|
fallbackReason = err instanceof Error ? err.message : String(err);
|
|
1534
1552
|
process.stderr.write(
|
|
@@ -1540,8 +1558,12 @@ var RenderUseCase = class {
|
|
|
1540
1558
|
fallbackReason = "Vite bundler not available";
|
|
1541
1559
|
}
|
|
1542
1560
|
const code = readFileSync3(filePath, "utf-8");
|
|
1543
|
-
const
|
|
1544
|
-
return {
|
|
1561
|
+
const raw = await this.render(code, extFramework, options);
|
|
1562
|
+
return {
|
|
1563
|
+
results: this.maybeSave(raw, opts.outputPath),
|
|
1564
|
+
mode: "cdn",
|
|
1565
|
+
fallbackReason
|
|
1566
|
+
};
|
|
1545
1567
|
}
|
|
1546
1568
|
async renderInteraction(code, framework, interactions, options = {}) {
|
|
1547
1569
|
const opts = this.resolveOptions(options);
|
|
@@ -1729,6 +1751,19 @@ var RenderUseCase = class {
|
|
|
1729
1751
|
height: Math.max(measured.height + AUTO_FIT_PAD * 2, AUTO_FIT_MIN.height)
|
|
1730
1752
|
};
|
|
1731
1753
|
}
|
|
1754
|
+
/**
|
|
1755
|
+
* When outputPath is set, write the PNG to disk and replace the inline
|
|
1756
|
+
* base64 with an empty string to keep the MCP response small.
|
|
1757
|
+
*/
|
|
1758
|
+
maybeSave(results, outputPath) {
|
|
1759
|
+
if (!outputPath) return results;
|
|
1760
|
+
return results.map((r) => {
|
|
1761
|
+
const filePath = results.length === 1 ? outputPath : outputPath.replace(/\.png$/i, `-${r.engine}.png`);
|
|
1762
|
+
const buf = Buffer.from(r.image, "base64");
|
|
1763
|
+
writeFileSync(filePath, buf);
|
|
1764
|
+
return { ...r, image: "", savedPath: filePath };
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1732
1767
|
resolveOptions(partial) {
|
|
1733
1768
|
return {
|
|
1734
1769
|
viewport: partial.viewport ?? DEFAULT_RENDER_OPTIONS.viewport,
|
|
@@ -1738,7 +1773,9 @@ var RenderUseCase = class {
|
|
|
1738
1773
|
css: partial.css ?? DEFAULT_RENDER_OPTIONS.css,
|
|
1739
1774
|
tailwindVersion: partial.tailwindVersion ?? DEFAULT_RENDER_OPTIONS.tailwindVersion,
|
|
1740
1775
|
waitFor: partial.waitFor ?? DEFAULT_RENDER_OPTIONS.waitFor,
|
|
1741
|
-
autoFit: partial.autoFit ?? DEFAULT_RENDER_OPTIONS.autoFit
|
|
1776
|
+
autoFit: partial.autoFit ?? DEFAULT_RENDER_OPTIONS.autoFit,
|
|
1777
|
+
mock: partial.mock,
|
|
1778
|
+
outputPath: partial.outputPath
|
|
1742
1779
|
};
|
|
1743
1780
|
}
|
|
1744
1781
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createContainer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SPOPEVPM.js";
|
|
5
5
|
import {
|
|
6
6
|
EXT_TO_FRAMEWORK
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-J5JI2IC5.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
10
10
|
import { mkdirSync } from "fs";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createContainer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SPOPEVPM.js";
|
|
5
5
|
import {
|
|
6
6
|
DEVICE_PRESETS,
|
|
7
7
|
EXT_TO_FRAMEWORK,
|
|
8
8
|
__export
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-J5JI2IC5.js";
|
|
10
10
|
|
|
11
11
|
// src/index.ts
|
|
12
12
|
import { execSync } from "child_process";
|
|
@@ -14531,6 +14531,9 @@ config(en_default());
|
|
|
14531
14531
|
var mockSchema = external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe(
|
|
14532
14532
|
"Mock network responses. Keys: URL pattern (path '/api/users', glob '**/api/*', or full URL). Values: response body (auto-serialized as JSON) or { status, contentType, body, headers }."
|
|
14533
14533
|
);
|
|
14534
|
+
var outputPathSchema = external_exports.string().optional().describe(
|
|
14535
|
+
"Absolute path to save the PNG (e.g. '/tmp/button.png'). When set, returns a text summary instead of base64 image data \u2014 use this in long agent sessions to avoid context bloat."
|
|
14536
|
+
);
|
|
14534
14537
|
function wrapHandler(handler) {
|
|
14535
14538
|
return async (args) => {
|
|
14536
14539
|
try {
|
|
@@ -14893,7 +14896,8 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14893
14896
|
projectRoot: external_exports.string().optional().describe(
|
|
14894
14897
|
"Project root directory override (defaults to auto-detect from file path)"
|
|
14895
14898
|
),
|
|
14896
|
-
mock: mockSchema
|
|
14899
|
+
mock: mockSchema,
|
|
14900
|
+
outputPath: outputPathSchema
|
|
14897
14901
|
},
|
|
14898
14902
|
wrapHandler(
|
|
14899
14903
|
async ({
|
|
@@ -14904,7 +14908,8 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14904
14908
|
darkMode,
|
|
14905
14909
|
tailwindVersion,
|
|
14906
14910
|
projectRoot,
|
|
14907
|
-
mock
|
|
14911
|
+
mock,
|
|
14912
|
+
outputPath
|
|
14908
14913
|
}) => {
|
|
14909
14914
|
const start = performance.now();
|
|
14910
14915
|
const { results, mode, fallbackReason } = await useCase.renderFile(
|
|
@@ -14917,7 +14922,8 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14917
14922
|
darkMode,
|
|
14918
14923
|
tailwindVersion,
|
|
14919
14924
|
projectRoot,
|
|
14920
|
-
mock
|
|
14925
|
+
mock,
|
|
14926
|
+
outputPath
|
|
14921
14927
|
}
|
|
14922
14928
|
);
|
|
14923
14929
|
const elapsed = Math.round(performance.now() - start);
|
|
@@ -14926,19 +14932,29 @@ function registerRenderFileTools(server2, useCase) {
|
|
|
14926
14932
|
const fallbackNote = mode === "cdn" && fallbackReason ? `
|
|
14927
14933
|
\u2139\uFE0F Fell back to CDN pipeline: ${fallbackReason}
|
|
14928
14934
|
Imports from node_modules may not resolve. To fix: install vite as a devDep and add a minimal vite.config.` : "";
|
|
14929
|
-
const content = results.flatMap((r) =>
|
|
14930
|
-
{
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14935
|
+
const content = results.flatMap((r) => {
|
|
14936
|
+
if (r.savedPath) {
|
|
14937
|
+
return [
|
|
14938
|
+
{
|
|
14939
|
+
type: "text",
|
|
14940
|
+
text: `\u2713 Saved to ${r.savedPath} (${r.width}\xD7${r.height}, ${elapsed}ms)${fallbackNote}`
|
|
14941
|
+
}
|
|
14942
|
+
];
|
|
14943
|
+
}
|
|
14944
|
+
return [
|
|
14945
|
+
{
|
|
14946
|
+
type: "image",
|
|
14947
|
+
data: r.image,
|
|
14948
|
+
mimeType: "image/png"
|
|
14949
|
+
},
|
|
14950
|
+
{
|
|
14951
|
+
type: "text",
|
|
14952
|
+
text: `[${mode}/${framework}] ${r.width}x${r.height} (${elapsed}ms)${r.consoleErrors.length ? `
|
|
14938
14953
|
\u26A0\uFE0F Console errors:
|
|
14939
14954
|
${r.consoleErrors.join("\n")}` : ""}${fallbackNote}`
|
|
14940
|
-
|
|
14941
|
-
|
|
14955
|
+
}
|
|
14956
|
+
];
|
|
14957
|
+
});
|
|
14942
14958
|
return { content };
|
|
14943
14959
|
}
|
|
14944
14960
|
)
|
package/dist/renderer.d.ts
CHANGED
|
@@ -30,6 +30,15 @@ interface RenderOptions {
|
|
|
30
30
|
* }
|
|
31
31
|
*/
|
|
32
32
|
mock?: Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* Write the screenshot to disk instead of returning it inline as base64.
|
|
35
|
+
* When set, tools return a short text summary ("Saved to /path 400×300 12KB")
|
|
36
|
+
* instead of the full image data. This prevents large base64 blobs from
|
|
37
|
+
* filling the LLM's context window in multi-step agent workflows.
|
|
38
|
+
*
|
|
39
|
+
* @example outputPath: "/tmp/my-component.png"
|
|
40
|
+
*/
|
|
41
|
+
outputPath?: string;
|
|
33
42
|
}
|
|
34
43
|
interface ScreenshotResult {
|
|
35
44
|
engine: Engine;
|
|
@@ -37,6 +46,8 @@ interface ScreenshotResult {
|
|
|
37
46
|
width: number;
|
|
38
47
|
height: number;
|
|
39
48
|
consoleErrors: string[];
|
|
49
|
+
/** Set when outputPath was provided — the image was saved here instead of inline. */
|
|
50
|
+
savedPath?: string;
|
|
40
51
|
}
|
|
41
52
|
interface DiffResult {
|
|
42
53
|
before: string;
|
|
@@ -254,6 +265,11 @@ declare class RenderUseCase {
|
|
|
254
265
|
private renderUrl;
|
|
255
266
|
private navigateAndWait;
|
|
256
267
|
private resolveAutoFitViewport;
|
|
268
|
+
/**
|
|
269
|
+
* When outputPath is set, write the PNG to disk and replace the inline
|
|
270
|
+
* base64 with an empty string to keep the MCP response small.
|
|
271
|
+
*/
|
|
272
|
+
private maybeSave;
|
|
257
273
|
private resolveOptions;
|
|
258
274
|
}
|
|
259
275
|
|
package/dist/renderer.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
// Stub for next/headers — server-only APIs that must not crash during component preview
|
|
1
|
+
// Stub for next/headers — server-only APIs that must not crash during component preview.
|
|
2
|
+
//
|
|
3
|
+
// Next.js 15 made headers()/cookies() async. We export both sync and async
|
|
4
|
+
// variants so components compiled for either version work.
|
|
5
|
+
|
|
2
6
|
const emptyMap = {
|
|
3
7
|
get: () => undefined,
|
|
4
8
|
getAll: () => [],
|
|
@@ -10,10 +14,23 @@ const emptyMap = {
|
|
|
10
14
|
set: () => {},
|
|
11
15
|
delete: () => {},
|
|
12
16
|
toString: () => "",
|
|
17
|
+
toJSON: () => ({}),
|
|
18
|
+
append: () => {},
|
|
19
|
+
[Symbol.iterator]: () => [][Symbol.iterator](),
|
|
13
20
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const
|
|
21
|
+
|
|
22
|
+
// Next.js 15+: headers() and cookies() are async
|
|
23
|
+
export const headers = async () => emptyMap;
|
|
24
|
+
export const cookies = async () => emptyMap;
|
|
25
|
+
|
|
26
|
+
// Next.js 15 additions
|
|
27
|
+
export const connection = async () => {};
|
|
28
|
+
export const after = (fn) => {
|
|
29
|
+
if (typeof fn === "function") fn();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Draft mode
|
|
33
|
+
export const draftMode = async () => ({
|
|
17
34
|
isEnabled: false,
|
|
18
35
|
enable: () => {},
|
|
19
36
|
disable: () => {},
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal stub for server-only ORM/database packages.
|
|
3
|
+
*
|
|
4
|
+
* Prisma, Drizzle, Mongoose, TypeORM etc. require a running database and
|
|
5
|
+
* Node.js-only modules (net, tls, dns) that break in a browser/Vite context.
|
|
6
|
+
*
|
|
7
|
+
* This stub returns a Proxy that:
|
|
8
|
+
* - Returns empty arrays for .findMany(), .find(), .all() style calls
|
|
9
|
+
* - Returns null for .findFirst(), .findOne() style calls
|
|
10
|
+
* - Returns the input for .create(), .update(), .save() style calls
|
|
11
|
+
* - Returns { count: 0 } for .count(), .deleteMany()
|
|
12
|
+
* - Chains infinitely (every property returns another proxy)
|
|
13
|
+
* - Never throws — components render in their "empty data" state
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function makeProxy(depth = 0) {
|
|
17
|
+
if (depth > 8) return undefined; // prevent infinite chain
|
|
18
|
+
return new Proxy(() => Promise.resolve([]), {
|
|
19
|
+
get(_, prop) {
|
|
20
|
+
if (prop === "then") return undefined; // not a thenable
|
|
21
|
+
if (prop === Symbol.toPrimitive) return () => "[ORM stub]";
|
|
22
|
+
if (prop === Symbol.iterator) return function* () {};
|
|
23
|
+
// Common result shapes
|
|
24
|
+
if (
|
|
25
|
+
typeof prop === "string" &&
|
|
26
|
+
/^(findMany|findAll|all|list|getAll|fetchAll)$/.test(prop)
|
|
27
|
+
)
|
|
28
|
+
return () => Promise.resolve([]);
|
|
29
|
+
if (
|
|
30
|
+
typeof prop === "string" &&
|
|
31
|
+
/^(findFirst|findOne|findUnique|get|fetch|findById)$/.test(prop)
|
|
32
|
+
)
|
|
33
|
+
return () => Promise.resolve(null);
|
|
34
|
+
if (
|
|
35
|
+
typeof prop === "string" &&
|
|
36
|
+
/^(count|countDocuments|estimatedDocumentCount)$/.test(prop)
|
|
37
|
+
)
|
|
38
|
+
return () => Promise.resolve(0);
|
|
39
|
+
if (
|
|
40
|
+
typeof prop === "string" &&
|
|
41
|
+
/^(create|insert|save|update|upsert|set)$/.test(prop)
|
|
42
|
+
)
|
|
43
|
+
return (data) => Promise.resolve(data ?? {});
|
|
44
|
+
if (
|
|
45
|
+
typeof prop === "string" &&
|
|
46
|
+
/^(delete|deleteMany|remove|destroy)$/.test(prop)
|
|
47
|
+
)
|
|
48
|
+
return () => Promise.resolve({ count: 0 });
|
|
49
|
+
return makeProxy(depth + 1);
|
|
50
|
+
},
|
|
51
|
+
apply() {
|
|
52
|
+
return Promise.resolve([]);
|
|
53
|
+
},
|
|
54
|
+
construct() {
|
|
55
|
+
return makeProxy(depth + 1);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Default export and named exports both return a proxy
|
|
61
|
+
export default makeProxy();
|
|
62
|
+
export const PrismaClient = () => makeProxy();
|
|
63
|
+
export const drizzle = () => makeProxy();
|
|
64
|
+
export const createClient = () => makeProxy();
|
|
65
|
+
export const getConnection = () => makeProxy();
|
|
66
|
+
export const DataSource = () => makeProxy();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
// Stub for next/headers — server-only APIs that must not crash during component preview
|
|
1
|
+
// Stub for next/headers — server-only APIs that must not crash during component preview.
|
|
2
|
+
//
|
|
3
|
+
// Next.js 15 made headers()/cookies() async. We export both sync and async
|
|
4
|
+
// variants so components compiled for either version work.
|
|
5
|
+
|
|
2
6
|
const emptyMap = {
|
|
3
7
|
get: () => undefined,
|
|
4
8
|
getAll: () => [],
|
|
@@ -10,10 +14,23 @@ const emptyMap = {
|
|
|
10
14
|
set: () => {},
|
|
11
15
|
delete: () => {},
|
|
12
16
|
toString: () => "",
|
|
17
|
+
toJSON: () => ({}),
|
|
18
|
+
append: () => {},
|
|
19
|
+
[Symbol.iterator]: () => [][Symbol.iterator](),
|
|
13
20
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const
|
|
21
|
+
|
|
22
|
+
// Next.js 15+: headers() and cookies() are async
|
|
23
|
+
export const headers = async () => emptyMap;
|
|
24
|
+
export const cookies = async () => emptyMap;
|
|
25
|
+
|
|
26
|
+
// Next.js 15 additions
|
|
27
|
+
export const connection = async () => {};
|
|
28
|
+
export const after = (fn) => {
|
|
29
|
+
if (typeof fn === "function") fn();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Draft mode
|
|
33
|
+
export const draftMode = async () => ({
|
|
17
34
|
isEnabled: false,
|
|
18
35
|
enable: () => {},
|
|
19
36
|
disable: () => {},
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal stub for server-only ORM/database packages.
|
|
3
|
+
*
|
|
4
|
+
* Prisma, Drizzle, Mongoose, TypeORM etc. require a running database and
|
|
5
|
+
* Node.js-only modules (net, tls, dns) that break in a browser/Vite context.
|
|
6
|
+
*
|
|
7
|
+
* This stub returns a Proxy that:
|
|
8
|
+
* - Returns empty arrays for .findMany(), .find(), .all() style calls
|
|
9
|
+
* - Returns null for .findFirst(), .findOne() style calls
|
|
10
|
+
* - Returns the input for .create(), .update(), .save() style calls
|
|
11
|
+
* - Returns { count: 0 } for .count(), .deleteMany()
|
|
12
|
+
* - Chains infinitely (every property returns another proxy)
|
|
13
|
+
* - Never throws — components render in their "empty data" state
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function makeProxy(depth = 0) {
|
|
17
|
+
if (depth > 8) return undefined; // prevent infinite chain
|
|
18
|
+
return new Proxy(() => Promise.resolve([]), {
|
|
19
|
+
get(_, prop) {
|
|
20
|
+
if (prop === "then") return undefined; // not a thenable
|
|
21
|
+
if (prop === Symbol.toPrimitive) return () => "[ORM stub]";
|
|
22
|
+
if (prop === Symbol.iterator) return function* () {};
|
|
23
|
+
// Common result shapes
|
|
24
|
+
if (
|
|
25
|
+
typeof prop === "string" &&
|
|
26
|
+
/^(findMany|findAll|all|list|getAll|fetchAll)$/.test(prop)
|
|
27
|
+
)
|
|
28
|
+
return () => Promise.resolve([]);
|
|
29
|
+
if (
|
|
30
|
+
typeof prop === "string" &&
|
|
31
|
+
/^(findFirst|findOne|findUnique|get|fetch|findById)$/.test(prop)
|
|
32
|
+
)
|
|
33
|
+
return () => Promise.resolve(null);
|
|
34
|
+
if (
|
|
35
|
+
typeof prop === "string" &&
|
|
36
|
+
/^(count|countDocuments|estimatedDocumentCount)$/.test(prop)
|
|
37
|
+
)
|
|
38
|
+
return () => Promise.resolve(0);
|
|
39
|
+
if (
|
|
40
|
+
typeof prop === "string" &&
|
|
41
|
+
/^(create|insert|save|update|upsert|set)$/.test(prop)
|
|
42
|
+
)
|
|
43
|
+
return (data) => Promise.resolve(data ?? {});
|
|
44
|
+
if (
|
|
45
|
+
typeof prop === "string" &&
|
|
46
|
+
/^(delete|deleteMany|remove|destroy)$/.test(prop)
|
|
47
|
+
)
|
|
48
|
+
return () => Promise.resolve({ count: 0 });
|
|
49
|
+
return makeProxy(depth + 1);
|
|
50
|
+
},
|
|
51
|
+
apply() {
|
|
52
|
+
return Promise.resolve([]);
|
|
53
|
+
},
|
|
54
|
+
construct() {
|
|
55
|
+
return makeProxy(depth + 1);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Default export and named exports both return a proxy
|
|
61
|
+
export default makeProxy();
|
|
62
|
+
export const PrismaClient = () => makeProxy();
|
|
63
|
+
export const drizzle = () => makeProxy();
|
|
64
|
+
export const createClient = () => makeProxy();
|
|
65
|
+
export const getConnection = () => makeProxy();
|
|
66
|
+
export const DataSource = () => makeProxy();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frameshot-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Zero-config visual testing for AI agents. Render project components with full Vite dependency resolution — no stories, no config.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|