@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.
@@ -1,10 +1,58 @@
1
- "use strict";var T=Object.create;var f=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var i in t)f(e,i,{get:t[i],enumerable:!0})},S=(e,t,i,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of D(t))!G.call(e,l)&&l!==i&&f(e,l,{get:()=>t[l],enumerable:!(n=P(t,l))||n.enumerable});return e};var A=(e,t,i)=>(i=e!=null?T(C(e)):{},S(t||!e||!e.__esModule?f(i,"default",{value:e,enumerable:!0}):i,e)),J=e=>S(f({},"__esModule",{value:!0}),e);var Y={};j(Y,{withGraphChannel:()=>K});module.exports=J(Y);var w=require("node:module"),N=require("node:path"),$={},v="virtual:fluixi/devtools-agent",I=`\0${v}`,M="/__fluixi/graph",R="fluixi:graph",m="the plugin could not load @fluixi/devtools from its own dependencies",V="no page has reported yet — open the application in a browser",_=100,W=500,q=(e,t,i,n)=>`
2
- import { installDevtoolsHook, observeGraph } from ${JSON.stringify(e)};
3
- import ${JSON.stringify(t)};
4
- import { observeReactiveNodes } from ${JSON.stringify(i)};
5
- import { VERSION } from ${JSON.stringify(n)};
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
6
29
 
7
- // The runtime this module imports is the application's own — same module graph, same nodes.
30
+ // src/graph-channel.ts
31
+ var graph_channel_exports = {};
32
+ __export(graph_channel_exports, {
33
+ withGraphChannel: () => withGraphChannel
34
+ });
35
+ module.exports = __toCommonJS(graph_channel_exports);
36
+ var import_node_module = require("node:module");
37
+ var import_node_fs = require("node:fs");
38
+ var import_node_path = require("node:path");
39
+ var import_node_url = require("node:url");
40
+ var import_meta = {};
41
+ var VIRTUAL = "virtual:fluixi/devtools-agent";
42
+ var RESOLVED = `\0${VIRTUAL}`;
43
+ var ENDPOINT = "/__fluixi/graph";
44
+ var EVENT = "fluixi:graph";
45
+ var MISSING = "the plugin could not load @fluixi/devtools from its own dependencies";
46
+ var WAITING = "no page has reported yet — open the application in a browser";
47
+ var INTERVAL = 100;
48
+ var HISTORY = 500;
49
+ var agentSource = (devtools, plugins, signal, reactive) => `
50
+ import { installDevtoolsHook, observeGraph } from ${JSON.stringify(devtools)};
51
+ import ${JSON.stringify(plugins)};
52
+ import { observeReactiveNodes } from ${JSON.stringify(signal)};
53
+ import { VERSION } from ${JSON.stringify(reactive)};
54
+
55
+ // The runtime this module imports is the application's own, same module graph, same nodes.
8
56
  // Nothing waits for the runtime to offer itself; that path is for a tool loaded from outside.
9
57
  //
10
58
  // \`watch\` is this copy of devtools, handed over with the runtime. A browser extension
@@ -13,7 +61,7 @@ import { VERSION } from ${JSON.stringify(n)};
13
61
  const hook = installDevtoolsHook();
14
62
  hook.inject({ observeReactiveNodes, version: VERSION, watch: observeGraph });
15
63
 
16
- const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(R)}, { kind, snapshot });
64
+ const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(EVENT)}, { kind, snapshot });
17
65
 
18
66
  const first = hook.snapshot();
19
67
  // Kept and handed back, so a browser panel polling the same hook cannot consume what this
@@ -26,7 +74,120 @@ const timer = setInterval(() => {
26
74
  cursor = delta.cursor;
27
75
  // Events count on their own: an effect that ran without changing a value moves no node.
28
76
  if (delta.nodes.length || delta.removed?.length || delta.events?.length) send('delta', delta);
29
- }, ${_});
77
+ }, ${INTERVAL});
30
78
 
