@fluixi/vite-plugin 1.0.0-alpha.83 → 1.0.0-alpha.85

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/index.cjs CHANGED
@@ -1,10 +1,64 @@
1
- "use strict";var V=Object.create;var g=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty;var A=(e,t)=>{for(var o in t)g(e,o,{get:t[o],enumerable:!0})},I=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of G(t))!L.call(e,r)&&r!==o&&g(e,r,{get:()=>t[r],enumerable:!(n=D(t,r))||n.enumerable});return e};var J=(e,t,o)=>(o=e!=null?V(j(e)):{},I(t||!e||!e.__esModule?g(o,"default",{value:e,enumerable:!0}):o,e)),M=e=>I(g({},"__esModule",{value:!0}),e);var Q={};A(Q,{createVitePlugin:()=>x.createVitePlugin,default:()=>B,fluixi:()=>E});module.exports=M(Q);var x=require("@fluixi/compiler/integrations");var w=require("node:module"),N=require("node:path"),$={},v="virtual:fluixi/devtools-agent",R=`\0${v}`,_="/__fluixi/graph",O="fluixi:graph",m="the plugin could not load @fluixi/devtools from its own dependencies",W="no page has reported yet — open the application in a browser",q=100,F=500,z=(e,t,o,n)=>`
2
- import { installDevtoolsHook, observeGraph } from ${JSON.stringify(e)};
3
- import ${JSON.stringify(t)};
4
- import { observeReactiveNodes } from ${JSON.stringify(o)};
5
- import { VERSION } from ${JSON.stringify(n)};
1
+ /*! @fluixi/vite-plugin v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
6
30
 
7
- // The runtime this module imports is the application's own — same module graph, same nodes.
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ createVitePlugin: () => import_integrations.createVitePlugin,
35
+ default: () => index_default,
36
+ fluixi: () => fluixi
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+ var import_integrations = require("@fluixi/compiler/integrations");
40
+
41
+ // src/graph-channel.ts
42
+ var import_node_module = require("node:module");
43
+ var import_node_fs = require("node:fs");
44
+ var import_node_path = require("node:path");
45
+ var import_node_url = require("node:url");
46
+ var import_meta = {};
47
+ var VIRTUAL = "virtual:fluixi/devtools-agent";
48
+ var RESOLVED = `\0${VIRTUAL}`;
49
+ var ENDPOINT = "/__fluixi/graph";
50
+ var EVENT = "fluixi:graph";
51
+ var MISSING = "the plugin could not load @fluixi/devtools from its own dependencies";
52
+ var WAITING = "no page has reported yet — open the application in a browser";
53
+ var INTERVAL = 100;
54
+ var HISTORY = 500;
55
+ var agentSource = (devtools, plugins, signal, reactive) => `
56
+ import { installDevtoolsHook, observeGraph } from ${JSON.stringify(devtools)};
57
+ import ${JSON.stringify(plugins)};
58
+ import { observeReactiveNodes } from ${JSON.stringify(signal)};
59
+ import { VERSION } from ${JSON.stringify(reactive)};
60
+
61
+ // The runtime this module imports is the application's own, same module graph, same nodes.
8
62
  // Nothing waits for the runtime to offer itself; that path is for a tool loaded from outside.
9
63
  //
10
64
  // \`watch\` is this copy of devtools, handed over with the runtime. A browser extension
@@ -13,7 +67,7 @@ import { VERSION } from ${JSON.stringify(n)};
13
67
  const hook = installDevtoolsHook();
14
68
  hook.inject({ observeReactiveNodes, version: VERSION, watch: observeGraph });
15
69
 
16
- const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(O)}, { kind, snapshot });
70
+ const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(EVENT)}, { kind, snapshot });
17
71
 
18
72
  const first = hook.snapshot();
19
73
  // Kept and handed back, so a browser panel polling the same hook cannot consume what this
