@fluixi/start 0.1.0-alpha.74 → 0.1.0-alpha.76

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.
Files changed (120) hide show
  1. package/dist/adapter.cjs +6 -4
  2. package/dist/adapter.d.ts +9 -9
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +13 -11
  5. package/dist/adapter.mjs +6 -4
  6. package/dist/adapters/entry.cjs +1 -1
  7. package/dist/adapters/entry.js +1 -1
  8. package/dist/adapters/entry.mjs +1 -1
  9. package/dist/adapters/platforms.cjs +1 -1
  10. package/dist/adapters/platforms.d.ts +2 -2
  11. package/dist/adapters/platforms.js +8 -8
  12. package/dist/adapters/platforms.mjs +1 -1
  13. package/dist/{api-RH6E5UTH.mjs → api-HD7KU3BS.mjs} +1 -1
  14. package/dist/api.cjs +2 -2
  15. package/dist/api.js +1 -1
  16. package/dist/api.mjs +2 -2
  17. package/dist/commands/{api-RH6E5UTH.mjs → api-HD7KU3BS.mjs} +1 -1
  18. package/dist/commands/{api-23MJFSYL.mjs → api-LTOLCZPE.mjs} +2 -2
  19. package/dist/commands/{api-4IYNQRKG.mjs → api-PBT4QZ34.mjs} +1 -1
  20. package/dist/commands/build.cjs +14 -7
  21. package/dist/commands/build.js +6 -6
  22. package/dist/commands/build.mjs +14 -7
  23. package/dist/commands/{chunk-OCPCK4ZJ.mjs → chunk-JACRXSN7.mjs} +2 -2
  24. package/dist/commands/{chunk-NS5GR2GX.mjs → chunk-MTM6M3TC.mjs} +1 -1
  25. package/dist/commands/dev.cjs +17 -5
  26. package/dist/commands/dev.d.ts.map +1 -1
  27. package/dist/commands/dev.js +9 -4
  28. package/dist/commands/dev.mjs +18 -6
  29. package/dist/commands/index.cjs +21 -9
  30. package/dist/commands/index.d.ts +1 -1
  31. package/dist/commands/index.js +1 -1
  32. package/dist/commands/index.mjs +22 -10
  33. package/dist/commands/prerender.cjs +2 -0
  34. package/dist/commands/prerender.d.ts +1 -1
  35. package/dist/commands/prerender.js +2 -2
  36. package/dist/commands/prerender.mjs +2 -0
  37. package/dist/commands/start.cjs +2 -0
  38. package/dist/commands/start.d.ts +1 -1
  39. package/dist/commands/start.js +2 -2
  40. package/dist/commands/start.mjs +2 -0
  41. package/dist/config.cjs +7 -1
  42. package/dist/config.d.ts +24 -7
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +8 -6
  45. package/dist/config.mjs +7 -1
  46. package/dist/define-config.cjs +32 -0
  47. package/dist/define-config.d.ts +12 -0
  48. package/dist/define-config.d.ts.map +1 -0
  49. package/dist/define-config.js +3 -0
  50. package/dist/define-config.mjs +7 -0
  51. package/dist/di.cjs +1 -1
  52. package/dist/di.d.ts +4 -4
  53. package/dist/di.d.ts.map +1 -1
  54. package/dist/di.js +9 -9
  55. package/dist/di.mjs +1 -1
  56. package/dist/document.d.ts +1 -1
  57. package/dist/document.js +1 -1
  58. package/dist/generated-api.cjs +1 -1
  59. package/dist/generated-api.js +1 -1
  60. package/dist/generated-api.mjs +1 -1
  61. package/dist/generated-server-fns.cjs +1 -1
  62. package/dist/generated-server-fns.mjs +1 -1
  63. package/dist/handler-core.cjs +1 -1
  64. package/dist/handler-core.d.ts +2 -2
  65. package/dist/handler-core.js +2 -2
  66. package/dist/handler-core.mjs +1 -1
  67. package/dist/handler.cjs +1 -0
  68. package/dist/handler.d.ts +3 -3
  69. package/dist/handler.js +3 -3
  70. package/dist/handler.mjs +2 -0
  71. package/dist/head.cjs +1 -1
  72. package/dist/head.d.ts +1 -1
  73. package/dist/head.js +1 -1
  74. package/dist/head.mjs +1 -1
  75. package/dist/image-loader.cjs +37 -0
  76. package/dist/image-loader.d.ts +25 -0
  77. package/dist/image-loader.d.ts.map +1 -0
  78. package/dist/image-loader.js +18 -0
  79. package/dist/image-loader.mjs +12 -0
  80. package/dist/image.cjs +13 -8
  81. package/dist/image.d.ts +2 -19
  82. package/dist/image.d.ts.map +1 -1
  83. package/dist/image.js +5 -21
  84. package/dist/image.mjs +14 -8
  85. package/dist/index.cjs +5 -738
  86. package/dist/index.d.ts +28 -8
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +33 -17
  89. package/dist/index.mjs +4 -710
  90. package/dist/interceptors.cjs +1 -0
  91. package/dist/interceptors.js +1 -1
  92. package/dist/interceptors.mjs +2 -0
  93. package/dist/internal.cjs +9 -4
  94. package/dist/internal.d.ts +6 -6
  95. package/dist/internal.d.ts.map +1 -1
  96. package/dist/internal.js +23 -15
  97. package/dist/internal.mjs +9 -4
  98. package/dist/middleware.d.ts +3 -3
  99. package/dist/middleware.d.ts.map +1 -1
  100. package/dist/middleware.js +1 -1
  101. package/dist/preload.cjs +1 -1
  102. package/dist/preload.js +1 -1
  103. package/dist/preload.mjs +1 -1
  104. package/dist/router.cjs +1 -1
  105. package/dist/router.d.ts +3 -3
  106. package/dist/router.js +3 -3
  107. package/dist/router.mjs +1 -1
  108. package/dist/server-fn-setup.cjs +1 -1
  109. package/dist/server-fn-setup.d.ts +1 -1
  110. package/dist/server-fn-setup.js +2 -2
  111. package/dist/server-fn-setup.mjs +1 -1
  112. package/dist/server-fn.cjs +1 -1
  113. package/dist/server-fn.d.ts +2 -2
  114. package/dist/server-fn.js +2 -2
  115. package/dist/server-fn.mjs +1 -1
  116. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  117. package/dist/ui.cjs +1 -1
  118. package/dist/ui.js +1 -1
  119. package/dist/ui.mjs +1 -1
  120. package/package.json +25 -7
