skybridge 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/build-helpers.d.ts +1 -1
- package/dist/cli/build-helpers.js +7 -2
- package/dist/cli/build-helpers.js.map +1 -1
- package/dist/cli/build-helpers.test.js +11 -0
- package/dist/cli/build-helpers.test.js.map +1 -1
- package/dist/cli/build-steps.js +3 -3
- package/dist/cli/build-steps.js.map +1 -1
- package/dist/cli/resolve-skybridge-config.d.ts +5 -0
- package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
- package/dist/cli/resolve-skybridge-config.js.map +1 -0
- package/dist/commands/dev.js +2 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/web/plugin/plugin.d.ts +6 -0
- package/dist/web/plugin/plugin.js +3 -2
- package/dist/web/plugin/plugin.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/resolve-views-dir.d.ts +0 -1
- package/dist/cli/resolve-views-dir.js.map +0 -1
|
@@ -8,4 +8,4 @@ export declare function ensureAssetsDir(assetsDir: string): void;
|
|
|
8
8
|
export declare const VERCEL_FUNCTION_NAME = "mcp";
|
|
9
9
|
export declare const VERCEL_CONFIG: unknown;
|
|
10
10
|
export declare const VERCEL_VC_CONFIG: unknown;
|
|
11
|
-
export declare function emitVercelBuildOutput(root: string): Promise<void>;
|
|
11
|
+
export declare function emitVercelBuildOutput(root: string, serverExternal?: string[]): Promise<void>;
|
|
@@ -64,7 +64,7 @@ export const VERCEL_VC_CONFIG = {
|
|
|
64
64
|
// directly would skip that priming and 500 on view resource reads when the
|
|
65
65
|
// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`
|
|
66
66
|
// (Vercel functions don't ship `dist/`).
|
|
67
|
-
export async function emitVercelBuildOutput(root) {
|
|
67
|
+
export async function emitVercelBuildOutput(root, serverExternal = []) {
|
|
68
68
|
const outputDir = path.join(root, ".vercel", "output");
|
|
69
69
|
const funcDir = path.join(outputDir, "functions", `${VERCEL_FUNCTION_NAME}.func`);
|
|
70
70
|
const staticAssetsDir = path.join(outputDir, "static", "assets");
|
|
@@ -82,7 +82,12 @@ export async function emitVercelBuildOutput(root) {
|
|
|
82
82
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
83
83
|
// Dev-only deps reachable from re-exports; safe to leave unresolved since
|
|
84
84
|
// the code paths that touch them are eliminated by the NODE_ENV define.
|
|
85
|
-
|
|
85
|
+
// `serverExternal` comes from the vite plugin, for deps esbuild can't
|
|
86
|
+
// resolve or load (e.g. optional native modules pulled in transitively).
|
|
87
|
+
external: ["vite", "@skybridge/devtools", ...serverExternal],
|
|
88
|
+
// Native addons can't be inlined into the bundle; copy them next to the
|
|
89
|
+
// function and rewrite the require path to point at the copy.
|
|
90
|
+
loader: { ".node": "file" },
|
|
86
91
|
banner: {
|
|
87
92
|
// ESM bundles miss CJS interop globals that some deps reach for.
|
|
88
93
|
js: "import{createRequire}from'node:module';const require=createRequire(import.meta.url);",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-helpers.js","sourceRoot":"","sources":["../../src/cli/build-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,4EAA4E;AAC5E,gFAAgF;AAChF,wDAAwD;AACxD,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,mDAAmD;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;CASpC,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,qBAAqB,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,OAAe;IACjE,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IACzC,aAAa,CAAC,OAAO,EAAE,kBAAkB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,YAAoB,EACpB,OAAe;IAEf,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACrD,aAAa,CAAC,OAAO,EAAE,kBAAkB,QAAQ,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,aAAa,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAE1C,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,OAAO,EAAE,CAAC;IACV,MAAM,EAAE;QACN;YACE,GAAG,EAAE,cAAc;YACnB,OAAO,EAAE,EAAE,6BAA6B,EAAE,GAAG,EAAE;YAC/C,QAAQ,EAAE,IAAI;SACf;QACD,EAAE,MAAM,EAAE,YAAY,EAAE;QACxB,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,oBAAoB,EAAE,EAAE;KACnD;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAY;IACvC,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,UAAU;IACnB,YAAY,EAAE,QAAQ;IACtB,gBAAgB,EAAE,IAAI;CACvB,CAAC;AAEF,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,qBAAqB,
|
|
1
|
+
{"version":3,"file":"build-helpers.js","sourceRoot":"","sources":["../../src/cli/build-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\nimport { discoverSkills } from \"../server/skills.js\";\n\n// Primes the manifest and skills snapshot in skybridge's module scope, then\n// dynamically imports `./server.js` so user code runs *after* the side channels\n// are set. The dynamic import is load-bearing: a static\n// `export { default } from ...` is hoisted with the rest of the static graph\n// and would evaluate `server.js` before the primers run. Both `skills.js` and\n// the manifest are imported (not read from disk) so they ride the bundle on\n// filesystem-less targets like Cloudflare Workers.\nexport const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest, __setSkillsManifest } from \"skybridge/server\";\nimport manifest from \"./vite-manifest.js\";\nimport skills from \"./skills.js\";\n\n__setBuildManifest(manifest);\n__setSkillsManifest(skills);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n`;\n\nexport function emitEntryWrapper(distDir: string): void {\n writeFileSync(path.join(distDir, \"__entry.js\"), ENTRY_WRAPPER_CONTENT);\n}\n\nexport function emitSkillsModule(skillsDir: string, outPath: string): void {\n const skills = discoverSkills(skillsDir);\n writeFileSync(outPath, `export default ${JSON.stringify(skills)};\\n`);\n}\n\nexport function emitManifestModule(\n manifestPath: string,\n outPath: string,\n): void {\n const manifest = readFileSync(manifestPath, \"utf-8\");\n writeFileSync(outPath, `export default ${manifest};\\n`);\n}\n\n/** Emit an empty Vite manifest for view-less (headless) servers. */\nexport function emitEmptyManifestModule(outPath: string): void {\n writeFileSync(outPath, \"export default {};\\n\");\n}\n\nexport function ensureAssetsDir(assetsDir: string): void {\n mkdirSync(assetsDir, { recursive: true });\n}\n\nexport const VERCEL_FUNCTION_NAME = \"mcp\";\n\nexport const VERCEL_CONFIG: unknown = {\n version: 3,\n routes: [\n {\n src: \"/assets/(.*)\",\n headers: { \"Access-Control-Allow-Origin\": \"*\" },\n continue: true,\n },\n { handle: \"filesystem\" },\n { src: \"/(.*)\", dest: `/${VERCEL_FUNCTION_NAME}` },\n ],\n};\n\nexport const VERCEL_VC_CONFIG: unknown = {\n runtime: \"nodejs22.x\",\n handler: \"index.js\",\n launcherType: \"Nodejs\",\n shouldAddHelpers: true,\n};\n\n// Emit a Build Output API tree under `.vercel/output/`. Bundling the server\n// with esbuild produces a self-contained function bundle, so we don't ship\n// `node_modules` and don't touch tracked paths like `api/` or `public/`.\n//\n// Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via\n// `__setBuildManifest` before importing user code. Bundling `dist/server.js`\n// directly would skip that priming and 500 on view resource reads when the\n// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`\n// (Vercel functions don't ship `dist/`).\nexport async function emitVercelBuildOutput(\n root: string,\n serverExternal: string[] = [],\n): Promise<void> {\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(\n outputDir,\n \"functions\",\n `${VERCEL_FUNCTION_NAME}.func`,\n );\n const staticAssetsDir = path.join(outputDir, \"static\", \"assets\");\n\n rmSync(outputDir, { recursive: true, force: true });\n mkdirSync(funcDir, { recursive: true });\n\n const { build } = await import(\"esbuild\");\n await build({\n entryPoints: [path.join(root, \"dist\", \"__entry.js\")],\n bundle: true,\n platform: \"node\",\n target: \"node22\",\n format: \"esm\",\n outfile: path.join(funcDir, \"index.js\"),\n // Lets esbuild DCE dev-only branches that pull in vite/devtools.\n define: { \"process.env.NODE_ENV\": '\"production\"' },\n // Dev-only deps reachable from re-exports; safe to leave unresolved since\n // the code paths that touch them are eliminated by the NODE_ENV define.\n // `serverExternal` comes from the vite plugin, for deps esbuild can't\n // resolve or load (e.g. optional native modules pulled in transitively).\n external: [\"vite\", \"@skybridge/devtools\", ...serverExternal],\n // Native addons can't be inlined into the bundle; copy them next to the\n // function and rewrite the require path to point at the copy.\n loader: { \".node\": \"file\" },\n banner: {\n // ESM bundles miss CJS interop globals that some deps reach for.\n js: \"import{createRequire}from'node:module';const require=createRequire(import.meta.url);\",\n },\n });\n\n writeFileSync(\n path.join(funcDir, \".vc-config.json\"),\n `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\\n`,\n );\n writeFileSync(\n path.join(funcDir, \"package.json\"),\n `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n );\n\n const assetsSrc = path.join(root, \"dist\", \"assets\");\n if (existsSync(assetsSrc)) {\n cpSync(assetsSrc, staticAssetsDir, { recursive: true });\n } else {\n mkdirSync(staticAssetsDir, { recursive: true });\n }\n\n writeFileSync(\n path.join(outputDir, \"config.json\"),\n `${JSON.stringify(VERCEL_CONFIG, null, 2)}\\n`,\n );\n}\n"]}
|
|
@@ -106,6 +106,17 @@ describe("emitVercelBuildOutput", () => {
|
|
|
106
106
|
expect(JSON.parse(readFileSync(path.join(outputDir, "config.json"), "utf-8"))).toEqual(VERCEL_CONFIG);
|
|
107
107
|
expect(readFileSync(path.join(outputDir, "static", "assets", "view-abc.js"), "utf-8")).toContain("bundled view");
|
|
108
108
|
});
|
|
109
|
+
it("leaves serverExternal packages unbundled", async () => {
|
|
110
|
+
const root = mkTmp();
|
|
111
|
+
mkdirSync(path.join(root, "dist"), { recursive: true });
|
|
112
|
+
// Unresolvable from the tmp root, so esbuild fails the build unless the
|
|
113
|
+
// package is marked external (bunyan → optional `dtrace-provider`).
|
|
114
|
+
writeFileSync(path.join(root, "dist", "__entry.js"), 'import "dtrace-provider";\nexport default null;\n');
|
|
115
|
+
await expect(emitVercelBuildOutput(root)).rejects.toThrow(/Could not resolve "dtrace-provider"/);
|
|
116
|
+
await emitVercelBuildOutput(root, ["dtrace-provider"]);
|
|
117
|
+
const bundle = readFileSync(path.join(root, ".vercel", "output", "functions", "mcp.func", "index.js"), "utf-8");
|
|
118
|
+
expect(bundle).toContain('import "dtrace-provider"');
|
|
119
|
+
});
|
|
109
120
|
it("emits static assets directory when dist/assets is missing", async () => {
|
|
110
121
|
const root = mkTmp();
|
|
111
122
|
mkdirSync(path.join(root, "dist"), { recursive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-helpers.test.js","sourceRoot":"","sources":["../../src/cli/build-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\n// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport {\n ENTRY_WRAPPER_CONTENT,\n emitEmptyManifestModule,\n emitEntryWrapper,\n emitManifestModule,\n emitSkillsModule,\n emitVercelBuildOutput,\n ensureAssetsDir,\n VERCEL_CONFIG,\n VERCEL_VC_CONFIG,\n} from \"./build-helpers.js\";\n\nfunction mkTmp(prefix = \"skybridge-build-helpers-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"emitEntryWrapper\", () => {\n it(\"writes dist/__entry.js that primes the manifest before importing user code\", () => {\n const dir = mkTmp();\n emitEntryWrapper(dir);\n const out = readFileSync(path.join(dir, \"__entry.js\"), \"utf-8\");\n expect(out).toBe(ENTRY_WRAPPER_CONTENT);\n expect(out).toContain(\n 'import { __setBuildManifest, __setSkillsManifest } from \"skybridge/server\"',\n );\n expect(out).toContain('import manifest from \"./vite-manifest.js\"');\n expect(out).toContain('import skills from \"./skills.js\"');\n expect(out).toContain(\"__setBuildManifest(manifest)\");\n expect(out).toContain(\"__setSkillsManifest(skills)\");\n // Dynamic import is load-bearing: `server.js` must evaluate after the\n // setters run, so a static re-export wouldn't work.\n expect(out).toContain('await import(\"./server.js\")');\n expect(out).toContain(\"export default userMod.default\");\n });\n});\n\ndescribe(\"emitSkillsModule\", () => {\n it(\"inlines discovered skills as an ESM default export\", () => {\n const dir = mkTmp();\n const skillsDir = path.join(dir, \"src\", \"skills\");\n mkdirSync(path.join(skillsDir, \"refunds\"), { recursive: true });\n writeFileSync(\n path.join(skillsDir, \"refunds\", \"SKILL.md\"),\n \"---\\nname: refunds\\ndescription: Process refunds\\n---\\nBody\",\n );\n const outPath = path.join(dir, \"skills.js\");\n emitSkillsModule(skillsDir, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n const skills = JSON.parse(literal);\n expect(skills).toHaveLength(1);\n expect(skills[0]).toMatchObject({\n name: \"refunds\",\n frontmatter: { name: \"refunds\", description: \"Process refunds\" },\n });\n expect(skills[0].digest).toMatch(/^sha256:[a-f0-9]{64}$/);\n });\n\n it(\"emits an empty array when the skills directory is absent\", () => {\n const dir = mkTmp();\n const outPath = path.join(dir, \"skills.js\");\n emitSkillsModule(path.join(dir, \"nope\"), outPath);\n expect(readFileSync(outPath, \"utf-8\")).toBe(\"export default [];\\n\");\n });\n});\n\ndescribe(\"emitManifestModule\", () => {\n it(\"inlines the JSON manifest as an ESM default export\", () => {\n const dir = mkTmp();\n const inPath = path.join(dir, \"manifest.json\");\n const outPath = path.join(dir, \"vite-manifest.js\");\n const manifest = { \"src/views/foo.tsx\": { file: \"assets/foo-abc.js\" } };\n writeFileSync(inPath, JSON.stringify(manifest));\n emitManifestModule(inPath, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n expect(out.startsWith(\"export default \")).toBe(true);\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n expect(JSON.parse(literal)).toEqual(manifest);\n });\n});\n\ndescribe(\"emitEmptyManifestModule\", () => {\n it(\"writes an empty object default export\", () => {\n const dir = mkTmp();\n const outPath = path.join(dir, \"vite-manifest.js\");\n emitEmptyManifestModule(outPath);\n expect(readFileSync(outPath, \"utf-8\")).toBe(\"export default {};\\n\");\n });\n});\n\ndescribe(\"ensureAssetsDir\", () => {\n it(\"creates the assets directory when missing\", () => {\n const dir = mkTmp();\n const assetsDir = path.join(dir, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n expect(existsSync(assetsDir)).toBe(true);\n });\n});\n\ndescribe(\"emitVercelBuildOutput\", () => {\n it(\"emits a Build Output API tree with bundled function and static assets\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\", \"assets\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n // Minimal `dist/__entry.js` (the real wrapper imports `skybridge/server`,\n // which isn't resolvable in this test's tmp dir — the function-bundling\n // contract we care about here is just \"bundle whatever `__entry.js`\n // imports into a single function file\").\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"view-abc.js\"),\n \"/* bundled view */\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(outputDir, \"functions\", \"mcp.func\");\n\n expect(existsSync(path.join(funcDir, \"index.js\"))).toBe(true);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \".vc-config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_VC_CONFIG);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \"package.json\"), \"utf-8\")),\n ).toEqual({ type: \"module\" });\n expect(\n JSON.parse(readFileSync(path.join(outputDir, \"config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_CONFIG);\n expect(\n readFileSync(\n path.join(outputDir, \"static\", \"assets\", \"view-abc.js\"),\n \"utf-8\",\n ),\n ).toContain(\"bundled view\");\n });\n\n it(\"emits static assets directory when dist/assets is missing\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n expect(\n existsSync(path.join(root, \".vercel\", \"output\", \"static\", \"assets\")),\n ).toBe(true);\n expect(\n existsSync(\n path.join(\n root,\n \".vercel\",\n \"output\",\n \"functions\",\n \"mcp.func\",\n \"index.js\",\n ),\n ),\n ).toBe(true);\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"build-helpers.test.js","sourceRoot":"","sources":["../../src/cli/build-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\n// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport {\n ENTRY_WRAPPER_CONTENT,\n emitEmptyManifestModule,\n emitEntryWrapper,\n emitManifestModule,\n emitSkillsModule,\n emitVercelBuildOutput,\n ensureAssetsDir,\n VERCEL_CONFIG,\n VERCEL_VC_CONFIG,\n} from \"./build-helpers.js\";\n\nfunction mkTmp(prefix = \"skybridge-build-helpers-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"emitEntryWrapper\", () => {\n it(\"writes dist/__entry.js that primes the manifest before importing user code\", () => {\n const dir = mkTmp();\n emitEntryWrapper(dir);\n const out = readFileSync(path.join(dir, \"__entry.js\"), \"utf-8\");\n expect(out).toBe(ENTRY_WRAPPER_CONTENT);\n expect(out).toContain(\n 'import { __setBuildManifest, __setSkillsManifest } from \"skybridge/server\"',\n );\n expect(out).toContain('import manifest from \"./vite-manifest.js\"');\n expect(out).toContain('import skills from \"./skills.js\"');\n expect(out).toContain(\"__setBuildManifest(manifest)\");\n expect(out).toContain(\"__setSkillsManifest(skills)\");\n // Dynamic import is load-bearing: `server.js` must evaluate after the\n // setters run, so a static re-export wouldn't work.\n expect(out).toContain('await import(\"./server.js\")');\n expect(out).toContain(\"export default userMod.default\");\n });\n});\n\ndescribe(\"emitSkillsModule\", () => {\n it(\"inlines discovered skills as an ESM default export\", () => {\n const dir = mkTmp();\n const skillsDir = path.join(dir, \"src\", \"skills\");\n mkdirSync(path.join(skillsDir, \"refunds\"), { recursive: true });\n writeFileSync(\n path.join(skillsDir, \"refunds\", \"SKILL.md\"),\n \"---\\nname: refunds\\ndescription: Process refunds\\n---\\nBody\",\n );\n const outPath = path.join(dir, \"skills.js\");\n emitSkillsModule(skillsDir, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n const skills = JSON.parse(literal);\n expect(skills).toHaveLength(1);\n expect(skills[0]).toMatchObject({\n name: \"refunds\",\n frontmatter: { name: \"refunds\", description: \"Process refunds\" },\n });\n expect(skills[0].digest).toMatch(/^sha256:[a-f0-9]{64}$/);\n });\n\n it(\"emits an empty array when the skills directory is absent\", () => {\n const dir = mkTmp();\n const outPath = path.join(dir, \"skills.js\");\n emitSkillsModule(path.join(dir, \"nope\"), outPath);\n expect(readFileSync(outPath, \"utf-8\")).toBe(\"export default [];\\n\");\n });\n});\n\ndescribe(\"emitManifestModule\", () => {\n it(\"inlines the JSON manifest as an ESM default export\", () => {\n const dir = mkTmp();\n const inPath = path.join(dir, \"manifest.json\");\n const outPath = path.join(dir, \"vite-manifest.js\");\n const manifest = { \"src/views/foo.tsx\": { file: \"assets/foo-abc.js\" } };\n writeFileSync(inPath, JSON.stringify(manifest));\n emitManifestModule(inPath, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n expect(out.startsWith(\"export default \")).toBe(true);\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n expect(JSON.parse(literal)).toEqual(manifest);\n });\n});\n\ndescribe(\"emitEmptyManifestModule\", () => {\n it(\"writes an empty object default export\", () => {\n const dir = mkTmp();\n const outPath = path.join(dir, \"vite-manifest.js\");\n emitEmptyManifestModule(outPath);\n expect(readFileSync(outPath, \"utf-8\")).toBe(\"export default {};\\n\");\n });\n});\n\ndescribe(\"ensureAssetsDir\", () => {\n it(\"creates the assets directory when missing\", () => {\n const dir = mkTmp();\n const assetsDir = path.join(dir, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n expect(existsSync(assetsDir)).toBe(true);\n });\n});\n\ndescribe(\"emitVercelBuildOutput\", () => {\n it(\"emits a Build Output API tree with bundled function and static assets\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\", \"assets\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n // Minimal `dist/__entry.js` (the real wrapper imports `skybridge/server`,\n // which isn't resolvable in this test's tmp dir — the function-bundling\n // contract we care about here is just \"bundle whatever `__entry.js`\n // imports into a single function file\").\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"view-abc.js\"),\n \"/* bundled view */\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(outputDir, \"functions\", \"mcp.func\");\n\n expect(existsSync(path.join(funcDir, \"index.js\"))).toBe(true);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \".vc-config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_VC_CONFIG);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \"package.json\"), \"utf-8\")),\n ).toEqual({ type: \"module\" });\n expect(\n JSON.parse(readFileSync(path.join(outputDir, \"config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_CONFIG);\n expect(\n readFileSync(\n path.join(outputDir, \"static\", \"assets\", \"view-abc.js\"),\n \"utf-8\",\n ),\n ).toContain(\"bundled view\");\n });\n\n it(\"leaves serverExternal packages unbundled\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n // Unresolvable from the tmp root, so esbuild fails the build unless the\n // package is marked external (bunyan → optional `dtrace-provider`).\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n 'import \"dtrace-provider\";\\nexport default null;\\n',\n );\n\n await expect(emitVercelBuildOutput(root)).rejects.toThrow(\n /Could not resolve \"dtrace-provider\"/,\n );\n await emitVercelBuildOutput(root, [\"dtrace-provider\"]);\n\n const bundle = readFileSync(\n path.join(root, \".vercel\", \"output\", \"functions\", \"mcp.func\", \"index.js\"),\n \"utf-8\",\n );\n expect(bundle).toContain('import \"dtrace-provider\"');\n });\n\n it(\"emits static assets directory when dist/assets is missing\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n expect(\n existsSync(path.join(root, \".vercel\", \"output\", \"static\", \"assets\")),\n ).toBe(true);\n expect(\n existsSync(\n path.join(\n root,\n \".vercel\",\n \"output\",\n \"functions\",\n \"mcp.func\",\n \"index.js\",\n ),\n ),\n ).toBe(true);\n });\n});\n"]}
|
package/dist/cli/build-steps.js
CHANGED
|
@@ -2,9 +2,9 @@ import { rmSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import path, { isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { scanAndWriteViewsDts, scanViewsSync, } from "../web/plugin/scan-views.js";
|
|
4
4
|
import { emitEmptyManifestModule, emitEntryWrapper, emitManifestModule, emitSkillsModule, emitVercelBuildOutput, ensureAssetsDir, } from "./build-helpers.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveSkybridgeConfig } from "./resolve-skybridge-config.js";
|
|
6
6
|
export async function getCommandSteps(root = process.cwd()) {
|
|
7
|
-
const viewsDir = await
|
|
7
|
+
const { viewsDir, serverExternal } = await resolveSkybridgeConfig(root);
|
|
8
8
|
const rawDir = viewsDir ?? "src/views";
|
|
9
9
|
const resolvedDir = isAbsolute(rawDir) ? rawDir : resolve(root, rawDir);
|
|
10
10
|
// Non-throwing pre-check: duplicate view names are validated in the
|
|
@@ -66,7 +66,7 @@ export async function getCommandSteps(root = process.cwd()) {
|
|
|
66
66
|
},
|
|
67
67
|
}, {
|
|
68
68
|
label: "Emitting Vercel build output",
|
|
69
|
-
run: () => emitVercelBuildOutput(root),
|
|
69
|
+
run: () => emitVercelBuildOutput(root, serverExternal),
|
|
70
70
|
});
|
|
71
71
|
return steps;
|
|
72
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-steps.js","sourceRoot":"","sources":["../../src/cli/build-steps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"build-steps.js","sourceRoot":"","sources":["../../src/cli/build-steps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,aAAa,GACd,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAGvE,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;IAEpB,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,QAAQ,IAAI,WAAW,CAAC;IACvC,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxE,oEAAoE;IACpE,sEAAsE;IACtE,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAE7D,MAAM,KAAK,GAAkB;QAC3B;YACE,KAAK,EAAE,gBAAgB;YACvB,GAAG,EAAE,KAAK,IAAI,EAAE;gBACd,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;SACF;QACD;YACE,KAAK,EAAE,kBAAkB;YACzB,GAAG,EAAE,GAAG,EAAE,CACR,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACnE,OAAO,EAAE,gBAAgB;SAC1B;KACF,CAAC;IAEF,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,gBAAgB;YACvB,OAAO,EAAE,YAAY;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CACR;QACE,KAAK,EAAE,0BAA0B;QACjC,GAAG,EAAE,GAAG,EAAE;YACR,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAChE,IAAI,QAAQ,EAAE,CAAC;gBACb,kBAAkB,CAChB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,CAAC,EAC3D,WAAW,CACZ,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,uBAAuB,CAAC,WAAW,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;KACF,EACD;QACE,KAAK,EAAE,wBAAwB;QAC/B,GAAG,EAAE,GAAG,EAAE;YACR,gBAAgB,CACd,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,EAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,CACrC,CAAC;QACJ,CAAC;KACF,EACD;QACE,KAAK,EAAE,wBAAwB;QAC/B,GAAG,EAAE,GAAG,EAAE;YACR,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5C,CAAC;KACF,EACD;QACE,KAAK,EAAE,+BAA+B;QACtC,GAAG,EAAE,GAAG,EAAE;YACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpD,eAAe,CAAC,SAAS,CAAC,CAAC;YAC3B,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAClC,uCAAuC,CACxC,CAAC;QACJ,CAAC;KACF,EACD;QACE,KAAK,EAAE,6BAA6B;QACpC,GAAG,EAAE,GAAG,EAAE;YACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpD,eAAe,CAAC,SAAS,CAAC,CAAC;YAC3B,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,+CAA+C,CAChD,CAAC;QACJ,CAAC;KACF,EACD;QACE,KAAK,EAAE,8BAA8B;QACrC,GAAG,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,cAAc,CAAC;KACvD,CACF,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { rmSync, writeFileSync } from \"node:fs\";\nimport path, { isAbsolute, resolve } from \"node:path\";\nimport {\n scanAndWriteViewsDts,\n scanViewsSync,\n} from \"../web/plugin/scan-views.js\";\nimport {\n emitEmptyManifestModule,\n emitEntryWrapper,\n emitManifestModule,\n emitSkillsModule,\n emitVercelBuildOutput,\n ensureAssetsDir,\n} from \"./build-helpers.js\";\nimport { resolveSkybridgeConfig } from \"./resolve-skybridge-config.js\";\nimport type { CommandStep } from \"./use-execute-steps.js\";\n\nexport async function getCommandSteps(\n root = process.cwd(),\n): Promise<CommandStep[]> {\n const { viewsDir, serverExternal } = await resolveSkybridgeConfig(root);\n const rawDir = viewsDir ?? \"src/views\";\n const resolvedDir = isAbsolute(rawDir) ? rawDir : resolve(root, rawDir);\n // Non-throwing pre-check: duplicate view names are validated in the\n // \"Scanning views\" step so useExecuteSteps can render a styled error.\n const hasViews = scanViewsSync(resolvedDir).valid.length > 0;\n\n const steps: CommandStep[] = [\n {\n label: \"Scanning views\",\n run: async () => {\n scanAndWriteViewsDts(root, viewsDir);\n },\n },\n {\n label: \"Compiling server\",\n run: () =>\n rmSync(path.join(root, \"dist\"), { recursive: true, force: true }),\n command: \"tsc -b --force\",\n },\n ];\n\n if (hasViews) {\n steps.push({\n label: \"Building views\",\n command: \"vite build\",\n });\n }\n\n steps.push(\n {\n label: \"Emitting manifest module\",\n run: () => {\n const manifestOut = path.join(root, \"dist\", \"vite-manifest.js\");\n if (hasViews) {\n emitManifestModule(\n path.join(root, \"dist\", \"assets\", \".vite\", \"manifest.json\"),\n manifestOut,\n );\n } else {\n emitEmptyManifestModule(manifestOut);\n }\n },\n },\n {\n label: \"Emitting skills module\",\n run: () => {\n emitSkillsModule(\n resolve(root, \"src/skills\"),\n path.join(root, \"dist\", \"skills.js\"),\n );\n },\n },\n {\n label: \"Emitting entry wrapper\",\n run: () => {\n emitEntryWrapper(path.join(root, \"dist\"));\n },\n },\n {\n label: \"Emitting Cloudflare redirects\",\n run: () => {\n const assetsDir = path.join(root, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n writeFileSync(\n path.join(assetsDir, \"_redirects\"),\n \"/assets/assets/* /assets/:splat 200\\n\",\n );\n },\n },\n {\n label: \"Emitting Cloudflare headers\",\n run: () => {\n const assetsDir = path.join(root, \"dist\", \"assets\");\n ensureAssetsDir(assetsDir);\n writeFileSync(\n path.join(assetsDir, \"_headers\"),\n \"/assets/*\\n Access-Control-Allow-Origin: *\\n\",\n );\n },\n },\n {\n label: \"Emitting Vercel build output\",\n run: () => emitVercelBuildOutput(root, serverExternal),\n },\n );\n\n return steps;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export async function
|
|
1
|
+
export async function resolveSkybridgeConfig(root) {
|
|
2
2
|
const { loadConfigFromFile } = await import("vite");
|
|
3
3
|
const loaded = await loadConfigFromFile({ command: "build", mode: "production" }, undefined, root);
|
|
4
4
|
const isPluginCandidate = (value) => typeof value === "object" && value !== null;
|
|
@@ -12,6 +12,7 @@ export async function resolveViewsDir(root) {
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
walk(loaded?.config.plugins ?? []);
|
|
15
|
-
|
|
15
|
+
const api = plugins.find((p) => p.name === "skybridge")?.api;
|
|
16
|
+
return { viewsDir: api?.viewsDir, serverExternal: api?.serverExternal };
|
|
16
17
|
}
|
|
17
|
-
//# sourceMappingURL=resolve-
|
|
18
|
+
//# sourceMappingURL=resolve-skybridge-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-skybridge-config.js","sourceRoot":"","sources":["../../src/cli/resolve-skybridge-config.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY;IAEZ,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,EACxC,SAAS,EACT,IAAI,CACL,CAAC;IAEF,MAAM,iBAAiB,GAAG,CACxB,KAAc,EACqC,EAAE,CACrD,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;IAE9C,MAAM,OAAO,GAAoD,EAAE,CAAC;IACpE,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,GAAG,CAAC;IAC7D,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;AAC1E,CAAC","sourcesContent":["export interface SkybridgeConfig {\n viewsDir?: string;\n serverExternal?: string[];\n}\n\nexport async function resolveSkybridgeConfig(\n root: string,\n): Promise<SkybridgeConfig> {\n const { loadConfigFromFile } = await import(\"vite\");\n const loaded = await loadConfigFromFile(\n { command: \"build\", mode: \"production\" },\n undefined,\n root,\n );\n\n const isPluginCandidate = (\n value: unknown,\n ): value is { name?: string; api?: SkybridgeConfig } =>\n typeof value === \"object\" && value !== null;\n\n const plugins: Array<{ name?: string; api?: SkybridgeConfig }> = [];\n const walk = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(walk);\n } else if (isPluginCandidate(value)) {\n plugins.push(value);\n }\n };\n walk(loaded?.config.plugins ?? []);\n const api = plugins.find((p) => p.name === \"skybridge\")?.api;\n return { viewsDir: api?.viewsDir, serverExternal: api?.serverExternal };\n}\n"]}
|
package/dist/commands/dev.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Command, Flags } from "@oclif/core";
|
|
|
3
3
|
import { Box, render, Text } from "ink";
|
|
4
4
|
import { resolvePort } from "../cli/detect-port.js";
|
|
5
5
|
import { Header } from "../cli/header.js";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveSkybridgeConfig } from "../cli/resolve-skybridge-config.js";
|
|
7
7
|
import { runPlain } from "../cli/run-plain.js";
|
|
8
8
|
import { startTunnelControlServer } from "../cli/tunnel-control-server.js";
|
|
9
9
|
import { useMessages } from "../cli/use-messages.js";
|
|
@@ -49,7 +49,7 @@ export default class Dev extends Command {
|
|
|
49
49
|
// and the dev UI reports phantom TS errors forever.
|
|
50
50
|
const root = process.cwd();
|
|
51
51
|
try {
|
|
52
|
-
scanAndWriteViewsDts(root, await
|
|
52
|
+
scanAndWriteViewsDts(root, (await resolveSkybridgeConfig(root)).viewsDir);
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
55
|
// Best-effort: if the scan fails (e.g. broken vite config, duplicate
|
package/dist/commands/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveViewsDir } from \"../cli/resolve-views-dir.js\";\nimport { runPlain } from \"../cli/run-plain.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n plain: Flags.boolean({\n description:\n \"Disable the interactive UI and stream raw server logs to stdout, so you can pipe them through a formatter (e.g. `skybridge dev --plain | bunyan`).\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, await resolveViewsDir(root));\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n if (flags.plain) {\n const teardown = runPlain({\n env,\n port,\n fallback,\n version: this.config.version,\n tunnel: flags.tunnel,\n tunnelManager,\n });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g.\n // nodemon's) exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n teardown();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n return;\n }\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACtC,MAAM,CAAU,WAAW,GAAG,0BAA0B,CAAC;IACzD,MAAM,CAAU,QAAQ,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,2BAA2B;YACxC,GAAG,EAAE,CAAC;SACP,CAAC;QACF,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;YACpB,WAAW,EAAE,yCAAyC;YACtD,OAAO,EAAE,KAAK;SACf,CAAC;QACF,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,WAAW,EAAE,uDAAuD;YACpE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;YAC/C,OAAO,EAAE,IAAI;SACd,CAAC;QACF,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,kBAAkB;YAC/B,OAAO,EAAE,KAAK;SACf,CAAC;QACF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;YACnB,WAAW,EACT,oJAAoJ;YACtJ,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAExC,sEAAsE;QACtE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,oDAAoD;QACpD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,oBAAoB,CAAC,IAAI,EAAE,CAAC,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,qEAAqE;YACrE,6DAA6D;QAC/D,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxB,CAAC;QAED,MAAM,EACJ,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,kBAAkB,GAC1B,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAE/C,MAAM,GAAG,GAAG;YACV,GAAG,OAAO,CAAC,GAAG;YACd,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;YACpB,qBAAqB,EAAE,MAAM,CAAC,WAAW,CAAC;SAC3C,CAAC;QAEF,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,QAAQ,CAAC;gBACxB,GAAG;gBACH,IAAI;gBACJ,QAAQ;gBACR,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;gBAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,aAAa;aACd,CAAC,CAAC;YAEH,uEAAuE;YACvE,gEAAgE;YAChE,mEAAmE;YACnE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,EAAE;gBACtC,aAAa,CAAC,IAAI,EAAE,CAAC;gBACrB,QAAQ,EAAE,CAAC;gBACX,KAAK,kBAAkB,EAAE;qBACtB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;gBAC9D,CAAC,CAAC;qBACD,OAAO,CAAC,GAAG,EAAE;oBACZ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrB,CAAC,CAAC,CAAC;YACP,CAAC,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,EAAE;YACf,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;YACtC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,WAAW,EAAE,CAAC;YAC9C,UAAU,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAC7B,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,WAAW,GAAG,SAAS,CAC3B,IAAI,EACJ,WAAW,EACX,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,MAAM,CACb,CAAC;YAEF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,aACnD,KAAC,MAAM,IAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,GAAI,EAExC,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACpB,QAAQ,CAAC,CAAC,CAAC,CACV,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,yCAAgC,CACrD,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,8BAAmB,CACzB,EACD,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,oBAAoB,IAAI,MAAM,GAAQ,IACvD,EACN,MAAC,GAAG,IAAC,YAAY,EAAE,CAAC,aAClB,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,uBAAG,IAAI,IAAQ,EACpC,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,kDACM,GAAG,IAC1B,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,oBAAoB,IAAI,GAAG,GAAQ,IACpD,EAEL,WAAW,CAAC,MAAM,KAAK,MAAM,IAAI,CAChC,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACrB,KAAC,IAAI,mEAAwD,EAC7D,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,+BAEhB,EACP,KAAC,IAAI,oBAAS,IACV,CACP,EACA,WAAW,CAAC,MAAM,KAAK,UAAU,IAAI,CACpC,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACrB,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,YAAE,WAAW,CAAC,OAAO,GAAQ,IAC7C,CACP,EACA,WAAW,CAAC,MAAM,KAAK,WAAW,IAAI,CACrC,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACrB,KAAC,IAAI,8BAAmB,EACxB,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,GAAG,WAAW,CAAC,GAAG,MAAM,GAAQ,IACjD,EACN,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,uBAAG,IAAI,IAAQ,EACpC,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,sDACU,GAAG,IAC9B,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,GAAG,WAAW,CAAC,GAAG,MAAM,GAAQ,IACjD,IACF,CACP,EACA,WAAW,CAAC,MAAM,KAAK,OAAO,IAAI,CACjC,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACrB,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,qCACM,WAAW,CAAC,OAAO,IACnC,IACH,EACN,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,uBAAG,IAAI,IAAQ,EACpC,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,yCAAyC,IAAI,EAAE,GAAQ,IACtE,IACF,CACP,EAED,MAAC,GAAG,eACF,MAAC,IAAI,+BAAI,IAAI,IAAQ,EACrB,KAAC,IAAI,0CAA+B,EACpC,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,SAAS,+CAEtB,IACH,EAEL,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACtB,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,EAAC,IAAI,4DAEf,EACN,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACvB,MAAC,GAAG,IAEF,UAAU,EAAE,CAAC,EACb,aAAa,EAAC,QAAQ,aAEtB,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,KAAK,CAAC,IAAI,GAAQ,EACvC,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,kBACd,KAAK,CAAC,IAAI,OAAG,KAAK,CAAC,GAAG,QAAI,GAAG,IAC1B,IACH,EACN,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YAChB,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,KAAK,CAAC,OAAO,GAAQ,GACpC,KAZD,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,EAAE,CAa3C,CACP,CAAC,IACE,CACP,EACA,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACtB,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,4BAEjB,EACN,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CACzB,KAAC,GAAG,IAAkB,UAAU,EAAE,CAAC,YAChC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAC5B,8BACE,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,uBAAG,IAAI,IAAQ,EAClC,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,OAAO,CAAC,IAAI,GAAQ,IACxC,CACJ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAC7B,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,OAAO,CAAC,IAAI,GAAQ,CACxC,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,cAAE,OAAO,CAAC,IAAI,GAAQ,CAC5B,IAVO,OAAO,CAAC,EAAE,CAWd,CACP,CAAC,IACE,CACP,IACG,CACP,CAAC;QACJ,CAAC,CAAC;QAEF,sEAAsE;QACtE,yEAAyE;QACzE,yEAAyE;QACzE,qEAAqE;QACrE,qBAAqB;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAC,GAAG,KAAG,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAExE,uEAAuE;QACvE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,EAAE;YACtC,aAAa,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,kBAAkB,EAAE;iBACtB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;YAC9D,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACZ,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveSkybridgeConfig } from \"../cli/resolve-skybridge-config.js\";\nimport { runPlain } from \"../cli/run-plain.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n plain: Flags.boolean({\n description:\n \"Disable the interactive UI and stream raw server logs to stdout, so you can pipe them through a formatter (e.g. `skybridge dev --plain | bunyan`).\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, (await resolveSkybridgeConfig(root)).viewsDir);\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n if (flags.plain) {\n const teardown = runPlain({\n env,\n port,\n fallback,\n version: this.config.version,\n tunnel: flags.tunnel,\n tunnelManager,\n });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g.\n // nodemon's) exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n teardown();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n return;\n }\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
|
@@ -3,6 +3,12 @@ import type { Plugin } from "vite";
|
|
|
3
3
|
export interface SkybridgePluginOptions {
|
|
4
4
|
/** Directory scanned for view modules. Defaults to `"src/views"`. */
|
|
5
5
|
viewsDir?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Package names to leave unbundled when `skybridge build` bundles the server
|
|
8
|
+
* for deployment. Use it for dependencies esbuild can't resolve or load —
|
|
9
|
+
* typically optional native modules pulled in by a transitive dependency.
|
|
10
|
+
*/
|
|
11
|
+
serverExternal?: string[];
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
8
14
|
* Vite plugin that wires a Skybridge project's view files into Vite.
|
|
@@ -52,8 +52,9 @@ export function skybridge(options) {
|
|
|
52
52
|
return {
|
|
53
53
|
name: "skybridge",
|
|
54
54
|
enforce: "pre",
|
|
55
|
-
// Read by `skybridge build` to resolve viewsDir before `tsc -b` runs
|
|
56
|
-
|
|
55
|
+
// Read by `skybridge build` to resolve viewsDir before `tsc -b` runs, and
|
|
56
|
+
// to feed esbuild's external list when bundling the server.
|
|
57
|
+
api: { viewsDir: rawViewsDir, serverExternal: options?.serverExternal },
|
|
57
58
|
config(config) {
|
|
58
59
|
projectRoot = config.root || process.cwd();
|
|
59
60
|
resolvedViewsDir = isAbsolute(rawViewsDir)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/web/plugin/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve } from \"node:path\";\nimport type { Plugin, ViteDevServer } from \"vite\";\nimport {\n assertUniqueViewNames,\n type DiscoveredView,\n discoverViewsSync,\n scanViewsSync,\n writeViewsDts,\n} from \"./scan-views.js\";\nimport { transform as dataLlmTransform } from \"./transform-data-llm.js\";\nimport { hasDefaultExport } from \"./validate-view.js\";\n\nconst VIRTUAL_PREFIX = \"/_skybridge/view/\";\nconst VIRTUAL_MODULE_PREFIX = \"\\0skybridge:view:\";\n\n/** Options for the {@link skybridge} Vite plugin. */\nexport interface SkybridgePluginOptions {\n /** Directory scanned for view modules. Defaults to `\"src/views\"`. */\n viewsDir?: string;\n}\n\nfunction buildVirtualEntry(viewFilePath: string): string {\n const normalized = viewFilePath.replace(/\\\\/g, \"/\");\n return [\n `import { mountView } from \"skybridge/web\";`,\n `import Component from \"${normalized}\";`,\n `import { createElement } from \"react\";`,\n `mountView(createElement(Component));`,\n ].join(\"\\n\");\n}\n\nfunction getViewEntryPattern(viewsDir: string): RegExp {\n const escaped = viewsDir.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(\n `${escaped}\\\\/(?:[^/]+\\\\.(?:jsx|tsx)|[^/]+\\\\/index\\\\.(?:tsx|jsx))(?:\\\\?.*)?$`,\n );\n}\n\n/**\n * Vite plugin that wires a Skybridge project's view files into Vite.\n *\n * For each `.tsx` / `.jsx` file in `viewsDir` with a default export, the\n * plugin:\n * - exposes a virtual entry that calls {@link mountView} with the view's\n * default export,\n * - generates `.skybridge/views.d.ts` to augment {@link ViewNameRegistry} so\n * {@link ViewName} narrows to the actual view names,\n * - rewrites `<DataLLM>` JSX so the host can extract its content,\n * - warns in dev if a view file is missing a default export.\n *\n * Add it to your `vite.config.ts` alongside `@vitejs/plugin-react`.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { skybridge } from \"skybridge/vite\";\n *\n * export default defineConfig({\n * plugins: [react(), skybridge({ viewsDir: \"src/views\" })],\n * });\n * ```\n */\nexport function skybridge(options?: SkybridgePluginOptions): Plugin {\n const rawViewsDir = options?.viewsDir ?? \"src/views\";\n let resolvedViewsDir: string;\n let projectRoot: string;\n let viewMap = new Map<string, DiscoveredView>();\n let viewEntryPattern: RegExp;\n\n return {\n name: \"skybridge\",\n enforce: \"pre\",\n // Read by `skybridge build` to resolve viewsDir before `tsc -b` runs.\n api: { viewsDir: rawViewsDir },\n\n config(config) {\n projectRoot = config.root || process.cwd();\n resolvedViewsDir = isAbsolute(rawViewsDir)\n ? rawViewsDir\n : resolve(projectRoot, rawViewsDir);\n viewEntryPattern = getViewEntryPattern(resolvedViewsDir);\n\n const views = discoverViewsSync(resolvedViewsDir);\n viewMap = new Map(views.map((v) => [v.name, v]));\n writeViewsDts(projectRoot, views);\n\n const input: Record<string, string> = {};\n for (const view of views) {\n input[view.name] = `${VIRTUAL_PREFIX}${view.name}`;\n }\n\n return {\n base: \"/assets\",\n // Fixes \"Invalid hook call\" on createStore by forcing a single\n // copy of React. Under pnpm's isolated node_modules, zustand\n // inside `skybridge` resolves React from skybridge's own\n // dependencies while the host app loads its own copy\n resolve: {\n dedupe: [\"react\", \"react-dom\"],\n },\n build: {\n outDir: \"dist/assets\",\n emptyOutDir: true,\n manifest: true,\n minify: true,\n cssCodeSplit: false,\n rollupOptions: {\n input,\n },\n },\n // Pre-bundle view deps at startup so the first tool invocation\n // doesn't hit Vite's on-demand re-optimization path (which sends\n // `full-reload` over HMR — in our iframe flow the parent host\n // can't honour a reload, and the view silently never mounts).\n optimizeDeps: {\n // Scan view files so transitive user deps (zod, tailwind, etc.)\n // get pre-bundled at startup.\n entries: [\n `${resolvedViewsDir}/*.{tsx,jsx}`,\n `${resolvedViewsDir}/*/index.{tsx,jsx}`,\n ],\n include: [\"react\", \"react-dom/client\", \"react/jsx-runtime\"],\n },\n experimental: {\n renderBuiltUrl: (filename) => {\n return {\n runtime: `window.skybridge.serverUrl + \"/assets/${filename}\"`,\n };\n },\n },\n };\n },\n\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n const name = id.slice(VIRTUAL_PREFIX.length);\n if (viewMap.has(name)) {\n return `${VIRTUAL_MODULE_PREFIX}${name}`;\n }\n }\n return null;\n },\n\n load(id) {\n if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {\n const name = id.slice(VIRTUAL_MODULE_PREFIX.length);\n const view = viewMap.get(name);\n if (view) {\n return buildVirtualEntry(view.filePath);\n }\n }\n return null;\n },\n\n configureServer(server: ViteDevServer) {\n if (!resolvedViewsDir) {\n const root = server.config.root || process.cwd();\n resolvedViewsDir = isAbsolute(rawViewsDir)\n ? rawViewsDir\n : resolve(root, rawViewsDir);\n projectRoot = root;\n viewEntryPattern = getViewEntryPattern(resolvedViewsDir);\n }\n\n server.watcher.add(resolvedViewsDir);\n // Track which view files we've already warned about so a rescan\n // triggered by an unrelated edit doesn't re-emit the same warning.\n let knownInvalid = new Set<string>();\n const rescan = () => {\n try {\n // Surface broken view files. Without this, files lacking a\n // default export are silently dropped from the input and the\n // user has no idea why their widget never mounts.\n const { valid, invalid } = scanViewsSync(resolvedViewsDir);\n const nextInvalid = new Set(invalid.map((v) => v.filePath));\n\n for (const filePath of nextInvalid) {\n if (!knownInvalid.has(filePath)) {\n server.config.logger.warn(\n `[skybridge] view file \"${relative(projectRoot, filePath)}\" is missing a default export — it won't be served until fixed.`,\n );\n }\n }\n for (const filePath of knownInvalid) {\n if (!nextInvalid.has(filePath)) {\n server.config.logger.info(\n `[skybridge] view file \"${relative(projectRoot, filePath)}\" resolved.`,\n );\n }\n }\n knownInvalid = nextInvalid;\n\n assertUniqueViewNames(valid);\n viewMap = new Map(valid.map((v) => [v.name, v]));\n writeViewsDts(projectRoot, valid);\n } catch (err) {\n // assertUniqueViewNames throws on duplicate view names. Catch so\n // chokidar's listener chain doesn't surface it as unhandled and\n // crash the dev server — previous viewMap stays active until\n // the user fixes the conflict.\n const message = err instanceof Error ? err.message : String(err);\n server.config.logger.error(\n `[skybridge] view rescan failed: ${message}`,\n );\n }\n };\n\n // Initial scan emits warnings for broken files that exist at startup.\n rescan();\n server.watcher.on(\"add\", rescan);\n server.watcher.on(\"change\", rescan);\n server.watcher.on(\"unlink\", rescan);\n },\n\n async transform(code, id) {\n if (viewEntryPattern?.test(id) && !hasDefaultExport(code, id)) {\n this.warn(\n `View file \"${id.split(\"/\").pop()}\" is missing a default export.`,\n );\n }\n\n return await dataLlmTransform(code, id);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/web/plugin/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve } from \"node:path\";\nimport type { Plugin, ViteDevServer } from \"vite\";\nimport {\n assertUniqueViewNames,\n type DiscoveredView,\n discoverViewsSync,\n scanViewsSync,\n writeViewsDts,\n} from \"./scan-views.js\";\nimport { transform as dataLlmTransform } from \"./transform-data-llm.js\";\nimport { hasDefaultExport } from \"./validate-view.js\";\n\nconst VIRTUAL_PREFIX = \"/_skybridge/view/\";\nconst VIRTUAL_MODULE_PREFIX = \"\\0skybridge:view:\";\n\n/** Options for the {@link skybridge} Vite plugin. */\nexport interface SkybridgePluginOptions {\n /** Directory scanned for view modules. Defaults to `\"src/views\"`. */\n viewsDir?: string;\n /**\n * Package names to leave unbundled when `skybridge build` bundles the server\n * for deployment. Use it for dependencies esbuild can't resolve or load —\n * typically optional native modules pulled in by a transitive dependency.\n */\n serverExternal?: string[];\n}\n\nfunction buildVirtualEntry(viewFilePath: string): string {\n const normalized = viewFilePath.replace(/\\\\/g, \"/\");\n return [\n `import { mountView } from \"skybridge/web\";`,\n `import Component from \"${normalized}\";`,\n `import { createElement } from \"react\";`,\n `mountView(createElement(Component));`,\n ].join(\"\\n\");\n}\n\nfunction getViewEntryPattern(viewsDir: string): RegExp {\n const escaped = viewsDir.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(\n `${escaped}\\\\/(?:[^/]+\\\\.(?:jsx|tsx)|[^/]+\\\\/index\\\\.(?:tsx|jsx))(?:\\\\?.*)?$`,\n );\n}\n\n/**\n * Vite plugin that wires a Skybridge project's view files into Vite.\n *\n * For each `.tsx` / `.jsx` file in `viewsDir` with a default export, the\n * plugin:\n * - exposes a virtual entry that calls {@link mountView} with the view's\n * default export,\n * - generates `.skybridge/views.d.ts` to augment {@link ViewNameRegistry} so\n * {@link ViewName} narrows to the actual view names,\n * - rewrites `<DataLLM>` JSX so the host can extract its content,\n * - warns in dev if a view file is missing a default export.\n *\n * Add it to your `vite.config.ts` alongside `@vitejs/plugin-react`.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { skybridge } from \"skybridge/vite\";\n *\n * export default defineConfig({\n * plugins: [react(), skybridge({ viewsDir: \"src/views\" })],\n * });\n * ```\n */\nexport function skybridge(options?: SkybridgePluginOptions): Plugin {\n const rawViewsDir = options?.viewsDir ?? \"src/views\";\n let resolvedViewsDir: string;\n let projectRoot: string;\n let viewMap = new Map<string, DiscoveredView>();\n let viewEntryPattern: RegExp;\n\n return {\n name: \"skybridge\",\n enforce: \"pre\",\n // Read by `skybridge build` to resolve viewsDir before `tsc -b` runs, and\n // to feed esbuild's external list when bundling the server.\n api: { viewsDir: rawViewsDir, serverExternal: options?.serverExternal },\n\n config(config) {\n projectRoot = config.root || process.cwd();\n resolvedViewsDir = isAbsolute(rawViewsDir)\n ? rawViewsDir\n : resolve(projectRoot, rawViewsDir);\n viewEntryPattern = getViewEntryPattern(resolvedViewsDir);\n\n const views = discoverViewsSync(resolvedViewsDir);\n viewMap = new Map(views.map((v) => [v.name, v]));\n writeViewsDts(projectRoot, views);\n\n const input: Record<string, string> = {};\n for (const view of views) {\n input[view.name] = `${VIRTUAL_PREFIX}${view.name}`;\n }\n\n return {\n base: \"/assets\",\n // Fixes \"Invalid hook call\" on createStore by forcing a single\n // copy of React. Under pnpm's isolated node_modules, zustand\n // inside `skybridge` resolves React from skybridge's own\n // dependencies while the host app loads its own copy\n resolve: {\n dedupe: [\"react\", \"react-dom\"],\n },\n build: {\n outDir: \"dist/assets\",\n emptyOutDir: true,\n manifest: true,\n minify: true,\n cssCodeSplit: false,\n rollupOptions: {\n input,\n },\n },\n // Pre-bundle view deps at startup so the first tool invocation\n // doesn't hit Vite's on-demand re-optimization path (which sends\n // `full-reload` over HMR — in our iframe flow the parent host\n // can't honour a reload, and the view silently never mounts).\n optimizeDeps: {\n // Scan view files so transitive user deps (zod, tailwind, etc.)\n // get pre-bundled at startup.\n entries: [\n `${resolvedViewsDir}/*.{tsx,jsx}`,\n `${resolvedViewsDir}/*/index.{tsx,jsx}`,\n ],\n include: [\"react\", \"react-dom/client\", \"react/jsx-runtime\"],\n },\n experimental: {\n renderBuiltUrl: (filename) => {\n return {\n runtime: `window.skybridge.serverUrl + \"/assets/${filename}\"`,\n };\n },\n },\n };\n },\n\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n const name = id.slice(VIRTUAL_PREFIX.length);\n if (viewMap.has(name)) {\n return `${VIRTUAL_MODULE_PREFIX}${name}`;\n }\n }\n return null;\n },\n\n load(id) {\n if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {\n const name = id.slice(VIRTUAL_MODULE_PREFIX.length);\n const view = viewMap.get(name);\n if (view) {\n return buildVirtualEntry(view.filePath);\n }\n }\n return null;\n },\n\n configureServer(server: ViteDevServer) {\n if (!resolvedViewsDir) {\n const root = server.config.root || process.cwd();\n resolvedViewsDir = isAbsolute(rawViewsDir)\n ? rawViewsDir\n : resolve(root, rawViewsDir);\n projectRoot = root;\n viewEntryPattern = getViewEntryPattern(resolvedViewsDir);\n }\n\n server.watcher.add(resolvedViewsDir);\n // Track which view files we've already warned about so a rescan\n // triggered by an unrelated edit doesn't re-emit the same warning.\n let knownInvalid = new Set<string>();\n const rescan = () => {\n try {\n // Surface broken view files. Without this, files lacking a\n // default export are silently dropped from the input and the\n // user has no idea why their widget never mounts.\n const { valid, invalid } = scanViewsSync(resolvedViewsDir);\n const nextInvalid = new Set(invalid.map((v) => v.filePath));\n\n for (const filePath of nextInvalid) {\n if (!knownInvalid.has(filePath)) {\n server.config.logger.warn(\n `[skybridge] view file \"${relative(projectRoot, filePath)}\" is missing a default export — it won't be served until fixed.`,\n );\n }\n }\n for (const filePath of knownInvalid) {\n if (!nextInvalid.has(filePath)) {\n server.config.logger.info(\n `[skybridge] view file \"${relative(projectRoot, filePath)}\" resolved.`,\n );\n }\n }\n knownInvalid = nextInvalid;\n\n assertUniqueViewNames(valid);\n viewMap = new Map(valid.map((v) => [v.name, v]));\n writeViewsDts(projectRoot, valid);\n } catch (err) {\n // assertUniqueViewNames throws on duplicate view names. Catch so\n // chokidar's listener chain doesn't surface it as unhandled and\n // crash the dev server — previous viewMap stays active until\n // the user fixes the conflict.\n const message = err instanceof Error ? err.message : String(err);\n server.config.logger.error(\n `[skybridge] view rescan failed: ${message}`,\n );\n }\n };\n\n // Initial scan emits warnings for broken files that exist at startup.\n rescan();\n server.watcher.on(\"add\", rescan);\n server.watcher.on(\"change\", rescan);\n server.watcher.on(\"unlink\", rescan);\n },\n\n async transform(code, id) {\n if (viewEntryPattern?.test(id) && !hasDefaultExport(code, id)) {\n this.warn(\n `View file \"${id.split(\"/\").pop()}\" is missing a default export.`,\n );\n }\n\n return await dataLlmTransform(code, id);\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function resolveViewsDir(root: string): Promise<string | undefined>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-views-dir.js","sourceRoot":"","sources":["../../src/cli/resolve-views-dir.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY;IAEZ,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,EACxC,SAAS,EACT,IAAI,CACL,CAAC;IAEF,MAAM,iBAAiB,GAAG,CACxB,KAAc,EAC2C,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;IAE9C,MAAM,OAAO,GAA0D,EAAE,CAAC;IAC1E,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC;AACpE,CAAC","sourcesContent":["export async function resolveViewsDir(\n root: string,\n): Promise<string | undefined> {\n const { loadConfigFromFile } = await import(\"vite\");\n const loaded = await loadConfigFromFile(\n { command: \"build\", mode: \"production\" },\n undefined,\n root,\n );\n\n const isPluginCandidate = (\n value: unknown,\n ): value is { name?: string; api?: { viewsDir?: string } } =>\n typeof value === \"object\" && value !== null;\n\n const plugins: Array<{ name?: string; api?: { viewsDir?: string } }> = [];\n const walk = (value: unknown) => {\n if (Array.isArray(value)) {\n value.forEach(walk);\n } else if (isPluginCandidate(value)) {\n plugins.push(value);\n }\n };\n walk(loaded?.config.plugins ?? []);\n return plugins.find((p) => p.name === \"skybridge\")?.api?.viewsDir;\n}\n"]}
|