@@ -26,7 +80,146 @@ const timer = setInterval(() => {
26
80
  cursor = delta.cursor;
27
81
  // Events count on their own: an effect that ran without changing a value moves no node.
28
82
  if (delta.nodes.length || delta.removed?.length || delta.events?.length) send('delta', delta);
29
- }, ${q});
83
+ }, ${INTERVAL});
30
84
 
31
85
  import.meta.hot?.dispose(() => clearInterval(timer));
32
- `;function K(){try{return(0,w.createRequire)($.url).resolve("@fluixi/devtools")}catch{return null}}function U(){try{return(0,w.createRequire)($.url).resolve("@fluixi/devtools/plugins")}catch{return null}}function P(e,t,o){let n=null,r=!1,a=m,p=process.cwd(),c,h=new Map,y=0,f=[],C=e.resolveId,H=e.transformIndexHtml;return{...e,resolveId(s,u){return s===v?R:C?.call(this,s,u)??null},async load(s){if(s!==R)return null;let u=(0,N.join)(p,"fluixi-devtools-agent.js"),i=["@fluixi/reactive/signal","@fluixi/reactive"],l=await Promise.all(i.map(S=>this.resolve?.(S,u,{skipSelf:!0}))),d=i.filter((S,T)=>!l[T]?.id),b=K(),k=U();return d.length||!b||!k?(a=d.length?`${d.join(", ")} did not resolve from ${p}`:m,c?.(`[fluixi] reactive graph off — ${a}`),"export {};"):z(`/@fs/${b}`,`/@fs/${k}`,l[0].id,l[1].id)},async configureServer(s){t()&&(p=s.config?.root??p,c=s.config?.logger?.info.bind(s.config.logger),n=await import("@fluixi/devtools/wire").catch(()=>null),r=n!==null,n&&o(),n?a=W:c?.(`[fluixi] reactive graph off — ${m}`),s.middlewares.use(_,(u,i)=>{let l=n?{...n.serializeGraph(h,y||Date.now()),events:f}:{t:Date.now(),nodes:[]},d=JSON.stringify(a?{...l,reason:a}:l);i.setHeader("Content-Type","application/json"),i.setHeader("Access-Control-Allow-Origin","*"),i.setHeader("Cache-Control","no-store"),i.end(d)}),n&&s.ws.on(O,u=>{let i=u;if(!i?.snapshot||!n)return;let l=i.kind==="full";h=n.applySnapshot(l?new Map:h,i.snapshot),l&&(f=[]);let d=i.snapshot.events;d?.length&&(f=[...f,...d].slice(-F)),y=Date.now(),a=null}))},transformIndexHtml:{order:"pre",handler(s,u){let i=Y(H,s,u);return!t()||!r||!n?i:{html:typeof i=="string"?i:s,tags:[{tag:"script",injectTo:"head-prepend",attrs:{type:"module",src:`/@id/${v}`}}]}}}}}function Y(e,t,o){if(typeof e=="function")return e(t,o);let n=e?.handler;return n?.(t,o)}function E(e={}){let t=e,o=!1,n=()=>o&&t.devtools!==!1,r=(0,x.createVitePlugin)(t),a=r.configResolved,p=()=>{t.sourceLocations=!0,t.sourceLocationsExternal=typeof t.devtools=="object"&&t.devtools.external===!0};return P({...r,configResolved(c){a?.(c),o=c?.command==="serve",t.sourceRoot=c.root}},n,p)}var B=E;
86
+ `;
87
+ function ownDevtools() {
88
+ return resolveForBrowser("@fluixi/devtools");
89
+ }
90
+ function ownPlugins() {
91
+ return resolveForBrowser("@fluixi/devtools/plugins");
92
+ }
93
+ function resolveForBrowser(spec) {
94
+ try {
95
+ const resolved = import_meta.resolve?.(spec);
96
+ if (resolved) return (0, import_node_url.fileURLToPath)(resolved);
97
+ } catch {
98
+ }
99
+ try {
100
+ const required = (0, import_node_module.createRequire)(import_meta.url).resolve(spec);
101
+ if (!required.endsWith(".cjs")) return required;
102
+ for (const ext of [".mjs", ".js"]) {
103
+ const sibling = required.slice(0, -".cjs".length) + ext;
104
+ if ((0, import_node_fs.existsSync)(sibling)) return sibling;
105
+ }
106
+ return required;
107
+ } catch {
108
+ return null;
109
+ }
110
+ }
111
+ function withGraphChannel(base, enabled, start) {
112
+ let wire = null;
113
+ let available = false;
114
+ let reason = MISSING;
115
+ let root = process.cwd();
116
+ let log;
117
+ let graph = /* @__PURE__ */ new Map();
118
+ let stamp = 0;
119
+ let events = [];
120
+ const baseResolveId = base.resolveId;
121
+ const baseTransformIndexHtml = base.transformIndexHtml;
122
+ return {
123
+ ...base,
124
+ resolveId(id, importer) {
125
+ if (id === VIRTUAL) return RESOLVED;
126
+ return baseResolveId?.call(this, id, importer) ?? null;
127
+ },
128
+ async load(id) {
129
+ if (id !== RESOLVED) return null;
130
+ const from = (0, import_node_path.join)(root, "fluixi-devtools-agent.js");
131
+ const specs = ["@fluixi/reactive/signal", "@fluixi/reactive"];
132
+ const ids = await Promise.all(specs.map((spec) => this.resolve?.(spec, from, { skipSelf: true })));
133
+ const missing = specs.filter((_, i) => !ids[i]?.id);
134
+ const devtools = ownDevtools();
135
+ const plugins = ownPlugins();
136
+ if (missing.length || !devtools || !plugins) {
137
+ reason = missing.length ? `${missing.join(", ")} did not resolve from ${root}` : MISSING;
138
+ log?.(`[fluixi] reactive graph off — ${reason}`);
139
+ return "export {};";
140
+ }
141
+ return agentSource(`/@fs/${devtools}`, `/@fs/${plugins}`, ids[0].id, ids[1].id);
142
+ },
143
+ async configureServer(server) {
144
+ if (!enabled()) return;
145
+ root = server.config?.root ?? root;
146
+ log = server.config?.logger?.info.bind(server.config.logger);
147
+ wire = await import("@fluixi/devtools/wire").catch(() => null);
148
+ available = wire !== null;
149
+ if (wire) start();
150
+ if (wire) reason = WAITING;
151
+ else {
152
+ log?.(`[fluixi] reactive graph off — ${MISSING}`);
153
+ }
154
+ server.middlewares.use(ENDPOINT, (_req, res) => {
155
+ const snapshot = wire ? { ...wire.serializeGraph(graph, stamp || Date.now()), events } : { t: Date.now(), nodes: [] };
156
+ const body = JSON.stringify(reason ? { ...snapshot, reason } : snapshot);
157
+ res.setHeader("Content-Type", "application/json");
158
+ res.setHeader("Access-Control-Allow-Origin", "*");
159
+ res.setHeader("Cache-Control", "no-store");
160
+ res.end(body);
161
+ });
162
+ if (!wire) return;
163
+ server.ws.on(EVENT, (payload) => {
164
+ const message = payload;
165
+ if (!message?.snapshot || !wire) return;
166
+ const full = message.kind === "full";
167
+ graph = wire.applySnapshot(full ? /* @__PURE__ */ new Map() : graph, message.snapshot);
168
+ if (full) events = [];
169
+ const arriving = message.snapshot.events;
170
+ if (arriving?.length) events = [...events, ...arriving].slice(-HISTORY);
171
+ stamp = Date.now();
172
+ reason = null;
173
+ });
174
+ },
175
+ transformIndexHtml: {
176
+ order: "pre",
177
+ handler(html, ctx) {
178
+ const inherited = callInheritedHtml(baseTransformIndexHtml, html, ctx);
179
+ if (!enabled() || !available || !wire) return inherited;
180
+ return {
181
+ html: typeof inherited === "string" ? inherited : html,
182
+ tags: [
183
+ {
184
+ tag: "script",
185
+ // First in the head, so the entry cannot create a node before the agent runs.
186
+ injectTo: "head-prepend",
187
+ attrs: { type: "module", src: `/@id/${VIRTUAL}` }
188
+ }
189
+ ]
190
+ };
191
+ }
192
+ }
193
+ };
194
+ }
195
+ function callInheritedHtml(hook, html, ctx) {
196
+ if (typeof hook === "function") return hook(html, ctx);
197
+ const handler = hook?.handler;
198
+ return handler?.(html, ctx);
199
+ }
200
+
201
+ // src/index.ts
202
+ function fluixi(options = {}) {
203
+ const settings = options;
204
+ let serving = false;
205
+ const enabled = () => serving && settings.devtools !== false;
206
+ const base = (0, import_integrations.createVitePlugin)(settings);
207
+ const inherited = base.configResolved;
208
+ const start = () => {
209
+ settings.sourceLocations = true;
210
+ settings.sourceLocationsExternal = typeof settings.devtools === "object" && settings.devtools.external === true;
211
+ };
212
+ return withGraphChannel(
213
+ {
214
+ ...base,
215
+ configResolved(config) {
216
+ inherited?.(config);
217
+ serving = config?.command === "serve";
218
+ settings.sourceRoot = config.root;
219
+ }
220
+ },
221
+ enabled,
222
+ start
223
+ );
224
+ }
225
+ var index_default = fluixi;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @fileoverview @fluixi/vite-plugin the Vite integration for Fluixi.
2
+ * @fileoverview @fluixi/vite-plugin: the Vite integration for Fluixi.
3
3
  * @module @fluixi/vite-plugin