@@ -20,6 +20,8 @@ function resolveConfig(config = {}) {
20
20
  middleware: config.middleware ?? "src/middleware.ts",
21
21
  ssrNoExternal: config.ssrNoExternal ?? [],
22
22
  resolve: config.resolve ?? [],
23
+ vitePlugin: config.vitePlugin ?? {},
24
+ plugins: config.plugins ?? [],
23
25
  adapter: config.adapter,
24
26
  i18n: resolveI18n(config.i18n),
25
27
  prerender: resolvePrerender(config.prerender)
@@ -215,7 +217,7 @@ function startTypesPlugin(cfg) {
215
217
  const blocks = [];
216
218
  if (cfg.i18n) blocks.push(...i18nTypeBlock(root, cfg.i18n));
217
219
  if (blocks.length === 0) return;
218
- const content = `// Auto-generated by @fluixi/start do not edit.
220
+ const content = `// Auto-generated by @fluixi/start, do not edit.
219
221
  ${blocks.join("\n")}
220
222
  `;
221
223
  const file = resolvePath(root, "src/fluixi-start-env.d.ts");
@@ -236,12 +238,17 @@ async function fluixiPlugins(cfg) {
236
238
  // app has no way to say where an unimported tag comes from.
237
239
  //
238
240
  // `fluixi()` and not `createVitePlugin()`: the latter is the bare compiler integration,
239
- // and the reactive graph agent, source marks, /__fluixi/graph is composed on top of
241
+ // and the reactive graph: agent, source marks, /__fluixi/graph, is composed on top of
240
242
  // it by the former. A start app got no graph at all until this changed.
241
- fluixi({ resolve: cfg.resolve })
243
+ // Everything the app declared for the compiler, with `resolve` still usable on its
244
+ // own because it is the one most apps set. A start app never writes
245
+ // `fluixi()` itself, so without this passthrough the plugin's other options
246
+ // (propsDestructure and the rest) had nowhere to be declared.
247
+ fluixi({ ...cfg.vitePlugin ?? {}, ...cfg.resolve ? { resolve: cfg.resolve } : {} })
242
248
  ];
249
+ if (cfg.plugins?.length) plugins.push(...cfg.plugins);
243
250
  if (cfg.i18n) plugins.push(i18nVitePlugin(cfg.i18n));
244
- const { apiRoutesVitePlugin } = await import("./api-RH6E5UTH.mjs");
251
+ const { apiRoutesVitePlugin } = await import("./api-HD7KU3BS.mjs");
245
252
  plugins.push(apiRoutesVitePlugin({ dir: cfg.apiDir }));
246
253
  plugins.push(startTypesPlugin(cfg));
247
254
  return plugins;
@@ -401,14 +408,14 @@ async function loadPreloader(cfg) {
401
408
  }
402
409
  var GENERATED_SUBPATHS = /* @__PURE__ */ new Set(["./routes", "./server-fns", "./api-routes"]);
403
410
  function ssrBuildOptions(cfg) {
404
- const noExternal = cfg.ssrNoExternal.length ? cfg.ssrNoExternal : void 0;
411
+ const noExternal = [.../* @__PURE__ */ new Set(["@fluixi/core", ...cfg.ssrNoExternal])];
405
412
  const mode = cfg.adapter?.bundle;
406
413
  if (mode === "inline") return { noExternal: true };
407
414
  if (mode !== "external") return { noExternal };
408
415
  const external = frameworkDeps(cfg.root).filter((name) => !cfg.ssrNoExternal.includes(name)).flatMap((name) => withSubpaths(cfg.root, name));
409
416
  if (!external.length) {
410
417
  console.warn(
411
- ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${join(cfg.root, "package.json")} bundling everything.`
418
+ ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${join(cfg.root, "package.json")}, bundling everything.`
412
419
  );
413
420
  }
414
421
  return { noExternal, external: external.length ? external : void 0 };
@@ -689,7 +696,7 @@ async function bundleEntry(cfg, plugins, source, outFile) {
689
696
  output: {
690
697
  entryFileNames: basename(outFile),
691
698
  // One file, no chunks. A lazy route would otherwise be split out beside
692
- // the entry and for Cloudflare that directory is the published one, so
699
+ // the entry: and for Cloudflare that directory is the published one, so
693
700
  // every server chunk would be a public download.
694
701
  inlineDynamicImports: true
695
702
  }
@@ -1,4 +1,4 @@
1
- /*! @fluixi/start v0.1.0-alpha.74 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/start v0.1.0-alpha.76 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/api.ts
4
4
  import { readdirSync, statSync } from "node:fs";
@@ -75,7 +75,7 @@ function apiRoutesVitePlugin(opts) {
75
75
  return {
76
76
  name: "fluixi-api",
77
77
  // Must beat node resolution: '@fluixi/start/api-routes' is a real file in this package,
78
- // so without `pre` Vite resolves the typed stub and the generated table never loads
78
+ // so without `pre` Vite resolves the typed stub and the generated table never loads ,
79
79
  // the app builds and every API route 404s.
80
80
  enforce: "pre",
81
81
  configResolved(config) {
@@ -73,7 +73,7 @@ function apiRoutesVitePlugin(opts) {
73
73
  return {
74
74
  name: "fluixi-api",
75
75
  // Must beat node resolution: '@fluixi/start/api-routes' is a real file in this package,
76
- // so without `pre` Vite resolves the typed stub and the generated table never loads
76
+ // so without `pre` Vite resolves the typed stub and the generated table never loads ,
77
77
  // the app builds and every API route 404s.
78
78
  enforce: "pre",
79
79
  configResolved(config) {
@@ -110,7 +110,7 @@ function apiRoutesVitePlugin(opts) {
110
110
  return {
111
111
  name: "fluixi-api",
112
112
  // Must beat node resolution: '@fluixi/start/api-routes' is a real file in this package,
113
- // so without `pre` Vite resolves the typed stub and the generated table never loads
113
+ // so without `pre` Vite resolves the typed stub and the generated table never loads ,
114
114
  // the app builds and every API route 404s.
115
115
  enforce: "pre",
116
116
  configResolved(config) {
@@ -179,6 +179,8 @@ function resolveConfig(config = {}) {
179
179
  middleware: config.middleware ?? "src/middleware.ts",
180
180
  ssrNoExternal: config.ssrNoExternal ?? [],
181
181
  resolve: config.resolve ?? [],
182
+ vitePlugin: config.vitePlugin ?? {},
183
+ plugins: config.plugins ?? [],
182
184
  adapter: config.adapter,
183
185
  i18n: resolveI18n(config.i18n),
184
186
  prerender: resolvePrerender(config.prerender)
@@ -363,7 +365,7 @@ function startTypesPlugin(cfg) {
363
365
  const blocks = [];
364
366
  if (cfg.i18n) blocks.push(...i18nTypeBlock(root, cfg.i18n));
365
367
  if (blocks.length === 0) return;
366
- const content = `// Auto-generated by @fluixi/start do not edit.
368
+ const content = `// Auto-generated by @fluixi/start, do not edit.
367
369
  ${blocks.join("\n")}
368
370
  `;
369
371
  const file = (0, import_node_path3.resolve)(root, "src/fluixi-start-env.d.ts");
@@ -384,10 +386,15 @@ async function fluixiPlugins(cfg) {
384
386
  // app has no way to say where an unimported tag comes from.
385
387
  //
386
388
  // `fluixi()` and not `createVitePlugin()`: the latter is the bare compiler integration,
387
- // and the reactive graph agent, source marks, /__fluixi/graph is composed on top of
389
+ // and the reactive graph: agent, source marks, /__fluixi/graph, is composed on top of
388
390
  // it by the former. A start app got no graph at all until this changed.
389
- fluixi({ resolve: cfg.resolve })
391
+ // Everything the app declared for the compiler, with `resolve` still usable on its
392
+ // own because it is the one most apps set. A start app never writes
393
+ // `fluixi()` itself, so without this passthrough the plugin's other options
394
+ // (propsDestructure and the rest) had nowhere to be declared.
395
+ fluixi({ ...cfg.vitePlugin ?? {}, ...cfg.resolve ? { resolve: cfg.resolve } : {} })
390
396
  ];
397
+ if (cfg.plugins?.length) plugins.push(...cfg.plugins);
391
398
  if (cfg.i18n) plugins.push(i18nVitePlugin(cfg.i18n));
392
399
  const { apiRoutesVitePlugin: apiRoutesVitePlugin2 } = await Promise.resolve().then(() => (init_api(), api_exports));
393
400
  plugins.push(apiRoutesVitePlugin2({ dir: cfg.apiDir }));
@@ -653,7 +660,12 @@ async function dev(config = {}) {
653
660
  // file routing + JSX/SSR transform (fluixi)
654
661
  server: { middlewareMode: true, hmr: { server: http } },
655
662
  appType: "custom",
656
- ssr: cfg.ssrNoExternal.length ? { noExternal: cfg.ssrNoExternal } : void 0
663
+ // `@fluixi/core` always goes through vite rather than being externalized.
664
+ // `@fluixi/core/routes` is served by fluixiRoutesPlugin, and an externalized
665
+ // dependency is imported by node directly, so no plugin ever sees the specifier and
666
+ // the app gets the "did not replace it" stub instead of its route tree. A workspace
667
+ // app hides this by resolving the package to source.
668
+ ssr: { noExternal: ["@fluixi/core", ...cfg.ssrNoExternal] }
657
669
  });
658
670
  http.listen(cfg.port, () => devReady({ port: cfg.port, startedAt }));
659
671
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkDjD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,MAAM,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFlE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkDjD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,MAAM,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2FlE"}
@@ -12,7 +12,7 @@ const STYLE_FILE = /\.(css|scss|sass|less|styl|stylus|pcss|postcss)(\?|$)/;
12
12
  * Stylesheets the SSR render pulled in, walked from the server entry.
13
13
  *
14
14
  * Without these, dev serves a fully rendered page with no CSS at all and the styles
15
- * arrive with the client bundle a flash of unstyled content on every load, in the one
15
+ * arrive with the client bundle: a flash of unstyled content on every load, in the one
16
16
  * environment you look at most. The build has no such gap: Vite emits real `<link>`s.
17
17
  *
18
18
  * Dev serves a `.css` URL as a JS module that injects a style tag, so `?direct` is what
@@ -75,13 +75,13 @@ export async function dev(config = {}) {
75
75
  const path = url.pathname + url.search;
76
76
  // Server-function RPC: auto-wired. Load the registry vmod (registers every "use server"
77
77
  // fn + wires the request-context runner + re-exports the dispatcher) and route /_server
78
- // through it no need for the app's entry-server to re-export anything.
78
+ // through it: no need for the app's entry-server to re-export anything.
79
79
  if (url.pathname === '/_server') {
80
80
  const sf = await vite.ssrLoadModule(SERVER_FNS_VMOD);
81
81
  if (sf.isServerFnRequest(request))
82
82
  return sf.handleServerFn(request);
83
83
  }
84
- // File-based API routes (src/api/** → /api/*) auto-wired, no entry change needed.
84
+ // File-based API routes (src/api/** → /api/*), auto-wired, no entry change needed.
85
85
  if (isApiPath(url.pathname)) {
86
86
  const api = await vite.ssrLoadModule(API_VIRTUAL_MODULE);
87
87
  if (api.isApiRequest(request))
@@ -128,7 +128,12 @@ export async function dev(config = {}) {
128
128
  plugins: await fluixiPlugins(cfg), // file routing + JSX/SSR transform (fluixi)
129
129
  server: { middlewareMode: true, hmr: { server: http } },
130
130
  appType: 'custom',
131
- ssr: cfg.ssrNoExternal.length ? { noExternal: cfg.ssrNoExternal } : undefined,
131
+ // `@fluixi/core` always goes through vite rather than being externalized.
132
+ // `@fluixi/core/routes` is served by fluixiRoutesPlugin, and an externalized
133
+ // dependency is imported by node directly, so no plugin ever sees the specifier and
134
+ // the app gets the "did not replace it" stub instead of its route tree. A workspace
135
+ // app hides this by resolving the package to source.
136
+ ssr: { noExternal: ['@fluixi/core', ...cfg.ssrNoExternal] },
132
137
  });
133
138
  http.listen(cfg.port, () => devReady({ port: cfg.port, startedAt }));
134
139
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  API_VIRTUAL_MODULE,
3
3
  isApiPath
4
- } from "./chunk-NS5GR2GX.mjs";
4
+ } from "./chunk-MTM6M3TC.mjs";
5
5
 