31
79
  import.meta.hot?.dispose(() => clearInterval(timer));
32
- `;function L(){try{return(0,w.createRequire)($.url).resolve("@fluixi/devtools")}catch{return null}}function z(){try{return(0,w.createRequire)($.url).resolve("@fluixi/devtools/plugins")}catch{return null}}function K(e,t,i){let n=null,l=!1,u=m,c=process.cwd(),h,g=new Map,y=0,p=[],O=e.resolveId,H=e.transformIndexHtml;return{...e,resolveId(s,a){return s===v?I:O?.call(this,s,a)??null},async load(s){if(s!==I)return null;let a=(0,N.join)(c,"fluixi-devtools-agent.js"),o=["@fluixi/reactive/signal","@fluixi/reactive"],r=await Promise.all(o.map(b=>this.resolve?.(b,a,{skipSelf:!0}))),d=o.filter((b,E)=>!r[E]?.id),k=L(),x=z();return d.length||!k||!x?(u=d.length?`${d.join(", ")} did not resolve from ${c}`:m,h?.(`[fluixi] reactive graph off — ${u}`),"export {};"):q(`/@fs/${k}`,`/@fs/${x}`,r[0].id,r[1].id)},async configureServer(s){t()&&(c=s.config?.root??c,h=s.config?.logger?.info.bind(s.config.logger),n=await import("@fluixi/devtools/wire").catch(()=>null),l=n!==null,n&&i(),n?u=V:h?.(`[fluixi] reactive graph off — ${m}`),s.middlewares.use(M,(a,o)=>{let r=n?{...n.serializeGraph(g,y||Date.now()),events:p}:{t:Date.now(),nodes:[]},d=JSON.stringify(u?{...r,reason:u}:r);o.setHeader("Content-Type","application/json"),o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Cache-Control","no-store"),o.end(d)}),n&&s.ws.on(R,a=>{let o=a;if(!o?.snapshot||!n)return;let r=o.kind==="full";g=n.applySnapshot(r?new Map:g,o.snapshot),r&&(p=[]);let d=o.snapshot.events;d?.length&&(p=[...p,...d].slice(-W)),y=Date.now(),u=null}))},transformIndexHtml:{order:"pre",handler(s,a){let o=U(H,s,a);return!t()||!l||!n?o:{html:typeof o=="string"?o:s,tags:[{tag:"script",injectTo:"head-prepend",attrs:{type:"module",src:`/@id/${v}`}}]}}}}}function U(e,t,i){if(typeof e=="function")return e(t,i);let n=e?.handler;return n?.(t,i)}
80
+ `;
81
+ function ownDevtools() {
82
+ return resolveForBrowser("@fluixi/devtools");
83
+ }
84
+ function ownPlugins() {
85
+ return resolveForBrowser("@fluixi/devtools/plugins");
86
+ }
87
+ function resolveForBrowser(spec) {
88
+ try {
89
+ const resolved = import_meta.resolve?.(spec);
90
+ if (resolved) return (0, import_node_url.fileURLToPath)(resolved);
91
+ } catch {
92
+ }
93
+ try {
94
+ const required = (0, import_node_module.createRequire)(import_meta.url).resolve(spec);
95
+ if (!required.endsWith(".cjs")) return required;
96
+ for (const ext of [".mjs", ".js"]) {
97
+ const sibling = required.slice(0, -".cjs".length) + ext;
98
+ if ((0, import_node_fs.existsSync)(sibling)) return sibling;
99
+ }
100
+ return required;
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ function withGraphChannel(base, enabled, start) {
106
+ let wire = null;
107
+ let available = false;
108
+ let reason = MISSING;
109
+ let root = process.cwd();
110
+ let log;
111
+ let graph = /* @__PURE__ */ new Map();
112
+ let stamp = 0;
113
+ let events = [];
114
+ const baseResolveId = base.resolveId;
115
+ const baseTransformIndexHtml = base.transformIndexHtml;
116
+ return {
117
+ ...base,
118
+ resolveId(id, importer) {
119
+ if (id === VIRTUAL) return RESOLVED;
120
+ return baseResolveId?.call(this, id, importer) ?? null;
121
+ },
122
+ async load(id) {
123
+ if (id !== RESOLVED) return null;
124
+ const from = (0, import_node_path.join)(root, "fluixi-devtools-agent.js");
125
+ const specs = ["@fluixi/reactive/signal", "@fluixi/reactive"];
126
+ const ids = await Promise.all(specs.map((spec) => this.resolve?.(spec, from, { skipSelf: true })));
127
+ const missing = specs.filter((_, i) => !ids[i]?.id);
128
+ const devtools = ownDevtools();
129
+ const plugins = ownPlugins();
130
+ if (missing.length || !devtools || !plugins) {
131
+ reason = missing.length ? `${missing.join(", ")} did not resolve from ${root}` : MISSING;
132
+ log?.(`[fluixi] reactive graph off — ${reason}`);
133
+ return "export {};";
134
+ }
135
+ return agentSource(`/@fs/${devtools}`, `/@fs/${plugins}`, ids[0].id, ids[1].id);
136
+ },
137
+ async configureServer(server) {
138
+ if (!enabled()) return;
139
+ root = server.config?.root ?? root;
140
+ log = server.config?.logger?.info.bind(server.config.logger);
141
+ wire = await import("@fluixi/devtools/wire").catch(() => null);
142
+ available = wire !== null;
143
+ if (wire) start();
144
+ if (wire) reason = WAITING;
145
+ else {
146
+ log?.(`[fluixi] reactive graph off — ${MISSING}`);
147
+ }
148
+ server.middlewares.use(ENDPOINT, (_req, res) => {
149
+ const snapshot = wire ? { ...wire.serializeGraph(graph, stamp || Date.now()), events } : { t: Date.now(), nodes: [] };
150
+ const body = JSON.stringify(reason ? { ...snapshot, reason } : snapshot);
151
+ res.setHeader("Content-Type", "application/json");
152
+ res.setHeader("Access-Control-Allow-Origin", "*");
153
+ res.setHeader("Cache-Control", "no-store");
154
+ res.end(body);
155
+ });
156
+ if (!wire) return;
157
+ server.ws.on(EVENT, (payload) => {
158
+ const message = payload;
159
+ if (!message?.snapshot || !wire) return;
160
+ const full = message.kind === "full";
161
+ graph = wire.applySnapshot(full ? /* @__PURE__ */ new Map() : graph, message.snapshot);
162
+ if (full) events = [];
163
+ const arriving = message.snapshot.events;
164
+ if (arriving?.length) events = [...events, ...arriving].slice(-HISTORY);
165
+ stamp = Date.now();
166
+ reason = null;
167
+ });
168
+ },
169
+ transformIndexHtml: {
170
+ order: "pre",
171
+ handler(html, ctx) {
172
+ const inherited = callInheritedHtml(baseTransformIndexHtml, html, ctx);
173
+ if (!enabled() || !available || !wire) return inherited;
174
+ return {
175
+ html: typeof inherited === "string" ? inherited : html,
176
+ tags: [
177
+ {
178
+ tag: "script",
179
+ // First in the head, so the entry cannot create a node before the agent runs.
180
+ injectTo: "head-prepend",
181
+ attrs: { type: "module", src: `/@id/${VIRTUAL}` }
182
+ }
183
+ ]
184
+ };
185
+ }
186
+ }
187
+ };
188
+ }
189
+ function callInheritedHtml(hook, html, ctx) {
190
+ if (typeof hook === "function") return hook(html, ctx);
191
+ const handler = hook?.handler;
192
+ return handler?.(html, ctx);
193
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"graph-channel.d.ts","sourceRoot":"","sources":["../src/graph-channel.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AA4EnC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,MAAM,CAyHhG"}
1
+ {"version":3,"file":"graph-channel.d.ts","sourceRoot":"","sources":["../src/graph-channel.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAqGnC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,MAAM,CAyHhG"}
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // A dev-only agent module goes into the page ahead of the entry, so no node is created
4
4
  // before something is watching. It pushes the graph over the channel Vite already keeps open
5
- // for HMR, and the dev server holds the latest state and answers a plain GET so an editor
5
+ // for HMR, and the dev server holds the latest state and answers a plain GET, so an editor
6
6
  // extension, a panel, or curl all read the same thing without speaking HMR.
7
7
  //
8
8
  // GET /__fluixi/graph → { t, nodes: [...] }
@@ -12,7 +12,9 @@
12
12
  // the framework itself is resolved from the project, because watching a second copy of the
13
13
  // runtime would watch a graph nobody is using.
14
14
  import { createRequire } from 'node:module';
15
+ import { existsSync } from 'node:fs';
15
16
  import { join } from 'node:path';
17
+ import { fileURLToPath } from 'node:url';
16
18
  const VIRTUAL = 'virtual:fluixi/devtools-agent';
17
19
  const RESOLVED = `\0${VIRTUAL}`;
18
20
  const ENDPOINT = '/__fluixi/graph';
@@ -31,7 +33,7 @@ import ${JSON.stringify(plugins)};
31
33
  import { observeReactiveNodes } from ${JSON.stringify(signal)};
32
34
  import { VERSION } from ${JSON.stringify(reactive)};
33
35
 
34
- // The runtime this module imports is the application's own same module graph, same nodes.
36
+ // The runtime this module imports is the application's own, same module graph, same nodes.
35
37
  // Nothing waits for the runtime to offer itself; that path is for a tool loaded from outside.
36
38
  //
37
39
  // \`watch\` is this copy of devtools, handed over with the runtime. A browser extension
@@ -62,20 +64,46 @@ import.meta.hot?.dispose(() => clearInterval(timer));
62
64
  *
63
65
  * Asking the application to install it as well made the graph depend on a devDependency
64
66
  * nobody knew to add, and in a workspace it resolved for one project and not the one beside
65
- * it which reads as the feature being broken rather than absent.
67
+ * it: which reads as the feature being broken rather than absent.
66
68
  */
67
69
  function ownDevtools() {
70
+ return resolveForBrowser('@fluixi/devtools');
71
+ }
72
+ /** The built-in plugins, beside the bundle they extend. Collecting happens in the agent. */
73
+ function ownPlugins() {
74
+ return resolveForBrowser('@fluixi/devtools/plugins');
75
+ }
76
+ /**
77
+ * A package's ESM entry, by path.
78
+ *
79
+ * The agent below is served to a browser as an ES module and imports these by `/@fs/`
80
+ * path, so the file has to be the one with the named exports. `createRequire().resolve`
81
+ * answers with the `require` condition instead: the CJS build, and a `.cjs` file
82
+ * offers nothing to import, which surfaces as "does not provide an export named
83
+ * 'installDevtoolsHook'". It only started happening when devtools gained a CJS build;
84
+ * before that there was one file and either resolver found it.
85
+ */
86
+ function resolveForBrowser(spec) {
87
+ // Honours the `import` condition, which is the one that matches how this is loaded.
68
88
  try {
69
- return createRequire(import.meta.url).resolve('@fluixi/devtools');
89
+ const resolved = import.meta.resolve?.(spec);
90
+ if (resolved)
91
+ return fileURLToPath(resolved);
70
92
  }
71
93
  catch {
72
- return null;
94
+ // Fall through to the require-based resolution below.
73
95
  }
74
- }
75
- /** The built-in plugins, beside the bundle they extend. Collecting happens in the agent. */
76
- function ownPlugins() {
77
96
  try {
78
- return createRequire(import.meta.url).resolve('@fluixi/devtools/plugins');
97
+ const required = createRequire(import.meta.url).resolve(spec);
98
+ if (!required.endsWith('.cjs'))
99
+ return required;
100
+ // Landed on the CJS build. Prefer its ESM sibling when the package ships one.
101
+ for (const ext of ['.mjs', '.js']) {
102
+ const sibling = required.slice(0, -'.cjs'.length) + ext;
103
+ if (existsSync(sibling))
104
+ return sibling;
105
+ }
106
+ return required;
79
107
  }
80
108
  catch {
81
109
  return null;
@@ -148,7 +176,7 @@ export function withGraphChannel(base, enabled, start) {
148
176
  log?.(`[fluixi] reactive graph off — ${MISSING}`);
149
177
  }
150
178
  // The endpoint answers either way. A tool asking for the graph of a project that has
151
- // not turned it on deserves to be told which of the two it is, and 404 says neither
179
+ // not turned it on deserves to be told which of the two it is, and 404 says neither ,
152
180
  // it reads the same as a dev server that is not a fluixi project at all.
153
181
  server.middlewares.use(ENDPOINT, (_req, res) => {
154
182
  const snapshot = wire
@@ -1,10 +1,23 @@
1
- import{createRequire as b}from"node:module";import{join as $}from"node:path";var g="virtual:fluixi/devtools-agent",x=`\0${g}`,O="/__fluixi/graph",S="fluixi:graph",h="the plugin could not load @fluixi/devtools from its own dependencies",H="no page has reported yet — open the application in a browser",E=100,T=500,P=(o,l,a,t)=>`
2
- import { installDevtoolsHook, observeGraph } from ${JSON.stringify(o)};
3
- import ${JSON.stringify(l)};
4
- import { observeReactiveNodes } from ${JSON.stringify(a)};
5
- import { VERSION } from ${JSON.stringify(t)};
1
+ // src/graph-channel.ts
2
+ import { createRequire } from "node:module";
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ var VIRTUAL = "virtual:fluixi/devtools-agent";
7
+ var RESOLVED = `\0${VIRTUAL}`;
8
+ var ENDPOINT = "/__fluixi/graph";
9
+ var EVENT = "fluixi:graph";
10
+ var MISSING = "the plugin could not load @fluixi/devtools from its own dependencies";
11
+ var WAITING = "no page has reported yet — open the application in a browser";
12
+ var INTERVAL = 100;
13
+ var HISTORY = 500;
14
+ var agentSource = (devtools, plugins, signal, reactive) => `
15
+ import { installDevtoolsHook, observeGraph } from ${JSON.stringify(devtools)};
16
+ import ${JSON.stringify(plugins)};
17
+ import { observeReactiveNodes } from ${JSON.stringify(signal)};
18
+ import { VERSION } from ${JSON.stringify(reactive)};
6
19
 
7
- // The runtime this module imports is the application's own same module graph, same nodes.
20
+ // The runtime this module imports is the application's own, same module graph, same nodes.
8
21
  // Nothing waits for the runtime to offer itself; that path is for a tool loaded from outside.
9
22
  //
10
23
  // \`watch\` is this copy of devtools, handed over with the runtime. A browser extension
@@ -13,7 +26,7 @@ import { VERSION } from ${JSON.stringify(t)};
13
26
  const hook = installDevtoolsHook();
14
27
  hook.inject({ observeReactiveNodes, version: VERSION, watch: observeGraph });
15
28
 
16
- const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(S)}, { kind, snapshot });
29
+ const send = (kind, snapshot) => import.meta.hot?.send(${JSON.stringify(EVENT)}, { kind, snapshot });
17
30
 
18
31
  const first = hook.snapshot();
19
32
  // Kept and handed back, so a browser panel polling the same hook cannot consume what this
@@ -26,7 +39,123 @@ const timer = setInterval(() => {
26
39
  cursor = delta.cursor;
27
40
  // Events count on their own: an effect that ran without changing a value moves no node.
28
41
  if (delta.nodes.length || delta.removed?.length || delta.events?.length) send('delta', delta);
29
- }, ${E});
42
+ }, ${INTERVAL});
30
43
 
31
44
  import.meta.hot?.dispose(() => clearInterval(timer));
32
- `;function D(){try{return b(import.meta.url).resolve("@fluixi/devtools")}catch{return null}}function C(){try{return b(import.meta.url).resolve("@fluixi/devtools/plugins")}catch{return null}}function J(o,l,a){let t=null,m=!1,d=h,u=process.cwd(),p,f=new Map,v=0,c=[],I=o.resolveId,N=o.transformIndexHtml;return{...o,resolveId(n,s){return n===g?x:I?.call(this,n,s)??null},async load(n){if(n!==x)return null;let s=$(u,"fluixi-devtools-agent.js"),e=["@fluixi/reactive/signal","@fluixi/reactive"],i=await Promise.all(e.map(k=>this.resolve?.(k,s,{skipSelf:!0}))),r=e.filter((k,R)=>!i[R]?.id),w=D(),y=C();return r.length||!w||!y?(d=r.length?`${r.join(", ")} did not resolve from ${u}`:h,p?.(`[fluixi] reactive graph off — ${d}`),"export {};"):P(`/@fs/${w}`,`/@fs/${y}`,i[0].id,i[1].id)},async configureServer(n){l()&&(u=n.config?.root??u,p=n.config?.logger?.info.bind(n.config.logger),t=await import("@fluixi/devtools/wire").catch(()=>null),m=t!==null,t&&a(),t?d=H:p?.(`[fluixi] reactive graph off — ${h}`),n.middlewares.use(O,(s,e)=>{let i=t?{...t.serializeGraph(f,v||Date.now()),events:c}:{t:Date.now(),nodes:[]},r=JSON.stringify(d?{...i,reason:d}:i);e.setHeader("Content-Type","application/json"),e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Cache-Control","no-store"),e.end(r)}),t&&n.ws.on(S,s=>{let e=s;if(!e?.snapshot||!t)return;let i=e.kind==="full";f=t.applySnapshot(i?new Map:f,e.snapshot),i&&(c=[]);let r=e.snapshot.events;r?.length&&(c=[...c,...r].slice(-T)),v=Date.now(),d=null}))},transformIndexHtml:{order:"pre",handler(n,s){let e=G(N,n,s);return!l()||!m||!t?e:{html:typeof e=="string"?e:n,tags:[{tag:"script",injectTo:"head-prepend",attrs:{type:"module",src:`/@id/${g}`}}]}}}}}function G(o,l,a){if(typeof o=="function")return o(l,a);let t=o?.handler;return t?.(l,a)}export{J as withGraphChannel};
45
+ `;
46
+ function ownDevtools() {
47
+ return resolveForBrowser("@fluixi/devtools");
48
+ }
49
+ function ownPlugins() {
50
+ return resolveForBrowser("@fluixi/devtools/plugins");
51
+ }
52
+ function resolveForBrowser(spec) {
53
+ try {
54
+ const resolved = import.meta.resolve?.(spec);
55
+ if (resolved) return fileURLToPath(resolved);
56
+ } catch {
57
+ }
58
+ try {
59
+ const required = createRequire(import.meta.url).resolve(spec);
60
+ if (!required.endsWith(".cjs")) return required;
61
+ for (const ext of [".mjs", ".js"]) {
62
+ const sibling = required.slice(0, -".cjs".length) + ext;
63
+ if (existsSync(sibling)) return sibling;
64
+ }
65
+ return required;
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ function withGraphChannel(base, enabled, start) {
71
+ let wire = null;
72
+ let available = false;
73
+ let reason = MISSING;
74
+ let root = process.cwd();
75
+ let log;
76
+ let graph = /* @__PURE__ */ new Map();
77
+ let stamp = 0;
78
+ let events = [];
79
+ const baseResolveId = base.resolveId;
80
+ const baseTransformIndexHtml = base.transformIndexHtml;
81
+ return {
82
+ ...base,
83
+ resolveId(id, importer) {
84
+ if (id === VIRTUAL) return RESOLVED;
85
+ return baseResolveId?.call(this, id, importer) ?? null;
86
+ },
87
+ async load(id) {
88
+ if (id !== RESOLVED) return null;
89
+ const from = join(root, "fluixi-devtools-agent.js");
90
+ const specs = ["@fluixi/reactive/signal", "@fluixi/reactive"];
91
+ const ids = await Promise.all(specs.map((spec) => this.resolve?.(spec, from, { skipSelf: true })));
92
+ const missing = specs.filter((_, i) => !ids[i]?.id);
93
+ const devtools = ownDevtools();
94
+ const plugins = ownPlugins();
95
+ if (missing.length || !devtools || !plugins) {
96
+ reason = missing.length ? `${missing.join(", ")} did not resolve from ${root}` : MISSING;
97
+ log?.(`[fluixi] reactive graph off — ${reason}`);
98
+ return "export {};";
99
+ }
100
+ return agentSource(`/@fs/${devtools}`, `/@fs/${plugins}`, ids[0].id, ids[1].id);
101
+ },
102
+ async configureServer(server) {
103
+ if (!enabled()) return;
104
+ root = server.config?.root ?? root;
105
+ log = server.config?.logger?.info.bind(server.config.logger);
106
+ wire = await import("@fluixi/devtools/wire").catch(() => null);
107
+ available = wire !== null;
108
+ if (wire) start();
109
+ if (wire) reason = WAITING;
110
+ else {
111
+ log?.(`[fluixi] reactive graph off — ${MISSING}`);
112
+ }
113
+ server.middlewares.use(ENDPOINT, (_req, res) => {
114
+ const snapshot = wire ? { ...wire.serializeGraph(graph, stamp || Date.now()), events } : { t: Date.now(), nodes: [] };
115
+ const body = JSON.stringify(reason ? { ...snapshot, reason } : snapshot);
116
+ res.setHeader("Content-Type", "application/json");
117
+ res.setHeader("Access-Control-Allow-Origin", "*");
118
+ res.setHeader("Cache-Control", "no-store");
119
+ res.end(body);
120
+ });
121
+ if (!wire) return;
122
+ server.ws.on(EVENT, (payload) => {
123
+ const message = payload;
124
+ if (!message?.snapshot || !wire) return;
125
+ const full = message.kind === "full";
126
+ graph = wire.applySnapshot(full ? /* @__PURE__ */ new Map() : graph, message.snapshot);
127
+ if (full) events = [];
128
+ const arriving = message.snapshot.events;
129
+ if (arriving?.length) events = [...events, ...arriving].slice(-HISTORY);
130
+ stamp = Date.now();
131
+ reason = null;
132
+ });
133
+ },
134
+ transformIndexHtml: {
135
+ order: "pre",
136
+ handler(html, ctx) {
137
+ const inherited = callInheritedHtml(baseTransformIndexHtml, html, ctx);
138
+ if (!enabled() || !available || !wire) return inherited;
139
+ return {
140
+ html: typeof inherited === "string" ? inherited : html,
141
+ tags: [
142
+ {
143
+ tag: "script",
144
+ // First in the head, so the entry cannot create a node before the agent runs.
145
+ injectTo: "head-prepend",
146
+ attrs: { type: "module", src: `/@id/${VIRTUAL}` }
147
+ }
148
+ ]
149
+ };
150
+ }
151
+ }
152
+ };
153
+ }
154
+ function callInheritedHtml(hook, html, ctx) {
155
+ if (typeof hook === "function") return hook(html, ctx);
156
+ const handler = hook?.handler;
157
+ return handler?.(html, ctx);
158
+ }
159
+ export {
160
+ withGraphChannel
161
+ };