4
4
  *
5
5
  * Thin, well-typed wrapper around @fluixi/compiler's vite integration. It sets
6
6
  * the esbuild jsxImportSource and runs the Fluixi transform: JSX and `` html`` ``
7
7
  * templates both lower to the shared IR and compile straight into @fluixi/dom
8
- * runtime calls no per-render jsx() dispatch.
8
+ * runtime calls: no per-render jsx() dispatch.
9
9
  */
10
10
  import type { Plugin } from 'vite';
11
11
  import { createVitePlugin, type CompilerOptions } from '@fluixi/compiler/integrations';
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { withGraphChannel } from './graph-channel.js';
15
15
  */
16
16
  export function fluixi(options = {}) {
17
17
  // The compiler reads this object per transform, so turning source marks on once the
18
- // command is known reaches every file they are worth their size in dev and nothing in a
18
+ // command is known reaches every file: they are worth their size in dev and nothing in a
19
19
  // build, which is why the answer waits for configResolved.
20
20
  const settings = options;
21
21
  let serving = false;
@@ -33,7 +33,7 @@ export function fluixi(options = {}) {
33
33
  configResolved(config) {
34
34
  inherited?.(config);
35
35
  // `serve` covers vitest as well as the dev server, and a test run has no page to
36
- // watch the marks would only change what the compiler emits under test. The
36
+ // watch: the marks would only change what the compiler emits under test. The
37
37
  // channel turns them on from configureServer, which only a real server calls.
38
38
  serving = config?.command === 'serve';
39
39
  settings.sourceRoot = config.root;
package/dist/index.mjs CHANGED
@@ -1,10 +1,28 @@
1
- import{createVitePlugin as j}from"@fluixi/compiler/integrations";import{createRequire as k}from"node:module";import{join as P}from"node:path";var m="virtual:fluixi/devtools-agent",b=`\0${m}`,$="/__fluixi/graph",S="fluixi:graph",h="the plugin could not load @fluixi/devtools from its own dependencies",E="no page has reported yet — open the application in a browser",C=100,H=500,T=(i,n,s,t)=>`
2
- import { installDevtoolsHook, observeGraph } from ${JSON.stringify(i)};
3
- import ${JSON.stringify(n)};
4
- import { observeReactiveNodes } from ${JSON.stringify(s)};
5
- import { VERSION } from ${JSON.stringify(t)};
1
+ /*! @fluixi/vite-plugin v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
6
2
 
7
- // The runtime this module imports is the application's own — same module graph, same nodes.
3
+ // src/index.ts
4
+ import { createVitePlugin } from "@fluixi/compiler/integrations";
5
+
6
+ // src/graph-channel.ts
7
+ import { createRequire } from "node:module";
8
+ import { existsSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ var VIRTUAL = "virtual:fluixi/devtools-agent";
12
+ var RESOLVED = `\0${VIRTUAL}`;
13
+ var ENDPOINT = "/__fluixi/graph";
14
+ var EVENT = "fluixi:graph";
15
+ var MISSING = "the plugin could not load @fluixi/devtools from its own dependencies";
16
+ var WAITING = "no page has reported yet — open the application in a browser";
17
+ var INTERVAL = 100;
18
+ var HISTORY = 500;
19
+ var agentSource = (devtools, plugins, signal, reactive) => `
20
+ import { installDevtoolsHook, observeGraph } from ${JSON.stringify(devtools)};
21
+ import ${JSON.stringify(plugins)};
22
+ import { observeReactiveNodes } from ${JSON.stringify(signal)};
23
+ import { VERSION } from ${JSON.stringify(reactive)};
24
+
25
+ // The runtime this module imports is the application's own, same module graph, same nodes.
8
26
  // Nothing waits for the runtime to offer itself; that path is for a tool loaded from outside.
9
27
  //
10
28
  // \`watch\` is this copy of devtools, handed over with the runtime. A browser extension
@@ -13,7 +31,7 @@ import { VERSION } from ${JSON.stringify(t)};
13
31
  const hook = installDevtoolsHook();
14
32
  hook.inject({ observeReactiveNodes, version: VERSION, watch: observeGraph });
15
33
 
16
- const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(S)}, { kind, snapshot });
34
+ const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(EVENT)}, { kind, snapshot });
17
35
 