6
6
  // src/commands/dev.ts
7
7
  import { createServer as createHttp } from "node:http";
@@ -25,6 +25,8 @@ function resolveConfig(config = {}) {
25
25
  middleware: config.middleware ?? "src/middleware.ts",
26
26
  ssrNoExternal: config.ssrNoExternal ?? [],
27
27
  resolve: config.resolve ?? [],
28
+ vitePlugin: config.vitePlugin ?? {},
29
+ plugins: config.plugins ?? [],
28
30
  adapter: config.adapter,
29
31
  i18n: resolveI18n(config.i18n),
30
32
  prerender: resolvePrerender(config.prerender)
@@ -209,7 +211,7 @@ function startTypesPlugin(cfg) {
209
211
  const blocks = [];
210
212
  if (cfg.i18n) blocks.push(...i18nTypeBlock(root, cfg.i18n));
211
213
  if (blocks.length === 0) return;
212
- const content = `// Auto-generated by @fluixi/start do not edit.
214
+ const content = `// Auto-generated by @fluixi/start, do not edit.
213
215
  ${blocks.join("\n")}
214
216
  `;
215
217
  const file = resolvePath(root, "src/fluixi-start-env.d.ts");
@@ -230,12 +232,17 @@ async function fluixiPlugins(cfg) {
230
232
  // app has no way to say where an unimported tag comes from.
231
233
  //
232
234
  // `fluixi()` and not `createVitePlugin()`: the latter is the bare compiler integration,
233
- // and the reactive graph agent, source marks, /__fluixi/graph is composed on top of
235
+ // and the reactive graph: agent, source marks, /__fluixi/graph, is composed on top of
234
236
  // it by the former. A start app got no graph at all until this changed.
235
- fluixi({ resolve: cfg.resolve })
237
+ // Everything the app declared for the compiler, with `resolve` still usable on its
238
+ // own because it is the one most apps set. A start app never writes
239
+ // `fluixi()` itself, so without this passthrough the plugin's other options
240
+ // (propsDestructure and the rest) had nowhere to be declared.
241
+ fluixi({ ...cfg.vitePlugin ?? {}, ...cfg.resolve ? { resolve: cfg.resolve } : {} })
236
242
  ];
243
+ if (cfg.plugins?.length) plugins.push(...cfg.plugins);
237
244
  if (cfg.i18n) plugins.push(i18nVitePlugin(cfg.i18n));
238
- const { apiRoutesVitePlugin } = await import("./api-4IYNQRKG.mjs");
245
+ const { apiRoutesVitePlugin } = await import("./api-PBT4QZ34.mjs");
239
246
  plugins.push(apiRoutesVitePlugin({ dir: cfg.apiDir }));
240
247
  plugins.push(startTypesPlugin(cfg));
241
248
  return plugins;
@@ -496,7 +503,12 @@ async function dev(config = {}) {
496
503
  // file routing + JSX/SSR transform (fluixi)
497
504
  server: { middlewareMode: true, hmr: { server: http } },
498
505
  appType: "custom",
499
- ssr: cfg.ssrNoExternal.length ? { noExternal: cfg.ssrNoExternal } : void 0
506
+ // `@fluixi/core` always goes through vite rather than being externalized.
507
+ // `@fluixi/core/routes` is served by fluixiRoutesPlugin, and an externalized
508
+ // dependency is imported by node directly, so no plugin ever sees the specifier and
509
+ // the app gets the "did not replace it" stub instead of its route tree. A workspace
510
+ // app hides this by resolving the package to source.
511
+ ssr: { noExternal: ["@fluixi/core", ...cfg.ssrNoExternal] }
500
512
  });
501
513
  http.listen(cfg.port, () => devReady({ port: cfg.port, startedAt }));
502
514
  }
@@ -1,4 +1,4 @@
1
- /*! @fluixi/start v0.1.0-alpha.74 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/start v0.1.0-alpha.76 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -111,7 +111,7 @@ function apiRoutesVitePlugin(opts) {
111
111
  return {
112
112
  name: "fluixi-api",
113
113
  // Must beat node resolution: '@fluixi/start/api-routes' is a real file in this package,
114
- // so without `pre` Vite resolves the typed stub and the generated table never loads
114
+ // so without `pre` Vite resolves the typed stub and the generated table never loads ,
115
115
  // the app builds and every API route 404s.
116
116
  enforce: "pre",
117
117
  configResolved(config) {
@@ -185,6 +185,8 @@ function resolveConfig(config = {}) {
185
185
  middleware: config.middleware ?? "src/middleware.ts",
186
186
  ssrNoExternal: config.ssrNoExternal ?? [],
187
187
  resolve: config.resolve ?? [],
188
+ vitePlugin: config.vitePlugin ?? {},
189
+ plugins: config.plugins ?? [],
188
190
  adapter: config.adapter,
189
191
  i18n: resolveI18n(config.i18n),
190
192
  prerender: resolvePrerender(config.prerender)
@@ -381,7 +383,7 @@ function startTypesPlugin(cfg) {
381
383
  const blocks = [];
382
384
  if (cfg.i18n) blocks.push(...i18nTypeBlock(root, cfg.i18n));
383
385
  if (blocks.length === 0) return;
384
- const content = `// Auto-generated by @fluixi/start do not edit.
386
+ const content = `// Auto-generated by @fluixi/start, do not edit.
385
387
  ${blocks.join("\n")}
386
388
  `;
387
389
  const file = (0, import_node_path3.resolve)(root, "src/fluixi-start-env.d.ts");
@@ -402,10 +404,15 @@ async function fluixiPlugins(cfg) {
402
404
  // app has no way to say where an unimported tag comes from.
403
405
  //
404
406
  // `fluixi()` and not `createVitePlugin()`: the latter is the bare compiler integration,
405
- // and the reactive graph agent, source marks, /__fluixi/graph is composed on top of
407
+ // and the reactive graph: agent, source marks, /__fluixi/graph, is composed on top of
406
408
  // it by the former. A start app got no graph at all until this changed.
407
- fluixi({ resolve: cfg.resolve })
409
+ // Everything the app declared for the compiler, with `resolve` still usable on its
410
+ // own because it is the one most apps set. A start app never writes
411
+ // `fluixi()` itself, so without this passthrough the plugin's other options
412
+ // (propsDestructure and the rest) had nowhere to be declared.
413
+ fluixi({ ...cfg.vitePlugin ?? {}, ...cfg.resolve ? { resolve: cfg.resolve } : {} })
408
414
  ];
415
+ if (cfg.plugins?.length) plugins.push(...cfg.plugins);
409
416
  if (cfg.i18n) plugins.push(i18nVitePlugin(cfg.i18n));
410
417
  const { apiRoutesVitePlugin: apiRoutesVitePlugin2 } = await Promise.resolve().then(() => (init_api(), api_exports));
411
418
  plugins.push(apiRoutesVitePlugin2({ dir: cfg.apiDir }));
@@ -754,7 +761,12 @@ async function dev(config = {}) {
754
761
  // file routing + JSX/SSR transform (fluixi)
755
762
  server: { middlewareMode: true, hmr: { server: http } },
756
763
  appType: "custom",
757
- ssr: cfg.ssrNoExternal.length ? { noExternal: cfg.ssrNoExternal } : void 0
764
+ // `@fluixi/core` always goes through vite rather than being externalized.
765
+ // `@fluixi/core/routes` is served by fluixiRoutesPlugin, and an externalized
766
+ // dependency is imported by node directly, so no plugin ever sees the specifier and
767
+ // the app gets the "did not replace it" stub instead of its route tree. A workspace
768
+ // app hides this by resolving the package to source.
769
+ ssr: { noExternal: ["@fluixi/core", ...cfg.ssrNoExternal] }
758
770
  });
759
771
  http.listen(cfg.port, () => devReady({ port: cfg.port, startedAt }));
760
772
  }
