@fougere/vite 0.13.1-alpha.0 → 0.14.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -10,6 +10,13 @@ export interface FougereViteOptions {
10
10
  keepClassNames?: boolean;
11
11
  /** Extra identifiers to reserve, for entities that do not live under `fronds/`. */
12
12
  reserved?: string[];
13
+ /**
14
+ * Where the fronds are, from the app — `'../..'` in a workspace, whose `fronds/` sit at its
15
+ * root. The same key `@fougere/nuxt` reads.
16
+ */
17
+ root?: string;
18
+ /** Set false when the host serves the call envelope itself. */
19
+ serve?: boolean;
13
20
  }
14
21
  export declare function fougere(options?: FougereViteOptions): Plugin;
15
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,eAAe,CAAC;AAEtE,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,GAAE,WAAiC,GAAG,MAAM,EAAE,CAgBpG;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,iDAAiD;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAiDD,wBAAgB,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAyDhE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,eAAe,CAAC;AAEtE,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,GAAE,WAAiC,GAAG,MAAM,EAAE,CAgBpG;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,iDAAiD;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA4FD,wBAAgB,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAgEhE"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readdirSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
- import { join, dirname } from 'node:path';
2
+ import { join, dirname, resolve } from 'node:path';
3
3
  import { RUNTIME_PACKAGES } from '@fougere/compiler';
4
4
  import { DEFAULT_CONVENTIONS } from '@fougere/core';
5
5
  /** The entity names a build must not rename, read off the filesystem. */
@@ -23,6 +23,47 @@ export function entityNamesIn(root, conventions = DEFAULT_CONVENTIONS) {
23
23
  return [...names];
24
24
  }
25
25
  export { RUNTIME_PACKAGES } from '@fougere/compiler';
26
+ /** What the browser primitives call, and the web handler that answers each. */
27
+ const DOORS = { '/_fougere/call': 'call', '/_fougere/session': 'session' };
28
+ /**
29
+ * The call envelope, answered by the dev server itself: a Vite app has no server of its own, and
30
+ * the browser calls its own origin. The app boots at the first call, from `fougere.config.ts`, so
31
+ * `fronds:` decides whether a frond answers here or a process away — the same line as under Nuxt.
32
+ */
33
+ function serveDoors() {
34
+ return (req, res, next) => {
35
+ const path = (req.url ?? '').split('?')[0];
36
+ const door = DOORS[path];
37
+ if (!door)
38
+ return next();
39
+ void (async () => {
40
+ try {
41
+ const web = await import('@fougere/app/web');
42
+ const response = await web[door](await requestOf(req));
43
+ res.statusCode = response.status;
44
+ response.headers.forEach((value, key) => res.setHeader(key, value));
45
+ res.end(Buffer.from(await response.arrayBuffer()));
46
+ }
47
+ catch (error) {
48
+ res.statusCode = 500;
49
+ res.setHeader('content-type', 'application/json');
50
+ res.end(JSON.stringify({ code: 'INTERNAL_ERROR', message: error.message }));
51
+ }
52
+ })();
53
+ };
54
+ }
55
+ async function requestOf(req) {
56
+ const chunks = [];
57
+ for await (const chunk of req)
58
+ chunks.push(chunk);
59
+ const headers = new Headers(Object.entries(req.headers)
60
+ .filter((entry) => typeof entry[1] === 'string'));
61
+ return new Request(`http://${req.headers.host ?? 'localhost'}${req.url}`, {
62
+ method: req.method,
63
+ headers,
64
+ ...(chunks.length ? { body: Buffer.concat(chunks) } : {}),
65
+ });
66
+ }
26
67
  /**
27
68
  * Where the facade types land — the same place `fougere build` puts them, so a host that runs the
28
69
  * command and one that only starts a dev server read one file and not two.
@@ -41,7 +82,7 @@ const NAMES = '.fougere/names.generated.d.ts';
41
82
  * A scan that fails is not a failure of the dev server: the types fall back to every code there
42
83
  * is, which is what a client had before this existed.
43
84
  */
