@skybridge/vite-plugin 0.0.0-dev.7aada9d

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Alpic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ export { type EvalsPluginOptions, type SkybridgePluginOptions, skybridge, } from "./plugin.js";
2
+ export { assertUniqueViewNames, type DiscoveredView, discoverViewsSync, scanAndWriteViewsDts, scanViewsSync, writeViewsDts, } from "./scan-views.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,KAAK,cAAc,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,aAAa,GACd,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { skybridge, } from "./plugin.js";
2
+ export { assertUniqueViewNames, discoverViewsSync, scanAndWriteViewsDts, scanViewsSync, writeViewsDts, } from "./scan-views.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EAErB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,aAAa,GACd,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,72 @@
1
+ import type { PluginOption } from "vite";
2
+ /**
3
+ * Options for the eval runner wired in through the `evals` plugin option.
4
+ * Mirrors `EvalsOptions` from `@skybridge/test`, which owns the runtime; the
5
+ * shape is duplicated here so this package needs no dependency on it.
6
+ */
7
+ export interface EvalsPluginOptions {
8
+ model: {
9
+ provider: "anthropic";
10
+ name: string;
11
+ apiKeyEnv?: string;
12
+ } | {
13
+ file: string;
14
+ };
15
+ temperature?: number;
16
+ systemPrompt?: string;
17
+ maxSteps?: number;
18
+ server?: string;
19
+ project?: {
20
+ cwd: string;
21
+ command: string[];
22
+ env?: Record<string, string>;
23
+ };
24
+ }
25
+ /** Options for the {@link skybridge} Vite plugin. */
26
+ export interface SkybridgePluginOptions {
27
+ /** Directory scanned for view modules. Defaults to `"src/views"`. */
28
+ viewsDir?: string;
29
+ /**
30
+ * Package names to leave unbundled when `skybridge build` bundles the server
31
+ * for deployment. Use it for dependencies esbuild can't resolve or load —
32
+ * typically optional native modules pulled in by a transitive dependency.
33
+ */
34
+ serverExternal?: string[];
35
+ /**
36
+ * Wires the eval runner into vitest: contributes `setupFiles`,
37
+ * `globalSetup`, `provide` and `testTimeout` from `@skybridge/test`, loaded
38
+ * lazily so production builds never touch it. Set it only in the config
39
+ * vitest uses for evals; when omitted, no test config is contributed and
40
+ * ordinary unit tests are unaffected. Requires `@skybridge/test` as a dev
41
+ * dependency.
42
+ */
43
+ evals?: EvalsPluginOptions;
44
+ }
45
+ /**
46
+ * Vite plugin that wires a Skybridge project's view files into Vite.
47
+ *
48
+ * For each `.tsx` / `.jsx` file in `viewsDir` with a default export, the
49
+ * plugin:
50
+ * - exposes a virtual entry that calls {@link mountView} with the view's
51
+ * default export,
52
+ * - generates `.skybridge/views.d.ts` to augment {@link ViewNameRegistry} so
53
+ * {@link ViewName} narrows to the actual view names,
54
+ * - rewrites `<DataLLM>` JSX so the host can extract its content,
55
+ * - warns in dev if a view file is missing a default export.
56
+ *
57
+ * Add it to your `vite.config.ts` alongside `@vitejs/plugin-react`.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * // vite.config.ts
62
+ * import { defineConfig } from "vite";
63
+ * import react from "@vitejs/plugin-react";
64
+ * import { skybridge } from "@skybridge/vite-plugin";
65
+ *
66
+ * export default defineConfig({
67
+ * plugins: [react(), skybridge({ viewsDir: "src/views" })],
68
+ * });
69
+ * ```
70
+ */
71
+ export declare function skybridge(options?: SkybridgePluginOptions): PluginOption[];
72
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,YAAY,EAAiB,MAAM,MAAM,CAAC;AAchE;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EACD;QAAE,QAAQ,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3D;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC9B,CAAC;CACH;AAED,qDAAqD;AACrD,MAAM,WAAW,sBAAsB;IACrC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,YAAY,EAAE,CAO1E"}
package/dist/plugin.js ADDED
@@ -0,0 +1,227 @@
1
+ import { createRequire } from "node:module";
2
+ import { isAbsolute, relative, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { assertUniqueViewNames, discoverViewsSync, scanViewsSync, writeViewsDts, } from "./scan-views.js";
5
+ import { transform as dataLlmTransform } from "./transform-data-llm.js";
6
+ import { hasDefaultExport } from "./validate-view.js";
7
+ const VIRTUAL_PREFIX = "/_skybridge/view/";
8
+ const VIRTUAL_MODULE_PREFIX = "\0skybridge:view:";
9
+ function buildVirtualEntry(viewFilePath) {
10
+ const normalized = viewFilePath.replace(/\\/g, "/");
11
+ return [
12
+ `import { mountView } from "skybridge/web";`,
13
+ `import Component from "${normalized}";`,
14
+ `import { createElement } from "react";`,
15
+ `mountView(createElement(Component));`,
16
+ ].join("\n");
17
+ }
18
+ function getViewEntryPattern(viewsDir) {
19
+ const escaped = viewsDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20
+ return new RegExp(`${escaped}\\/(?:[^/]+\\.(?:jsx|tsx)|[^/]+\\/index\\.(?:tsx|jsx))(?:\\?.*)?$`);
21
+ }
22
+ /**
23
+ * Vite plugin that wires a Skybridge project's view files into Vite.
24
+ *
25
+ * For each `.tsx` / `.jsx` file in `viewsDir` with a default export, the
26
+ * plugin:
27
+ * - exposes a virtual entry that calls {@link mountView} with the view's
28
+ * default export,
29
+ * - generates `.skybridge/views.d.ts` to augment {@link ViewNameRegistry} so
30
+ * {@link ViewName} narrows to the actual view names,
31
+ * - rewrites `<DataLLM>` JSX so the host can extract its content,
32
+ * - warns in dev if a view file is missing a default export.
33
+ *
34
+ * Add it to your `vite.config.ts` alongside `@vitejs/plugin-react`.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // vite.config.ts
39
+ * import { defineConfig } from "vite";
40
+ * import react from "@vitejs/plugin-react";
41
+ * import { skybridge } from "@skybridge/vite-plugin";
42
+ *
43
+ * export default defineConfig({
44
+ * plugins: [react(), skybridge({ viewsDir: "src/views" })],
45
+ * });
46
+ * ```
47
+ */
48
+ export function skybridge(options) {
49
+ const plugins = [viewsPlugin(options)];
50
+ const evals = options?.evals;
51
+ if (evals !== undefined) {
52
+ plugins.push(loadEvalsPlugin(evals));
53
+ }
54
+ return plugins;
55
+ }
56
+ /**
57
+ * Resolves `@skybridge/test/plugin` from the user's project rather than from
58
+ * this package, which never depends on it: the eval runtime is an optional
59
+ * dev dependency of the app.
60
+ */
61
+ async function loadEvalsPlugin(evals) {
62
+ const projectRequire = createRequire(resolve(process.cwd(), "package.json"));
63
+ let resolved;
64
+ try {
65
+ resolved = projectRequire.resolve("@skybridge/test/plugin");
66
+ }
67
+ catch {
68
+ throw new Error("The `evals` option requires the @skybridge/test package. Install it as a dev dependency.");
69
+ }
70
+ const module = (await import(pathToFileURL(resolved).href));
71
+ return module.evals(evals);
72
+ }
73
+ function viewsPlugin(options) {
74
+ const rawViewsDir = options?.viewsDir ?? "src/views";
75
+ let resolvedViewsDir;
76
+ let projectRoot;
77
+ let viewMap = new Map();
78
+ let viewEntryPattern;
79
+ return {
80
+ name: "skybridge",
81
+ enforce: "pre",
82
+ // Read by `skybridge build` to resolve viewsDir before `tsc -b` runs, and
83
+ // to feed esbuild's external list when bundling the server.
84
+ api: { viewsDir: rawViewsDir, serverExternal: options?.serverExternal },
85
+ config(config) {
86
+ projectRoot = config.root || process.cwd();
87
+ resolvedViewsDir = isAbsolute(rawViewsDir)
88
+ ? rawViewsDir
89
+ : resolve(projectRoot, rawViewsDir);
90
+ viewEntryPattern = getViewEntryPattern(resolvedViewsDir);
91
+ const views = discoverViewsSync(resolvedViewsDir);
92
+ viewMap = new Map(views.map((v) => [v.name, v]));
93
+ writeViewsDts(projectRoot, views);
94
+ const input = {};
95
+ for (const view of views) {
96
+ input[view.name] = `${VIRTUAL_PREFIX}${view.name}`;
97
+ }
98
+ return {
99
+ base: "/assets",
100
+ // Fixes "Invalid hook call" on createStore by forcing a single
101
+ // copy of React. Under pnpm's isolated node_modules, zustand
102
+ // inside `skybridge` resolves React from skybridge's own
103
+ // dependencies while the host app loads its own copy
104
+ resolve: {
105
+ dedupe: ["react", "react-dom"],
106
+ },
107
+ build: {
108
+ outDir: "dist/assets",
109
+ emptyOutDir: true,
110
+ manifest: true,
111
+ minify: true,
112
+ cssCodeSplit: false,
113
+ rollupOptions: {
114
+ input,
115
+ },
116
+ },
117
+ // Pre-bundle view deps at startup so the first tool invocation
118
+ // doesn't hit Vite's on-demand re-optimization path (which sends
119
+ // `full-reload` over HMR — in our iframe flow the parent host
120
+ // can't honour a reload, and the view silently never mounts).
121
+ optimizeDeps: {
122
+ // Scan view files so transitive user deps (zod, tailwind, etc.)
123
+ // get pre-bundled at startup.
124
+ entries: [
125
+ `${resolvedViewsDir}/*.{tsx,jsx}`,
126
+ `${resolvedViewsDir}/*/index.{tsx,jsx}`,
127
+ ],
128
+ include: ["react", "react-dom/client", "react/jsx-runtime"],
129
+ },
130
+ experimental: {
131
+ renderBuiltUrl: (filename, { hostType }) => {
132
+ // Views render inside a host sandbox iframe, so `import.meta.url`
133
+ // points at the sandbox domain rather than the Skybridge server.
134
+ // JS asset references have to be resolved at runtime against
135
+ // `window.skybridge.serverUrl` so they follow tunnels too.
136
+ if (hostType === "js") {
137
+ return {
138
+ runtime: `window.skybridge.serverUrl + "/assets/${filename}"`,
139
+ };
140
+ }
141
+ // CSS has nowhere to evaluate a runtime expression — `vite:css-post`
142
+ // throws on one. It doesn't need it either: the stylesheet is served
143
+ // from `${serverUrl}/assets/…` and a relative `url()` resolves
144
+ // against the stylesheet's own URL, tunnel origin included.
145
+ return { relative: true };
146
+ },
147
+ },
148
+ };
149
+ },
150
+ resolveId(id) {
151
+ if (id.startsWith(VIRTUAL_PREFIX)) {
152
+ const name = id.slice(VIRTUAL_PREFIX.length);
153
+ if (viewMap.has(name)) {
154
+ return `${VIRTUAL_MODULE_PREFIX}${name}`;
155
+ }
156
+ }
157
+ return null;
158
+ },
159
+ load(id) {
160
+ if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {
161
+ const name = id.slice(VIRTUAL_MODULE_PREFIX.length);
162
+ const view = viewMap.get(name);
163
+ if (view) {
164
+ return buildVirtualEntry(view.filePath);
165
+ }
166
+ }
167
+ return null;
168
+ },
169
+ configureServer(server) {
170
+ if (!resolvedViewsDir) {
171
+ const root = server.config.root || process.cwd();
172
+ resolvedViewsDir = isAbsolute(rawViewsDir)
173
+ ? rawViewsDir
174
+ : resolve(root, rawViewsDir);
175
+ projectRoot = root;
176
+ viewEntryPattern = getViewEntryPattern(resolvedViewsDir);
177
+ }
178
+ server.watcher.add(resolvedViewsDir);
179
+ // Track which view files we've already warned about so a rescan
180
+ // triggered by an unrelated edit doesn't re-emit the same warning.
181
+ let knownInvalid = new Set();
182
+ const rescan = () => {
183
+ try {
184
+ // Surface broken view files. Without this, files lacking a
185
+ // default export are silently dropped from the input and the
186
+ // user has no idea why their widget never mounts.
187
+ const { valid, invalid } = scanViewsSync(resolvedViewsDir);
188
+ const nextInvalid = new Set(invalid.map((v) => v.filePath));
189
+ for (const filePath of nextInvalid) {
190
+ if (!knownInvalid.has(filePath)) {
191
+ server.config.logger.warn(`[skybridge] view file "${relative(projectRoot, filePath)}" is missing a default export — it won't be served until fixed.`);
192
+ }
193
+ }
194
+ for (const filePath of knownInvalid) {
195
+ if (!nextInvalid.has(filePath)) {
196
+ server.config.logger.info(`[skybridge] view file "${relative(projectRoot, filePath)}" resolved.`);
197
+ }
198
+ }
199
+ knownInvalid = nextInvalid;
200
+ assertUniqueViewNames(valid);
201
+ viewMap = new Map(valid.map((v) => [v.name, v]));
202
+ writeViewsDts(projectRoot, valid);
203
+ }
204
+ catch (err) {
205
+ // assertUniqueViewNames throws on duplicate view names. Catch so
206
+ // chokidar's listener chain doesn't surface it as unhandled and
207
+ // crash the dev server — previous viewMap stays active until
208
+ // the user fixes the conflict.
209
+ const message = err instanceof Error ? err.message : String(err);
210
+ server.config.logger.error(`[skybridge] view rescan failed: ${message}`);
211
+ }
212
+ };
213
+ // Initial scan emits warnings for broken files that exist at startup.
214
+ rescan();
215
+ server.watcher.on("add", rescan);
216
+ server.watcher.on("change", rescan);
217
+ server.watcher.on("unlink", rescan);
218
+ },
219
+ async transform(code, id) {
220
+ if (viewEntryPattern?.test(id) && !hasDefaultExport(code, id)) {
221
+ this.warn(`View file "${id.split("/").pop()}" is missing a default export.`);
222
+ }
223
+ return await dataLlmTransform(code, id);
224
+ },
225
+ };
226
+ }
227
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface DiscoveredView {
2
+ name: string;
3
+ filePath: string;
4
+ }
5
+ export interface InvalidView {
6
+ filePath: string;
7
+ }
8
+ export declare function scanViewsSync(viewsDir: string): {
9
+ valid: DiscoveredView[];
10
+ invalid: InvalidView[];
11
+ };
12
+ export declare function assertUniqueViewNames(views: DiscoveredView[]): void;
13
+ export declare function discoverViewsSync(viewsDir: string): DiscoveredView[];
14
+ export declare function generateViewsDts(views: DiscoveredView[]): string;
15
+ export declare function writeViewsDts(projectRoot: string, views: DiscoveredView[]): void;
16
+ export declare function scanAndWriteViewsDts(projectRoot?: string, viewsDir?: string): void;
17
+ //# sourceMappingURL=scan-views.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-views.d.ts","sourceRoot":"","sources":["../src/scan-views.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAC/C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAmCA;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI,CAenE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAIpE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAYhE;AAED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,cAAc,EAAE,GACtB,IAAI,CAiBN;AAED,wBAAgB,oBAAoB,CAClC,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CAON"}
@@ -0,0 +1,88 @@
1
+ import { globSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname, isAbsolute, join, parse, resolve } from "node:path";
3
+ import { hasDefaultExport } from "./validate-view.js";
4
+ export function scanViewsSync(viewsDir) {
5
+ const flatPattern = resolve(viewsDir, "*.{tsx,jsx}");
6
+ const dirPattern = resolve(viewsDir, "*/index.{tsx,jsx}");
7
+ const flatFiles = globSync(flatPattern).map((file) => ({
8
+ name: parse(file).name,
9
+ filePath: file,
10
+ }));
11
+ const dirFiles = globSync(dirPattern).map((file) => ({
12
+ name: basename(dirname(file)),
13
+ filePath: file,
14
+ }));
15
+ // A barrel file like `views/foo/index.tsx` (no default export) must not
16
+ // falsely collide with a sibling `views/foo.tsx`. Drop top-level `index`
17
+ // before splitting valid vs invalid.
18
+ const candidates = [...flatFiles, ...dirFiles].filter((v) => v.name !== "index");
19
+ const valid = [];
20
+ const invalid = [];
21
+ for (const candidate of candidates) {
22
+ const code = readFileSync(candidate.filePath, "utf-8");
23
+ if (hasDefaultExport(code, candidate.filePath)) {
24
+ valid.push(candidate);
25
+ }
26
+ else {
27
+ invalid.push({
28
+ filePath: candidate.filePath,
29
+ });
30
+ }
31
+ }
32
+ return { valid, invalid };
33
+ }
34
+ export function assertUniqueViewNames(views) {
35
+ const nameMap = new Map();
36
+ for (const view of views) {
37
+ const paths = nameMap.get(view.name) ?? [];
38
+ paths.push(view.filePath);
39
+ nameMap.set(view.name, paths);
40
+ }
41
+ for (const [name, paths] of nameMap) {
42
+ if (paths.length > 1) {
43
+ throw new Error(`skybridge: duplicate view name "${name}" resolved from:\n - ${paths.join("\n - ")}\nRename one of the files to avoid the conflict.`);
44
+ }
45
+ }
46
+ }
47
+ export function discoverViewsSync(viewsDir) {
48
+ const { valid } = scanViewsSync(viewsDir);
49
+ assertUniqueViewNames(valid);
50
+ return valid;
51
+ }
52
+ export function generateViewsDts(views) {
53
+ const entries = views.map((v) => ` "${v.name}": true;`).join("\n");
54
+ return [
55
+ "export {};",
56
+ "",
57
+ 'declare module "skybridge/server" {',
58
+ " interface ViewNameRegistry {",
59
+ entries,
60
+ " }",
61
+ "}",
62
+ "",
63
+ ].join("\n");
64
+ }
65
+ export function writeViewsDts(projectRoot, views) {
66
+ const dir = join(projectRoot, ".skybridge");
67
+ mkdirSync(dir, { recursive: true });
68
+ const filePath = join(dir, "views.d.ts");
69
+ const content = generateViewsDts(views);
70
+ try {
71
+ const existing = readFileSync(filePath, "utf-8");
72
+ if (existing === content) {
73
+ return;
74
+ }
75
+ }
76
+ catch {
77
+ // File doesn't exist yet
78
+ }
79
+ writeFileSync(filePath, content, "utf-8");
80
+ }
81
+ export function scanAndWriteViewsDts(projectRoot, viewsDir) {
82
+ const root = projectRoot ?? process.cwd();
83
+ const rawDir = viewsDir ?? "src/views";
84
+ const resolvedDir = isAbsolute(rawDir) ? rawDir : resolve(root, rawDir);
85
+ const views = discoverViewsSync(resolvedDir);
86
+ writeViewsDts(root, views);
87
+ }
88
+ //# sourceMappingURL=scan-views.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-views.js","sourceRoot":"","sources":["../src/scan-views.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const transform: (code: string, id: string) => Promise<{
2
+ code: string;
3
+ map: {
4
+ version: number;
5
+ sources: string[];
6
+ names: string[];
7
+ sourceRoot?: string | undefined;
8
+ sourcesContent?: string[] | undefined;
9
+ mappings: string;
10
+ file: string;
11
+ } | null;
12
+ } | null>;
13
+ //# sourceMappingURL=transform-data-llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-data-llm.d.ts","sourceRoot":"","sources":["../src/transform-data-llm.ts"],"names":[],"mappings":"AA+HA,eAAO,MAAM,SAAS,GAAU,MAAM,MAAM,EAAE,IAAI,MAAM;;;;;;;;;;;SA+BvD,CAAC"}
@@ -0,0 +1,96 @@
1
+ const LLM_IMPORT_SOURCE = "skybridge/web";
2
+ function createBabelPlugin(t) {
3
+ return {
4
+ name: "data-llm-babel",
5
+ visitor: {
6
+ Program: {
7
+ enter(path, state) {
8
+ state.hasDataLLMImport = false;
9
+ state.needsDataLLMImport = false;
10
+ for (const node of path.node.body) {
11
+ if (!t.isImportDeclaration(node)) {
12
+ continue;
13
+ }
14
+ if (node.source.value !== LLM_IMPORT_SOURCE) {
15
+ continue;
16
+ }
17
+ const hasSpecifier = node.specifiers.some((s) => t.isImportSpecifier(s) &&
18
+ t.isIdentifier(s.imported, { name: "DataLLM" }));
19
+ if (hasSpecifier) {
20
+ state.hasDataLLMImport = true;
21
+ break;
22
+ }
23
+ }
24
+ },
25
+ exit(path, state) {
26
+ if (state.needsDataLLMImport && !state.hasDataLLMImport) {
27
+ const importDecl = t.importDeclaration([
28
+ t.importSpecifier(t.identifier("DataLLM"), t.identifier("DataLLM")),
29
+ ], t.stringLiteral(LLM_IMPORT_SOURCE));
30
+ path.node.body.unshift(importDecl);
31
+ }
32
+ },
33
+ },
34
+ JSXElement(path, state) {
35
+ const opening = path.node.openingElement;
36
+ const attributes = opening.attributes;
37
+ const llmAttributeIndex = attributes.findIndex((attribute) => t.isJSXAttribute(attribute) &&
38
+ t.isJSXIdentifier(attribute.name, { name: "data-llm" }));
39
+ if (llmAttributeIndex === -1) {
40
+ return;
41
+ }
42
+ const llmAttribute = attributes[llmAttributeIndex];
43
+ let contentExpression;
44
+ if (t.isStringLiteral(llmAttribute.value)) {
45
+ contentExpression = llmAttribute.value;
46
+ }
47
+ else if (t.isJSXExpressionContainer(llmAttribute.value)) {
48
+ contentExpression = llmAttribute.value.expression;
49
+ }
50
+ else {
51
+ return;
52
+ }
53
+ const contentAttr = t.jsxAttribute(t.jsxIdentifier("content"), t.isStringLiteral(contentExpression)
54
+ ? contentExpression
55
+ : t.jsxExpressionContainer(contentExpression));
56
+ const filteredAttributes = attributes.filter((_, index) => index !== llmAttributeIndex);
57
+ const newOpening = t.jsxOpeningElement(opening.name, filteredAttributes, opening.selfClosing);
58
+ const elementWithoutLlm = t.jsxElement(newOpening, path.node.closingElement, path.node.children, path.node.selfClosing);
59
+ const llmOpening = t.jsxOpeningElement(t.jsxIdentifier("DataLLM"), [
60
+ contentAttr,
61
+ ]);
62
+ const llmClosing = t.jsxClosingElement(t.jsxIdentifier("DataLLM"));
63
+ const wrapped = t.jsxElement(llmOpening, llmClosing, [elementWithoutLlm], false);
64
+ state.needsDataLLMImport = true;
65
+ path.replaceWith(wrapped);
66
+ },
67
+ },
68
+ };
69
+ }
70
+ export const transform = async (code, id) => {
71
+ if (!/\.(jsx|tsx)$/.test(id)) {
72
+ return null;
73
+ }
74
+ if (id.includes("node_modules")) {
75
+ return null;
76
+ }
77
+ // Dynamic import to ensure @babel/core is only loaded in Node.js context
78
+ const { types: t, transformSync } = await import("@babel/core");
79
+ const babelOptions = {
80
+ plugins: [createBabelPlugin(t)],
81
+ parserOpts: {
82
+ plugins: ["jsx", "typescript"],
83
+ },
84
+ filename: id,
85
+ sourceFileName: id,
86
+ };
87
+ const result = transformSync(code, babelOptions);
88
+ if (!result?.code) {
89
+ return null;
90
+ }
91
+ return {
92
+ code: result.code,
93
+ map: result.map || null,
94
+ };
95
+ };
96
+ //# sourceMappingURL=transform-data-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-data-llm.js","sourceRoot":"","sources":["../src/transform-data-llm.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAO1C,SAAS,iBAAiB,CAAC,CAAe;IACxC,OAAO;QACL,IAAI,EAAE,gBAAgB;QAEtB,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,KAAK,CAAC,IAAI,EAAE,KAAK;oBACf,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAC;oBAC/B,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC;oBAEjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;wBAClC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;4BACjC,SAAS;wBACX,CAAC;wBACD,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,iBAAiB,EAAE,CAAC;4BAC5C,SAAS;wBACX,CAAC;wBAED,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;4BACtB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAClD,CAAC;wBAEF,IAAI,YAAY,EAAE,CAAC;4BACjB,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;4BAC9B,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,IAAI,EAAE,KAAK;oBACd,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;wBACxD,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,CACpC;4BACE,CAAC,CAAC,eAAe,CACf,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EACvB,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CACxB;yBACF,EACD,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CACnC,CAAC;wBAEF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBACrC,CAAC;gBACH,CAAC;aACF;YAED,UAAU,CAAC,IAAI,EAAE,KAAK;gBACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;gBACzC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;gBAEtC,MAAM,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAC5C,CAAC,SAAS,EAAE,EAAE,CACZ,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC;oBAC3B,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAC1D,CAAC;gBAEF,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC7B,OAAO;gBACT,CAAC;gBAED,MAAM,YAAY,GAAG,UAAU,CAC7B,iBAAiB,CACI,CAAC;gBAExB,IAAI,iBAAmC,CAAC;gBAExC,IAAI,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1C,iBAAiB,GAAG,YAAY,CAAC,KAAK,CAAC;gBACzC,CAAC;qBAAM,IAAI,CAAC,CAAC,wBAAwB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1D,iBAAiB,GAAG,YAAY,CAAC,KAAK,CAAC,UAA8B,CAAC;gBACxE,CAAC;qBAAM,CAAC;oBACN,OAAO;gBACT,CAAC;gBAED,MAAM,WAAW,GAAG,CAAC,CAAC,YAAY,CAChC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,EAC1B,CAAC,CAAC,eAAe,CAAC,iBAAiB,CAAC;oBAClC,CAAC,CAAC,iBAAiB;oBACnB,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAChD,CAAC;gBAEF,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,iBAAiB,CAC1C,CAAC;gBACF,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,CACpC,OAAO,CAAC,IAAI,EACZ,kBAAkB,EAClB,OAAO,CAAC,WAAW,CACpB,CAAC;gBAEF,MAAM,iBAAiB,GAAG,CAAC,CAAC,UAAU,CACpC,UAAU,EACV,IAAI,CAAC,IAAI,CAAC,cAAc,EACxB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAClB,IAAI,CAAC,IAAI,CAAC,WAAW,CACtB,CAAC;gBAEF,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE;oBACjE,WAAW;iBACZ,CAAC,CAAC;gBACH,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;gBAEnE,MAAM,OAAO,GAAG,CAAC,CAAC,UAAU,CAC1B,UAAU,EACV,UAAU,EACV,CAAC,iBAAiB,CAAC,EACnB,KAAK,CACN,CAAC;gBAEF,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC;gBAChC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,IAAY,EAAE,EAAU,EAAE,EAAE;IAC1D,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yEAAyE;IACzE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAEhE,MAAM,YAAY,GAAqB;QACrC,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC/B,UAAU,EAAE;YACV,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;SAC/B;QACD,QAAQ,EAAE,EAAE;QACZ,cAAc,EAAE,EAAE;KACnB,CAAC;IAEF,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEjD,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,IAAI;KACxB,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function hasDefaultExport(code: string, _filePath?: string): boolean;
2
+ //# sourceMappingURL=validate-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-view.d.ts","sourceRoot":"","sources":["../src/validate-view.ts"],"names":[],"mappings":"AAIA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAM1E"}
@@ -0,0 +1,9 @@
1
+ function stripComments(code) {
2
+ return code.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
3
+ }
4
+ export function hasDefaultExport(code, _filePath) {
5
+ const stripped = stripComments(code);
6
+ return (/export\s+default\s/.test(stripped) ||
7
+ /export\s*\{[^}]*\bas\s+default\b[^}]*}/.test(stripped));
8
+ }
9
+ //# sourceMappingURL=validate-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-view.js","sourceRoot":"","sources":["../src/validate-view.ts"],"names":[],"mappings":"AAAA,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,SAAkB;IAC/D,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,CACL,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC;QACnC,wCAAwC,CAAC,IAAI,CAAC,QAAQ,CAAC,CACxD,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@skybridge/vite-plugin",
3
+ "version": "0.0.0-dev.7aada9d",
4
+ "description": "The Skybridge Vite plugin: view discovery, data-llm transforms, and eval wiring",
5
+ "license": "ISC",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/alpic-ai/skybridge.git"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@babel/core": "^7.29.7"
22
+ },
23
+ "peerDependencies": {
24
+ "vite": ">=7.3.1"
25
+ },
26
+ "devDependencies": {
27
+ "@types/babel__core": "^7.20.5",
28
+ "@types/node": "^24.13.3",
29
+ "typescript": "^5.9.3",
30
+ "vite": "^8.1.5",
31
+ "vitest": "^4.1.10"
32
+ },
33
+ "engines": {
34
+ "node": ">=22.23.1"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json",
38
+ "format": "biome check --write --error-on-warnings",
39
+ "test": "pnpm run test:format && pnpm run test:types && pnpm run test:unit",
40
+ "test:format": "biome ci",
41
+ "test:types": "tsc --noEmit -p tsconfig.test.json",
42
+ "test:unit": "vitest run"
43
+ }
44
+ }