@@ -863,14 +875,14 @@ var nodeAdapter = {
863
875
  };
864
876
  var GENERATED_SUBPATHS = /* @__PURE__ */ new Set(["./routes", "./server-fns", "./api-routes"]);
865
877
  function ssrBuildOptions(cfg) {
866
- const noExternal = cfg.ssrNoExternal.length ? cfg.ssrNoExternal : void 0;
878
+ const noExternal = [.../* @__PURE__ */ new Set(["@fluixi/core", ...cfg.ssrNoExternal])];
867
879
  const mode = cfg.adapter?.bundle;
868
880
  if (mode === "inline") return { noExternal: true };
869
881
  if (mode !== "external") return { noExternal };
870
882
  const external = frameworkDeps(cfg.root).filter((name) => !cfg.ssrNoExternal.includes(name)).flatMap((name) => withSubpaths(cfg.root, name));
871
883
  if (!external.length) {
872
884
  console.warn(
873
- ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${(0, import_node_path6.join)(cfg.root, "package.json")} bundling everything.`
885
+ ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${(0, import_node_path6.join)(cfg.root, "package.json")}, bundling everything.`
874
886
  );
875
887
  }
876
888
  return { noExternal, external: external.length ? external : void 0 };
@@ -1096,7 +1108,7 @@ async function bundleEntry(cfg, plugins, source, outFile) {
1096
1108
  output: {
1097
1109
  entryFileNames: (0, import_node_path8.basename)(outFile),
1098
1110
  // One file, no chunks. A lazy route would otherwise be split out beside
1099
- // the entry and for Cloudflare that directory is the published one, so
1111
+ // the entry: and for Cloudflare that directory is the published one, so
1100
1112
  // every server chunk would be a public download.
1101
1113
  inlineDynamicImports: true
1102
1114
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Kept off the package root deliberately: these reach the dev server, the build
5
5
  * and the prerenderer, and a module that only wants `defineMiddleware` should not
6
- * be able to pull a bundler in behind it. That matters at build time a deploy
6
+ * be able to pull a bundler in behind it. That matters at build time, a deploy
7
7
  * adapter inlines everything the entry can reach, and reaching this would put
8
8
  * vite in a worker.
9
9
  */
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Kept off the package root deliberately: these reach the dev server, the build
5
5
  * and the prerenderer, and a module that only wants `defineMiddleware` should not
6
- * be able to pull a bundler in behind it. That matters at build time a deploy
6
+ * be able to pull a bundler in behind it. That matters at build time, a deploy
7
7
  * adapter inlines everything the entry can reach, and reaching this would put
8
8
  * vite in a worker.
9
9
  */
@@ -1,8 +1,8 @@
1
- /*! @fluixi/start v0.1.0-alpha.74 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/start v0.1.0-alpha.76 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  API_VIRTUAL_MODULE,
4
4
  isApiPath
5
- } from "./chunk-OCPCK4ZJ.mjs";
5
+ } from "./chunk-JACRXSN7.mjs";
6
6
 
7
7
  // src/commands/dev.ts
8
8
  import { createServer as createHttp } from "node:http";
@@ -26,6 +26,8 @@ function resolveConfig(config = {}) {
26
26
  middleware: config.middleware ?? "src/middleware.ts",
27
27
  ssrNoExternal: config.ssrNoExternal ?? [],
28
28
  resolve: config.resolve ?? [],
29
+ vitePlugin: config.vitePlugin ?? {},
30
+ plugins: config.plugins ?? [],
29
31
  adapter: config.adapter,
30
32
  i18n: resolveI18n(config.i18n),
31
33
  prerender: resolvePrerender(config.prerender)
@@ -222,7 +224,7 @@ function startTypesPlugin(cfg) {
222
224
  const blocks = [];
223
225
  if (cfg.i18n) blocks.push(...i18nTypeBlock(root, cfg.i18n));
224
226
  if (blocks.length === 0) return;
225
- const content = `// Auto-generated by @fluixi/start do not edit.
227
+ const content = `// Auto-generated by @fluixi/start, do not edit.
226
228
  ${blocks.join("\n")}
227
229
  `;
228
230
  const file = resolvePath(root, "src/fluixi-start-env.d.ts");
@@ -243,12 +245,17 @@ async function fluixiPlugins(cfg) {
243
245
  // app has no way to say where an unimported tag comes from.
244
246
  //
245
247
  // `fluixi()` and not `createVitePlugin()`: the latter is the bare compiler integration,
246
- // and the reactive graph agent, source marks, /__fluixi/graph is composed on top of
248
+ // and the reactive graph: agent, source marks, /__fluixi/graph, is composed on top of
247
249
  // it by the former. A start app got no graph at all until this changed.
248
- fluixi({ resolve: cfg.resolve })
250
+ // Everything the app declared for the compiler, with `resolve` still usable on its
251
+ // own because it is the one most apps set. A start app never writes
252
+ // `fluixi()` itself, so without this passthrough the plugin's other options
253
+ // (propsDestructure and the rest) had nowhere to be declared.
254
+ fluixi({ ...cfg.vitePlugin ?? {}, ...cfg.resolve ? { resolve: cfg.resolve } : {} })
249
255
  ];
256
+ if (cfg.plugins?.length) plugins.push(...cfg.plugins);
250
257
  if (cfg.i18n) plugins.push(i18nVitePlugin(cfg.i18n));
251
- const { apiRoutesVitePlugin } = await import("./api-23MJFSYL.mjs");
258
+ const { apiRoutesVitePlugin } = await import("./api-LTOLCZPE.mjs");
252
259
  plugins.push(apiRoutesVitePlugin({ dir: cfg.apiDir }));
253
260
  plugins.push(startTypesPlugin(cfg));
254
261
  return plugins;
@@ -592,7 +599,12 @@ async function dev(config = {}) {
592
599
  // file routing + JSX/SSR transform (fluixi)
593
600
  server: { middlewareMode: true, hmr: { server: http } },
594
601
  appType: "custom",
595
- ssr: cfg.ssrNoExternal.length ? { noExternal: cfg.ssrNoExternal } : void 0
602
+ // `@fluixi/core` always goes through vite rather than being externalized.
603
+ // `@fluixi/core/routes` is served by fluixiRoutesPlugin, and an externalized
604
+ // dependency is imported by node directly, so no plugin ever sees the specifier and
605
+ // the app gets the "did not replace it" stub instead of its route tree. A workspace
606
+ // app hides this by resolving the package to source.
607
+ ssr: { noExternal: ["@fluixi/core", ...cfg.ssrNoExternal] }
596
608
  });
597
609
  http.listen(cfg.port, () => devReady({ port: cfg.port, startedAt }));
598
610
  }
@@ -701,14 +713,14 @@ var nodeAdapter = {
701
713
  };
702
714
  var GENERATED_SUBPATHS = /* @__PURE__ */ new Set(["./routes", "./server-fns", "./api-routes"]);
703
715
  function ssrBuildOptions(cfg) {
704
- const noExternal = cfg.ssrNoExternal.length ? cfg.ssrNoExternal : void 0;
716
+ const noExternal = [.../* @__PURE__ */ new Set(["@fluixi/core", ...cfg.ssrNoExternal])];
705
717
  const mode = cfg.adapter?.bundle;
706
718
  if (mode === "inline") return { noExternal: true };
707
719
  if (mode !== "external") return { noExternal };
708
720
  const external = frameworkDeps(cfg.root).filter((name) => !cfg.ssrNoExternal.includes(name)).flatMap((name) => withSubpaths(cfg.root, name));
709
721
  if (!external.length) {
710
722
  console.warn(
711
- ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${join2(cfg.root, "package.json")} bundling everything.`
723
+ ` fluixi: adapter "${cfg.adapter?.name}" builds an externalized server, but no fluixi or @fluixi/* dependency was found in ${join2(cfg.root, "package.json")}, bundling everything.`
712
724
  );
713
725
  }
714
726
  return { noExternal, external: external.length ? external : void 0 };
@@ -934,7 +946,7 @@ async function bundleEntry(cfg, plugins, source, outFile) {
934
946
  output: {
935
947
  entryFileNames: basename(outFile),
936
948
  // One file, no chunks. A lazy route would otherwise be split out beside
937
- // the entry and for Cloudflare that directory is the published one, so
949
+ // the entry: and for Cloudflare that directory is the published one, so
938
950
  // every server chunk would be a public download.
939
951
  inlineDynamicImports: true
940
952
  }
@@ -45,6 +45,8 @@ function resolveConfig(config = {}) {
45
45
  middleware: config.middleware ?? "src/middleware.ts",
46
46
  ssrNoExternal: config.ssrNoExternal ?? [],
47
47
  resolve: config.resolve ?? [],
48
+ vitePlugin: config.vitePlugin ?? {},
49
+ plugins: config.plugins ?? [],
48
50
  adapter: config.adapter,
49
51
  i18n: resolveI18n(config.i18n),
50
52
  prerender: resolvePrerender(config.prerender)
@@ -2,7 +2,7 @@ import type { FluixiConfig } from '../config.js';
2
2
  export declare function htmlPath(url: string): string;
3
3
  export declare function extractLinks(html: string): string[];
4
4
  /**
5
- * Render routes to static HTML in dist/client, via the real prod handler so each page is
5
+ * Render routes to static HTML in dist/client, via the real prod handler, so each page is
6
6
  * byte-identical to what `fluixi start` would serve (assets, __FX_DATA__, hydration), it just
7
7
  * lives on disk. Seeds from `prerender.routes` (default `/`) and, when `crawl`, follows internal
8
8
  * links. Returns the written route paths.
@@ -8,7 +8,7 @@ export function htmlPath(url) {
8
8
  const clean = url.split(/[?#]/)[0].replace(/\/+$/, '');
9
9
  return clean === '' ? 'index.html' : `${clean.replace(/^\//, '')}/index.html`;
10
10
  }
11
- // internal links from rendered HTML skip files (.js/.css/…), anchors, queries, external
11
+ // internal links from rendered HTML: skip files (.js/.css/…), anchors, queries, external
12
12
  export function extractLinks(html) {
13
13
  const out = new Set();
14
14
  for (const m of html.matchAll(/href=["'](\/[^"'#?]*)["']/g)) {
@@ -24,7 +24,7 @@ const norm = (u) => {
24
24
  return p || '/';
25
25
  };
26
26
  /**
27
- * Render routes to static HTML in dist/client, via the real prod handler so each page is
27
+ * Render routes to static HTML in dist/client, via the real prod handler, so each page is
28
28
  * byte-identical to what `fluixi start` would serve (assets, __FX_DATA__, hydration), it just
29
29
  * lives on disk. Seeds from `prerender.routes` (default `/`) and, when `crawl`, follows internal
30
30
  * links. Returns the written route paths.
@@ -19,6 +19,8 @@ function resolveConfig(config = {}) {
19
19
  middleware: config.middleware ?? "src/middleware.ts",
20
20
  ssrNoExternal: config.ssrNoExternal ?? [],
21
21
  resolve: config.resolve ?? [],
22
+ vitePlugin: config.vitePlugin ?? {},
23
+ plugins: config.plugins ?? [],
22
24
  adapter: config.adapter,
23
25
  i18n: resolveI18n(config.i18n),
24
26
  prerender: resolvePrerender(config.prerender)
@@ -52,6 +52,8 @@ function resolveConfig(config = {}) {
52
52
  middleware: config.middleware ?? "src/middleware.ts",
53
53
  ssrNoExternal: config.ssrNoExternal ?? [],
54
54
  resolve: config.resolve ?? [],
55
+ vitePlugin: config.vitePlugin ?? {},
56
+ plugins: config.plugins ?? [],
55
57
  adapter: config.adapter,
56
58
  i18n: resolveI18n(config.i18n),
57
59
  prerender: resolvePrerender(config.prerender)
@@ -3,7 +3,7 @@ import type { FluixiConfig } from '../config.js';
3
3
  * Production server: build the runtime-neutral SSR fetch handler from the `fluixi
4
4
  * build` output and serve it via the Node adapter (static files from dist/client +
5
5
  * SSR for everything else). Other runtimes (edge/Bun/Deno) use the same
6
- * `createProdHandler` with their own adapter `export default { fetch }`.
6
+ * `createProdHandler` with their own adapter: `export default { fetch }`.
7
7
  */
8
8
  export declare function start(config?: FluixiConfig): Promise<void>;
9
9
  //# sourceMappingURL=start.d.ts.map
@@ -6,7 +6,7 @@ import { createProdHandler, nodeAdapter } from '../adapter.js';
6
6
  * Production server: build the runtime-neutral SSR fetch handler from the `fluixi
7
7
  * build` output and serve it via the Node adapter (static files from dist/client +
8
8
  * SSR for everything else). Other runtimes (edge/Bun/Deno) use the same
9
- * `createProdHandler` with their own adapter `export default { fetch }`.
9
+ * `createProdHandler` with their own adapter: `export default { fetch }`.
10
10
  */
11
11
  export async function start(config = {}) {
12
12
  const cfg = resolveConfig(config);
@@ -15,7 +15,7 @@ export async function start(config = {}) {
15
15
  const clientDir = resolve(cfg.root, 'dist/client');
16
16
  const handler = await createProdHandler(cfg);
17
17
  // The configured adapter, or node when there is none. An adapter that returns
18
- // `{ fetch }` has no process to run its output is a module the platform imports
18
+ // `{ fetch }` has no process to run: its output is a module the platform imports ,
19
19
  // so say that instead of exiting as if the server had started.
20
20
  const adapter = cfg.adapter ?? nodeAdapter;
21
21
  const served = await adapter.serve({ handler, cfg, clientDir });
@@ -18,6 +18,8 @@ function resolveConfig(config = {}) {
18
18
  middleware: config.middleware ?? "src/middleware.ts",
19
19
  ssrNoExternal: config.ssrNoExternal ?? [],
20
20
  resolve: config.resolve ?? [],
21
+ vitePlugin: config.vitePlugin ?? {},
22
+ plugins: config.plugins ?? [],
21
23
  adapter: config.adapter,
22
24
  i18n: resolveI18n(config.i18n),
23
25
  prerender: resolvePrerender(config.prerender)
package/dist/config.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! @fluixi/start v0.1.0-alpha.74 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/start v0.1.0-alpha.76 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -40,9 +40,13 @@ var import_node_url = require("node:url");
40
40
  var import_node_fs = require("node:fs");
41
41
  var import_promises = require("node:fs/promises");
42
42
  var import_node_path = require("node:path");
43
+
44
+ // src/define-config.ts
43
45
  function defineConfig(config) {
44
46
  return config;
45
47
  }
48
+
49
+ // src/config.ts
46
50
  function resolveConfig(config = {}) {
47
51
  const root = (0, import_node_path.resolve)(config.root ?? process.cwd());
48
52
  return {
@@ -58,6 +62,8 @@ function resolveConfig(config = {}) {
58
62
  middleware: config.middleware ?? "src/middleware.ts",
59
63
  ssrNoExternal: config.ssrNoExternal ?? [],
60
64
  resolve: config.resolve ?? [],
65
+ vitePlugin: config.vitePlugin ?? {},
66
+ plugins: config.plugins ?? [],
61
67
  adapter: config.adapter,
62
68
  i18n: resolveI18n(config.i18n),
63
69
  prerender: resolvePrerender(config.prerender)