44
- async function writeDoors(root) {
85
+ async function writeDoors(app, root) {
45
86
  try {
46
87
  const { scanProject, emitFacade, emitNames, frondAliases } = await import('@fougere/compiler');
47
88
  const { setModuleLoader } = await import('@fougere/core/node');
@@ -57,25 +98,30 @@ async function writeDoors(root) {
57
98
  });
58
99
  setModuleLoader((filePath) => jiti.import(filePath));
59
100
  const { loadConfig } = await import('@fougere/core/node');
60
- const out = join(root, FACADE);
101
+ const out = join(app, FACADE);
61
102
  mkdirSync(dirname(out), { recursive: true });
62
103
  const scan = await scanProject(root);
63
104
  writeFileSync(out, emitFacade(scan, { outFile: out }));
64
105
  // What a config may NAME, from the same scan: the sources are the config's own keys, which
65
106
  // no scan can find, and a project without one states none.
66
107
  const config = await loadConfig(root).catch(() => ({}));
67
- writeFileSync(join(root, NAMES), emitNames(scan, { sources: Object.keys(config.sources ?? {}) }));
108
+ writeFileSync(join(app, NAMES), emitNames(scan, { sources: Object.keys(config.sources ?? {}) }));
68
109
  }
69
110
  catch { /* a host with no fronds, or a scan that could not run */ }
70
111
  }