18
36
  const first = hook.snapshot();
19
37
  // Kept and handed back, so a browser panel polling the same hook cannot consume what this
@@ -26,7 +44,151 @@ const timer = setInterval(() => {
26
44
  cursor = delta.cursor;
27
45
  // Events count on their own: an effect that ran without changing a value moves no node.
28
46
  if (delta.nodes.length || delta.removed?.length || delta.events?.length) send('delta', delta);
29
- }, ${C});
47
+ }, ${INTERVAL});
30
48
 
31
49
  import.meta.hot?.dispose(() => clearInterval(timer));
32
- `;function V(){try{return k(import.meta.url).resolve("@fluixi/devtools")}catch{return null}}function D(){try{return k(import.meta.url).resolve("@fluixi/devtools/plugins")}catch{return null}}function I(i,n,s){let t=null,p=!1,l=h,c=process.cwd(),d,g=new Map,v=0,f=[],R=i.resolveId,N=i.transformIndexHtml;return{...i,resolveId(o,a){return o===m?b:R?.call(this,o,a)??null},async load(o){if(o!==b)return null;let a=P(c,"fluixi-devtools-agent.js"),e=["@fluixi/reactive/signal","@fluixi/reactive"],r=await Promise.all(e.map(y=>this.resolve?.(y,a,{skipSelf:!0}))),u=e.filter((y,O)=>!r[O]?.id),w=V(),x=D();return u.length||!w||!x?(l=u.length?`${u.join(", ")} did not resolve from ${c}`:h,d?.(`[fluixi] reactive graph off — ${l}`),"export {};"):T(`/@fs/${w}`,`/@fs/${x}`,r[0].id,r[1].id)},async configureServer(o){n()&&(c=o.config?.root??c,d=o.config?.logger?.info.bind(o.config.logger),t=await import("@fluixi/devtools/wire").catch(()=>null),p=t!==null,t&&s(),t?l=E:d?.(`[fluixi] reactive graph off — ${h}`),o.middlewares.use($,(a,e)=>{let r=t?{...t.serializeGraph(g,v||Date.now()),events:f}:{t:Date.now(),nodes:[]},u=JSON.stringify(l?{...r,reason:l}:r);e.setHeader("Content-Type","application/json"),e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Cache-Control","no-store"),e.end(u)}),t&&o.ws.on(S,a=>{let e=a;if(!e?.snapshot||!t)return;let r=e.kind==="full";g=t.applySnapshot(r?new Map:g,e.snapshot),r&&(f=[]);let u=e.snapshot.events;u?.length&&(f=[...f,...u].slice(-H)),v=Date.now(),l=null}))},transformIndexHtml:{order:"pre",handler(o,a){let e=G(N,o,a);return!n()||!p||!t?e:{html:typeof e=="string"?e:o,tags:[{tag:"script",injectTo:"head-prepend",attrs:{type:"module",src:`/@id/${m}`}}]}}}}}function G(i,n,s){if(typeof i=="function")return i(n,s);let t=i?.handler;return t?.(n,s)}function L(i={}){let n=i,s=!1,t=()=>s&&n.devtools!==!1,p=j(n),l=p.configResolved,c=()=>{n.sourceLocations=!0,n.sourceLocationsExternal=typeof n.devtools=="object"&&n.devtools.external===!0};return I({...p,configResolved(d){l?.(d),s=d?.command==="serve",n.sourceRoot=d.root}},t,c)}var q=L;export{j as createVitePlugin,q as default,L as fluixi};
50
+ `;
51
+ function ownDevtools() {
52
+ return resolveForBrowser("@fluixi/devtools");
53
+ }
54
+ function ownPlugins() {
55
+ return resolveForBrowser("@fluixi/devtools/plugins");
56
+ }
57
+ function resolveForBrowser(spec) {
58
+ try {
59
+ const resolved = import.meta.resolve?.(spec);
60
+ if (resolved) return fileURLToPath(resolved);
61
+ } catch {
62
+ }
63
+ try {
64
+ const required = createRequire(import.meta.url).resolve(spec);
65
+ if (!required.endsWith(".cjs")) return required;
66
+ for (const ext of [".mjs", ".js"]) {
67
+ const sibling = required.slice(0, -".cjs".length) + ext;
68
+ if (existsSync(sibling)) return sibling;
69
+ }
70
+ return required;
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ function withGraphChannel(base, enabled, start) {
76
+ let wire = null;
77
+ let available = false;
78
+ let reason = MISSING;
79
+ let root = process.cwd();
80
+ let log;
81
+ let graph = /* @__PURE__ */ new Map();
82
+ let stamp = 0;
83
+ let events = [];
84
+ const baseResolveId = base.resolveId;
85
+ const baseTransformIndexHtml = base.transformIndexHtml;
86
+ return {
87
+ ...base,
88
+ resolveId(id, importer) {
89
+ if (id === VIRTUAL) return RESOLVED;
90
+ return baseResolveId?.call(this, id, importer) ?? null;
91
+ },
92
+ async load(id) {
93
+ if (id !== RESOLVED) return null;
94
+ const from = join(root, "fluixi-devtools-agent.js");
95
+ const specs = ["@fluixi/reactive/signal", "@fluixi/reactive"];
96
+ const ids = await Promise.all(specs.map((spec) => this.resolve?.(spec, from, { skipSelf: true })));
97
+ const missing = specs.filter((_, i) => !ids[i]?.id);
98
+ const devtools = ownDevtools();
99
+ const plugins = ownPlugins();
100
+ if (missing.length || !devtools || !plugins) {
101
+ reason = missing.length ? `${missing.join(", ")} did not resolve from ${root}` : MISSING;
102
+ log?.(`[fluixi] reactive graph off — ${reason}`);
103
+ return "export {};";
104
+ }
105
+ return agentSource(`/@fs/${devtools}`, `/@fs/${plugins}`, ids[0].id, ids[1].id);
106
+ },
107
+ async configureServer(server) {
108
+ if (!enabled()) return;
109
+ root = server.config?.root ?? root;
110
+ log = server.config?.logger?.info.bind(server.config.logger);
111
+ wire = await import("@fluixi/devtools/wire").catch(() => null);
112
+ available = wire !== null;
113
+ if (wire) start();
114
+ if (wire) reason = WAITING;
115
+ else {
116
+ log?.(`[fluixi] reactive graph off — ${MISSING}`);
117
+ }
118
+ server.middlewares.use(ENDPOINT, (_req, res) => {
119
+ const snapshot = wire ? { ...wire.serializeGraph(graph, stamp || Date.now()), events } : { t: Date.now(), nodes: [] };
120
+ const body = JSON.stringify(reason ? { ...snapshot, reason } : snapshot);
121
+ res.setHeader("Content-Type", "application/json");
122
+ res.setHeader("Access-Control-Allow-Origin", "*");
123
+ res.setHeader("Cache-Control", "no-store");
124
+ res.end(body);
125
+ });
126
+ if (!wire) return;
127
+ server.ws.on(EVENT, (payload) => {
128
+ const message = payload;
129
+ if (!message?.snapshot || !wire) return;
130
+ const full = message.kind === "full";
131
+ graph = wire.applySnapshot(full ? /* @__PURE__ */ new Map() : graph, message.snapshot);
132
+ if (full) events = [];
133
+ const arriving = message.snapshot.events;
134
+ if (arriving?.length) events = [...events, ...arriving].slice(-HISTORY);
135
+ stamp = Date.now();
136
+ reason = null;
137
+ });
138
+ },
139
+ transformIndexHtml: {
140
+ order: "pre",
141
+ handler(html, ctx) {
142
+ const inherited = callInheritedHtml(baseTransformIndexHtml, html, ctx);
143
+ if (!enabled() || !available || !wire) return inherited;
144
+ return {
145
+ html: typeof inherited === "string" ? inherited : html,
146
+ tags: [
147
+ {
148
+ tag: "script",
149
+ // First in the head, so the entry cannot create a node before the agent runs.
150
+ injectTo: "head-prepend",
151
+ attrs: { type: "module", src: `/@id/${VIRTUAL}` }
152
+ }
153
+ ]
154
+ };
155
+ }
156
+ }
157
+ };
158
+ }
159
+ function callInheritedHtml(hook, html, ctx) {
160
+ if (typeof hook === "function") return hook(html, ctx);
161
+ const handler = hook?.handler;
162
+ return handler?.(html, ctx);
163
+ }
164
+
165
+ // src/index.ts
166
+ function fluixi(options = {}) {
167
+ const settings = options;
168
+ let serving = false;
169
+ const enabled = () => serving && settings.devtools !== false;
170
+ const base = createVitePlugin(settings);
171
+ const inherited = base.configResolved;
172
+ const start = () => {
173
+ settings.sourceLocations = true;
174
+ settings.sourceLocationsExternal = typeof settings.devtools === "object" && settings.devtools.external === true;
175
+ };
176
+ return withGraphChannel(
177
+ {
178
+ ...base,
179
+ configResolved(config) {
180
+ inherited?.(config);
181
+ serving = config?.command === "serve";
182
+ settings.sourceRoot = config.root;
183
+ }
184
+ },
185
+ enabled,
186
+ start
187
+ );
188
+ }
189
+ var index_default = fluixi;
190
+ export {
191
+ createVitePlugin,
192
+ index_default as default,
193
+ fluixi
194
+ };