71
112
  export function fougere(options = {}) {
72
113
  const external = [...new Set([...RUNTIME_PACKAGES, ...(options.external ?? [])])];
73
- // Where `config` said the project is, so `buildStart` writes beside the alias it set.
74
- let root = process.cwd();
114
+ // Where `config` said the app is, so `buildStart` writes beside the alias it set — and where
115
+ // its fronds are, which a workspace puts two levels up.
116
+ let app = process.cwd();
117
+ const frondsOf = (from) => resolve(from, options.root ?? '.');
75
118
  return {
76
119
  name: 'fougere',
77
120
  configureServer(server) {
78
- void writeDoors(server.config?.root ?? root);
121
+ const root = server.config?.root ?? app;
122
+ void writeDoors(root, frondsOf(root));
123
+ if (options.serve !== false)
124
+ server.middlewares.use(serveDoors());
79
125
  },
80
126
  /**
81
127
  * AWAITED, and that is the whole point: the bundler resolves `@fronds/facade` right after
@@ -83,7 +129,7 @@ export function fougere(options = {}) {
83
129
  * .fougere/facade.generated.ts`, measured on `demos/react-router-blog`.
84
130
  */
85
131
  async buildStart() {
86
- await writeDoors(root);
132
+ await writeDoors(app, frondsOf(app));
87
133
  },
88
134
  /** `order. */
89
135
  config: {
@@ -94,18 +140,21 @@ export function fougere(options = {}) {
94
140
  // A page IMPORTS its facade, so the alias sits beside the file that declares them: a
95
141
  // project that never generated it fails to resolve rather than losing its types in
96
142
  // silence.
97
- root = config.root ?? root;
143
+ app = resolve(config.root ?? app);
144
+ // Read by the boot, which runs in this process and has no other way to learn it — the
145
+ // variable `@fougere/nuxt` sets for the same reason.
146
+ process.env.FOUGERE_ROOT = frondsOf(app);
98
147
  config.resolve ??= {};
99
148
  // Vite admits BOTH shapes and a host picks one: SvelteKit states an array of
100
149
  // `{ find, replacement }`, and spreading an object over it made rolldown refuse the
101
150
  // whole plugin — `StringExpected … on BindingViteAliasPluginAlias.replacement`.
102
- const facade = join(root, FACADE);
151
+ const facade = join(app, FACADE);
103
152
  config.resolve.alias = Array.isArray(config.resolve.alias)
104
153
  ? [...config.resolve.alias, { find: '@fronds/facade', replacement: facade }]
105
154
  : { ...config.resolve.alias, '@fronds/facade': facade };
106
155
  if (options.keepClassNames === false)
107
156
  return;
108
- const reserved = [...(options.reserved ?? []), ...entityNamesIn(config.root ?? process.cwd())];
157
+ const reserved = [...(options.reserved ?? []), ...entityNamesIn(frondsOf(app))];
109
158
  if (reserved.length === 0)
110
159
  return;
111
160
  config.build ??= {};
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAoB,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEtE,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,WAAW,GAAgB,mBAAmB;IACxF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QACpC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,KAAK;gBAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAWrD;;;GAGG;AACH,MAAM,MAAM,GAAG,8BAA8B,CAAC;AAC9C,MAAM,KAAK,GAAG,+BAA+B,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC/F,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC/D,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QAE5C,6FAA6F;QAC7F,uFAAuF;QACvF,wFAAwF;QACxF,2EAA2E;QAC3E,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE;YACvC,cAAc,EAAE,IAAI;YACpB,KAAK,EAAE,MAAM,YAAY,CAAC,IAAI,EAAE,kBAAkB,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,eAAe,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAqC,CAAC,CAAC;QACjG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/B,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;QACrC,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACvD,2FAA2F;QAC3F,2DAA2D;QAC3D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAkB,CAAC,CAAC;QACzE,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpG,CAAC;IAAC,MAAM,CAAC,CAAC,yDAAyD,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAO,GAAuB,EAAE;IACtD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,gBAAgB,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,sFAAsF;IACtF,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAEzB,OAAO;QACL,IAAI,EAAE,SAAS;QACf,eAAe,CAAC,MAAsC;YACpD,KAAK,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;QAC/C,CAAC;QACD;;;;WAIG;QACH,KAAK,CAAC,UAAU;YACd,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,cAAc;QACd,MAAM,EAAE;YACN,KAAK,EAAE,MAAM;YACb,OAAO,CAAC,MAA2B;gBACjC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,MAAM,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAElF,qFAAqF;gBACrF,mFAAmF;gBACnF,WAAW;gBACX,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC;gBAC3B,MAAM,CAAC,OAAO,KAAK,EAAE,CAAC;gBACtB,6EAA6E;gBAC7E,oFAAoF;gBACpF,gFAAgF;gBAChF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAClC,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;oBACxD,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;oBAC5E,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;gBAE1D,IAAI,OAAO,CAAC,cAAc,KAAK,KAAK;oBAAE,OAAO;gBAE7C,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC/F,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBAElC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;gBACpB,iFAAiF;gBACjF,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;gBAC/B,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG;oBAC3B,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa;oBAC7B,eAAe,EAAE,IAAI;oBACrB,MAAM,EAAE;wBACN,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM;wBACrC,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;qBAC/F;iBACF,CAAC;YACJ,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fougere/vite",
3
- "version": "0.13.1-alpha.0",
3
+ "version": "0.14.0-alpha.0",
4
4
  "description": "The Vite plugin: what any Vite-built host must know to run a Fougere app.",
5
5
  "keywords": [
6
6
  "fougere",
@@ -30,8 +30,9 @@
30
30
  "src"
31
31
  ],
32
32
  "dependencies": {
33
- "@fougere/compiler": "0.13.1-alpha.0",
34
- "@fougere/core": "0.13.1-alpha.0",
33
+ "@fougere/app": "0.14.0-alpha.0",
34
+ "@fougere/compiler": "0.14.0-alpha.0",
35
+ "@fougere/core": "0.14.0-alpha.0",
35
36
  "jiti": "^2.7.0",
36
37
  "terser": "^5.44.0"
37
38
  },
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /** `@fougere/vite` — the one place a Vite-built host is told what a Fougere app needs. */
2
2
  import type { FougereConfig } from '@fougere/core';
3
3
  import { readdirSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
4
- import { join, dirname } from 'node:path';
4
+ import type { IncomingMessage, ServerResponse } from 'node:http';
5
+ import { join, dirname, resolve } from 'node:path';
5
6
  import type { Plugin } from 'vite';
6
7
  import { RUNTIME_PACKAGES } from '@fougere/compiler';
7
8
  import { type Conventions, DEFAULT_CONVENTIONS } from '@fougere/core';
@@ -34,6 +35,56 @@ export interface FougereViteOptions {
34
35
  keepClassNames?: boolean;
35
36
  /** Extra identifiers to reserve, for entities that do not live under `fronds/`. */
36
37
  reserved?: string[];
38
+ /**
39
+ * Where the fronds are, from the app — `'../..'` in a workspace, whose `fronds/` sit at its
40
+ * root. The same key `@fougere/nuxt` reads.
41
+ */
42
+ root?: string;
43
+ /** Set false when the host serves the call envelope itself. */
44
+ serve?: boolean;
45
+ }
46
+
47
+ /** What the browser primitives call, and the web handler that answers each. */
48
+ const DOORS = { '/_fougere/call': 'call', '/_fougere/session': 'session' } as const;
49
+
50
+ /**
51
+ * The call envelope, answered by the dev server itself: a Vite app has no server of its own, and
52
+ * the browser calls its own origin. The app boots at the first call, from `fougere.config.ts`, so
53
+ * `fronds:` decides whether a frond answers here or a process away — the same line as under Nuxt.
54
+ */
55
+ function serveDoors() {
56
+ return (req: IncomingMessage, res: ServerResponse, next: () => void): void => {
57
+ const path = (req.url ?? '').split('?')[0] as keyof typeof DOORS;
58
+ const door = DOORS[path];
59
+ if (!door) return next();
60
+
61
+ void (async () => {
62
+ try {
63
+ const web = await import('@fougere/app/web');
64
+ const response = await web[door](await requestOf(req));
65
+ res.statusCode = response.status;
66
+ response.headers.forEach((value, key) => res.setHeader(key, value));
67
+ res.end(Buffer.from(await response.arrayBuffer()));
68
+ } catch (error) {
69
+ res.statusCode = 500;
70
+ res.setHeader('content-type', 'application/json');
71
+ res.end(JSON.stringify({ code: 'INTERNAL_ERROR', message: (error as Error).message }));
72
+ }
73
+ })();
74
+ };
75
+ }
76
+
77
+ async function requestOf(req: IncomingMessage): Promise<Request> {
78
+ const chunks: Buffer[] = [];
79
+ for await (const chunk of req) chunks.push(chunk as Buffer);
80
+ const headers = new Headers(Object.entries(req.headers)
81
+ .filter((entry): entry is [string, string] => typeof entry[1] === 'string'));
82
+
83
+ return new Request(`http://${req.headers.host ?? 'localhost'}${req.url}`, {
84
+ method: req.method,
85
+ headers,
86
+ ...(chunks.length ? { body: Buffer.concat(chunks) } : {}),
87
+ });
37
88
  }
38
89
 
39
90
  /**
@@ -55,7 +106,7 @@ const NAMES = '.fougere/names.generated.d.ts';
55
106
  * A scan that fails is not a failure of the dev server: the types fall back to every code there
56
107
  * is, which is what a client had before this existed.
57
108
  */
58
- async function writeDoors(root: string): Promise<void> {
109
+ async function writeDoors(app: string, root: string): Promise<void> {
59
110
  try {
60
111
  const { scanProject, emitFacade, emitNames, frondAliases } = await import('@fougere/compiler');
61
112
  const { setModuleLoader } = await import('@fougere/core/node');
@@ -72,26 +123,30 @@ async function writeDoors(root: string): Promise<void> {
72
123
  });
73
124
  setModuleLoader((filePath: string) => jiti.import(filePath) as Promise<Record<string, unknown>>);
74
125
  const { loadConfig } = await import('@fougere/core/node');
75
- const out = join(root, FACADE);
126
+ const out = join(app, FACADE);
76
127
  mkdirSync(dirname(out), { recursive: true });
77
128
  const scan = await scanProject(root);
78
129
  writeFileSync(out, emitFacade(scan, { outFile: out }));
79
130
  // What a config may NAME, from the same scan: the sources are the config's own keys, which
80
131
  // no scan can find, and a project without one states none.
81
132
  const config = await loadConfig(root).catch(() => ({}) as FougereConfig);
82
- writeFileSync(join(root, NAMES), emitNames(scan, { sources: Object.keys(config.sources ?? {}) }));
133
+ writeFileSync(join(app, NAMES), emitNames(scan, { sources: Object.keys(config.sources ?? {}) }));
83
134
  } catch { /* a host with no fronds, or a scan that could not run */ }
84
135
  }
85
136
 
86
137
  export function fougere(options: FougereViteOptions = {}): Plugin {
87
138
  const external = [...new Set([...RUNTIME_PACKAGES, ...(options.external ?? [])])];
88
- // Where `config` said the project is, so `buildStart` writes beside the alias it set.
89
- let root = process.cwd();
139
+ // Where `config` said the app is, so `buildStart` writes beside the alias it set — and where
140
+ // its fronds are, which a workspace puts two levels up.
141
+ let app = process.cwd();
142
+ const frondsOf = (from: string) => resolve(from, options.root ?? '.');
90
143
 
91
144
  return {
92
145
  name: 'fougere',
93
- configureServer(server: { config?: { root?: string } }) {
94
- void writeDoors(server.config?.root ?? root);
146
+ configureServer(server: { config?: { root?: string }; middlewares: { use(handler: ReturnType<typeof serveDoors>): void } }) {
147
+ const root = server.config?.root ?? app;
148
+ void writeDoors(root, frondsOf(root));
149
+ if (options.serve !== false) server.middlewares.use(serveDoors());
95
150
  },
96
151
  /**
97
152
  * AWAITED, and that is the whole point: the bundler resolves `@fronds/facade` right after
@@ -99,7 +154,7 @@ export function fougere(options: FougereViteOptions = {}): Plugin {
99
154
  * .fougere/facade.generated.ts`, measured on `demos/react-router-blog`.
100
155
  */
101
156
  async buildStart() {
102
- await writeDoors(root);
157
+ await writeDoors(app, frondsOf(app));
103
158
  },
104
159
  /** `order. */
105
160
  config: {
@@ -111,19 +166,22 @@ export function fougere(options: FougereViteOptions = {}): Plugin {
111
166
  // A page IMPORTS its facade, so the alias sits beside the file that declares them: a
112
167
  // project that never generated it fails to resolve rather than losing its types in
113
168
  // silence.
114
- root = config.root ?? root;
169
+ app = resolve(config.root ?? app);
170
+ // Read by the boot, which runs in this process and has no other way to learn it — the
171
+ // variable `@fougere/nuxt` sets for the same reason.
172
+ process.env.FOUGERE_ROOT = frondsOf(app);
115
173
  config.resolve ??= {};
116
174
  // Vite admits BOTH shapes and a host picks one: SvelteKit states an array of
117
175
  // `{ find, replacement }`, and spreading an object over it made rolldown refuse the
118
176
  // whole plugin — `StringExpected … on BindingViteAliasPluginAlias.replacement`.
119
- const facade = join(root, FACADE);
177
+ const facade = join(app, FACADE);
120
178
  config.resolve.alias = Array.isArray(config.resolve.alias)
121
179
  ? [...config.resolve.alias, { find: '@fronds/facade', replacement: facade }]
122
180
  : { ...config.resolve.alias, '@fronds/facade': facade };
123
181
 
124
182
  if (options.keepClassNames === false) return;
125
183
 
126
- const reserved = [...(options.reserved ?? []), ...entityNamesIn(config.root ?? process.cwd())];
184
+ const reserved = [...(options.reserved ?? []), ...entityNamesIn(frondsOf(app))];
127
185
  if (reserved.length === 0) return;
128
186
 
129
187
  config.build ??= {};