@noego/forge 0.0.10 → 0.0.12

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 (54) hide show
  1. package/dist/client.cjs +1 -1
  2. package/dist/client.cjs.map +1 -1
  3. package/dist/client.mjs +224 -219
  4. package/dist/client.mjs.map +1 -1
  5. package/dist/options/ServerOptions.cjs +28 -0
  6. package/dist/options/ServerOptions.cjs.map +1 -0
  7. package/dist/options/ServerOptions.d.ts +19 -0
  8. package/dist/options/ServerOptions.mjs +21 -0
  9. package/dist/options/ServerOptions.mjs.map +1 -0
  10. package/dist/options/assets.cjs +42 -0
  11. package/dist/options/assets.cjs.map +1 -0
  12. package/dist/options/assets.d.ts +46 -0
  13. package/dist/options/assets.mjs +38 -0
  14. package/dist/options/assets.mjs.map +1 -0
  15. package/dist/plugins/serverOnlyStub.d.ts +6 -0
  16. package/dist/plugins-cjs/index.plugins.js +9 -0
  17. package/dist/plugins-cjs/index.plugins.js.map +1 -0
  18. package/dist/plugins-cjs/options/ServerOptions.js +28 -0
  19. package/dist/plugins-cjs/options/ServerOptions.js.map +1 -0
  20. package/dist/plugins-cjs/options/assets.js +42 -0
  21. package/dist/plugins-cjs/options/assets.js.map +1 -0
  22. package/dist/plugins-cjs/plugins/serverOnlyStub.js +226 -0
  23. package/dist/plugins-cjs/plugins/serverOnlyStub.js.map +1 -0
  24. package/dist/plugins-cjs/routing/html_render/html_render.js +62 -0
  25. package/dist/plugins-cjs/routing/html_render/html_render.js.map +1 -0
  26. package/dist/plugins-cjs/stubs/server-only.js +10 -0
  27. package/dist/plugins-cjs/stubs/server-only.js.map +1 -0
  28. package/dist/plugins-es/index.plugins.d.ts +2 -0
  29. package/dist/plugins-es/index.plugins.js +2 -0
  30. package/dist/plugins-es/index.plugins.js.map +1 -0
  31. package/dist/plugins-es/options/ServerOptions.d.ts +19 -0
  32. package/dist/plugins-es/options/ServerOptions.js +21 -0
  33. package/dist/plugins-es/options/ServerOptions.js.map +1 -0
  34. package/dist/plugins-es/options/assets.d.ts +46 -0
  35. package/dist/plugins-es/options/assets.js +38 -0
  36. package/dist/plugins-es/options/assets.js.map +1 -0
  37. package/dist/plugins-es/plugins/serverOnlyStub.d.ts +6 -0
  38. package/dist/plugins-es/plugins/serverOnlyStub.js +200 -0
  39. package/dist/plugins-es/plugins/serverOnlyStub.js.map +1 -0
  40. package/dist/plugins-es/routing/html_render/html_render.d.ts +19 -0
  41. package/dist/plugins-es/routing/html_render/html_render.js +53 -0
  42. package/dist/plugins-es/routing/html_render/html_render.js.map +1 -0
  43. package/dist/plugins-es/stubs/server-only.d.ts +3 -0
  44. package/dist/plugins-es/stubs/server-only.js +7 -0
  45. package/dist/plugins-es/stubs/server-only.js.map +1 -0
  46. package/dist/routing/html_render/html_render.d.ts +19 -0
  47. package/dist/routing/html_render/html_render.js +53 -0
  48. package/dist/routing/html_render/html_render.js.map +1 -0
  49. package/dist-ssr/server.cjs +179 -23
  50. package/dist-ssr/server.cjs.map +1 -1
  51. package/dist-ssr/server.js +179 -23
  52. package/dist-ssr/server.js.map +1 -1
  53. package/package.json +11 -4
  54. package/src/components/RecursiveRender.svelte +55 -14
@@ -3,18 +3,17 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import express from "express";
5
5
  import path from "path";
6
- import deepmerge from "deepmerge";
7
6
  import fs from "fs";
7
+ import deepmerge from "deepmerge";
8
+ import { pathToFileURL } from "url";
8
9
  import Handlebars from "handlebars";
9
10
  import fs$1 from "fs/promises";
10
11
  import yaml from "js-yaml";
11
12
  import "clone-deep";
12
13
  import join from "url-join";
13
14
  import { p as parsePathConfig } from "./path-BqcF5dbs.js";
14
- import { pathToFileURL } from "url";
15
15
  import { render } from "svelte/server";
16
16
  import pathToRegex from "path-to-regex";
17
- import ApplicationRenderer from "../src/components/RecursiveRender.svelte";
18
17
  class ViteComponentLoader {
19
18
  constructor(basePath, vite) {
20
19
  this.basePath = basePath;
@@ -33,6 +32,19 @@ class ViteComponentLoader {
33
32
  }
34
33
  }
35
34
  console.log(`[ViteComponentLoader] Loading component from path: ${absoluteComponentPath}`);
35
+ const jsPath = absoluteComponentPath.replace(/\.svelte$/, ".js");
36
+ const jsExists = fs.existsSync(jsPath);
37
+ if (jsExists) {
38
+ console.log(`[ViteComponentLoader] Found precompiled component at: ${jsPath}`);
39
+ try {
40
+ const module = await import(jsPath);
41
+ console.log(`[ViteComponentLoader] Loaded precompiled module successfully`);
42
+ return module;
43
+ } catch (error) {
44
+ console.error(`[ViteComponentLoader] Error loading precompiled module from ${jsPath}`, error);
45
+ throw error;
46
+ }
47
+ }
36
48
  let vitePath = path.relative(process.cwd(), absoluteComponentPath);
37
49
  vitePath = vitePath.replace(/\\/g, "/");
38
50
  if (!vitePath.startsWith("/")) {
@@ -60,13 +72,58 @@ class ViteComponentLoader {
60
72
  }
61
73
  class ProdComponentLoader {
62
74
  constructor(base_path) {
75
+ __publicField(this, "componentMapPromise", null);
63
76
  this.base_path = base_path;
64
77
  }
65
78
  async load(componentPath) {
79
+ const normalized = this.normalizeKey(componentPath);
80
+ try {
81
+ const map = await this.loadComponentMap();
82
+ const module2 = map[normalized];
83
+ if (module2) {
84
+ return module2;
85
+ }
86
+ } catch (error) {
87
+ console.warn(`[Forge] Failed to load component "${componentPath}" from entry manifest:`, error);
88
+ }
66
89
  const component_path = path.join(this.base_path, componentPath);
67
- const module = await import(component_path.replace(/\.svelte$/, ".js"));
90
+ const fallbackPath = component_path.endsWith(".js") ? component_path : component_path.replace(/\.svelte$/, ".js");
91
+ const module = await import(pathToFileURL(fallbackPath).href);
68
92
  return module;
69
93
  }
94
+ normalizeKey(componentPath) {
95
+ const trimmed = componentPath.replace(/^\.\//, "");
96
+ if (trimmed.endsWith(".svelte")) {
97
+ return trimmed.replace(/\.svelte$/, ".js");
98
+ }
99
+ return trimmed;
100
+ }
101
+ async loadComponentMap() {
102
+ if (!this.componentMapPromise) {
103
+ const entryPath = path.join(this.base_path, "entry-ssr.js");
104
+ const entryUrl = pathToFileURL(entryPath).href;
105
+ this.componentMapPromise = import(entryUrl).then((mod) => {
106
+ const source = mod.components ?? mod.default ?? {};
107
+ const normalized = {};
108
+ for (const [key, value] of Object.entries(source)) {
109
+ const cleanKey = key.replace(/^\.\//, "");
110
+ normalized[cleanKey] = value;
111
+ if (cleanKey.startsWith("ui/")) {
112
+ normalized[cleanKey.slice(3)] = value;
113
+ }
114
+ if (cleanKey.endsWith(".svelte")) {
115
+ const jsKey = cleanKey.replace(/\.svelte$/, ".js");
116
+ normalized[jsKey] = value;
117
+ }
118
+ }
119
+ return normalized;
120
+ }).catch((error) => {
121
+ this.componentMapPromise = null;
122
+ throw error;
123
+ });
124
+ }
125
+ return this.componentMapPromise;
126
+ }
70
127
  }
71
128
  const default_template = `
72
129
  <!DOCTYPE html>
@@ -257,11 +314,9 @@ async function parse_openapi_config(openapi_config_path) {
257
314
  const defaultViteOptions = {
258
315
  appType: "custom",
259
316
  root: process.cwd(),
260
- // Explicitly set root
261
317
  server: { middlewareMode: true },
262
318
  ssr: {
263
319
  noExternal: ["svelte", /^svelte\/.*/]
264
- // Adjust if needed, maybe add your component specifically if still failing
265
320
  }
266
321
  };
267
322
  const defaultOptions = {
@@ -611,17 +666,57 @@ function initialize_route_matchers(routes) {
611
666
  class ServerAdapter {
612
667
  }
613
668
  class ExpressServerAdapter extends ServerAdapter {
614
- constructor(server, manager, htmlRender, api_adapter, middleware_adapter, context_builder) {
669
+ constructor(server, manager, htmlRender, api_adapter, middleware_adapter, context_builder, isProd = false, componentDir) {
615
670
  super();
671
+ __publicField(this, "clientRoutes", []);
616
672
  this.server = server;
617
673
  this.manager = manager;
618
674
  this.htmlRender = htmlRender;
619
675
  this.api_adapter = api_adapter;
620
676
  this.middleware_adapter = middleware_adapter;
621
677
  this.context_builder = context_builder;
678
+ this.isProd = isProd;
679
+ this.componentDir = componentDir;
680
+ }
681
+ async loadApplicationRenderer(componentRoot) {
682
+ if (!this.isProd) {
683
+ const mod = await import("../src/components/RecursiveRender.svelte");
684
+ return mod.default ?? mod;
685
+ }
686
+ const candidates = [
687
+ path.join(componentRoot, "RecursiveRender.js"),
688
+ path.join(componentRoot, "ssr", "RecursiveRender.js")
689
+ ];
690
+ let lastError;
691
+ for (const fp of candidates) {
692
+ try {
693
+ const mod = await import(fp);
694
+ return mod.default ?? mod;
695
+ } catch (e) {
696
+ lastError = e;
697
+ }
698
+ }
699
+ throw lastError ?? new Error("Unable to locate precompiled RecursiveRender.js");
700
+ }
701
+ transformRoutesForClient(routes) {
702
+ var _a, _b;
703
+ if (!this.isProd) return routes;
704
+ console.log(`[transformRoutesForClient] Transforming ${routes.length} routes for production`);
705
+ const transformed = routes.map((route) => {
706
+ var _a2, _b2;
707
+ return {
708
+ ...route,
709
+ layout: (_a2 = route.layout) == null ? void 0 : _a2.map((path2) => path2.replace(/\.svelte$/, ".js")),
710
+ view: (_b2 = route.view) == null ? void 0 : _b2.replace(/\.svelte$/, ".js")
711
+ };
712
+ });
713
+ console.log(`[transformRoutesForClient] First route view transformed: ${(_a = routes[0]) == null ? void 0 : _a.view} → ${(_b = transformed[0]) == null ? void 0 : _b.view}`);
714
+ return transformed;
622
715
  }
623
716
  async handleRoutes(routes, manifest) {
624
- const matchers = initialize_route_matchers(routes);
717
+ const transformedRoutes = this.transformRoutesForClient(routes);
718
+ this.clientRoutes = transformedRoutes;
719
+ const matchers = initialize_route_matchers(transformedRoutes);
625
720
  this.server.use((req, res, next) => {
626
721
  (async () => {
627
722
  if (res.headersSent) {
@@ -638,13 +733,13 @@ class ExpressServerAdapter extends ServerAdapter {
638
733
  await not_found();
639
734
  return;
640
735
  }
641
- const route_options = routes.filter((r) => r.path === matcher.pattern);
736
+ const route_options = transformedRoutes.filter((r) => r.path === matcher.pattern);
642
737
  const route = route_options.find((r) => r.method.toLowerCase() === method);
643
738
  if (!route) {
644
739
  await not_found();
645
740
  return;
646
741
  }
647
- await this.handleResponse(fullUrl, matcher, route, routes, manifest, req, res).catch((e) => {
742
+ await this.handleResponse(fullUrl, matcher, route, transformedRoutes, manifest, req, res).catch((e) => {
648
743
  res.status(500).send(`
649
744
  <h1>500 Internal Server Error</h1>
650
745
  <pre>${e}</pre>
@@ -655,7 +750,7 @@ class ExpressServerAdapter extends ServerAdapter {
655
750
  });
656
751
  }
657
752
  async handleResponse(url, matcher, route, routes, manifest, req, res) {
658
- var _a, _b;
753
+ var _a, _b, _c;
659
754
  let accepts = req.headers.accept || "";
660
755
  let server_api_call = accepts.toLowerCase().includes("application/json");
661
756
  if (res.headersSent) {
@@ -729,7 +824,12 @@ ${e.stack}</pre>
729
824
  params: request_data.params || {},
730
825
  query: request_data.query
731
826
  };
732
- let { head: head_render, body: body_render, css } = render(ApplicationRenderer, {
827
+ console.log("[SSR DEBUG] layouts:", layouts.map((l) => typeof l), "view:", typeof view);
828
+ const loader = ((_a = this.manager) == null ? void 0 : _a["componentLoader"]) || {};
829
+ const componentRoot = loader["base_path"] || loader["basePath"] || "";
830
+ const applicationRenderer = await this.loadApplicationRenderer(componentRoot);
831
+ console.log("[SSR DEBUG] applicationRenderer:", typeof applicationRenderer);
832
+ const { head: head_render, html: renderedHtml, css } = render(applicationRenderer, {
733
833
  props: {
734
834
  layouts,
735
835
  view,
@@ -740,9 +840,12 @@ ${e.stack}</pre>
740
840
  page
741
841
  }
742
842
  });
843
+ const body_render = renderedHtml;
844
+ console.log("[SSR DEBUG] render result - body length:", (body_render == null ? void 0 : body_render.length) || 0);
845
+ const clientComponentDir = this.isProd ? "assets" : this.componentDir;
743
846
  const head_routing = `
744
847
  <script type='text/javascript'>
745
- window.__ROUTING__ = ${JSON.stringify(routes)}
848
+ window.__ROUTING__ = ${JSON.stringify(this.clientRoutes)}
746
849
  <\/script>
747
850
 
748
851
  <script type='text/javascript'>
@@ -752,16 +855,22 @@ ${e.stack}</pre>
752
855
  <script type='text/javascript'>
753
856
  window.__INITIAL_DATA__ = ${JSON.stringify(server_data || {}).trim()}
754
857
  <\/script>
858
+
859
+ <script type='text/javascript'>
860
+ window.__COMPONENT_DIR__ = ${JSON.stringify(clientComponentDir)}
861
+ <\/script>
755
862
  `;
863
+ console.log("[SSR DEBUG] About to render HTML with APP length:", (body_render == null ? void 0 : body_render.length) || 0);
756
864
  html_render = await this.htmlRender.renderHTML({
757
865
  HEAD: head_routing + (head_render || ""),
758
866
  CSS: css,
759
867
  APP: body_render
760
868
  });
869
+ console.log("[SSR DEBUG] Final HTML length:", (html_render == null ? void 0 : html_render.length) || 0, "contains APP div:", html_render == null ? void 0 : html_render.includes('<div id="app">'));
761
870
  } catch (e) {
762
871
  response_code = 500;
763
872
  const new_body = `<pre>Error rendering HTML:
764
- ${e}` + (((_a = route.layout) == null ? void 0 : _a.length) ? `layouts: ${(_b = route.layout) == null ? void 0 : _b.join(",\n")}` : "") + `
873
+ ${e}` + (((_b = route.layout) == null ? void 0 : _b.length) ? `layouts: ${(_c = route.layout) == null ? void 0 : _c.join(",\n")}` : "") + `
765
874
  view: ${route.view}</pre>`;
766
875
  html_render = await this.htmlRender.renderHTML({
767
876
  APP: new_body
@@ -773,6 +882,7 @@ view: ${route.view}</pre>`;
773
882
  res.end(html_render);
774
883
  }
775
884
  async handleFallback(req, res, server_config) {
885
+ var _a;
776
886
  if (res.headersSent) {
777
887
  console.log("Reply already sent");
778
888
  return;
@@ -813,7 +923,10 @@ view: ${route.view}</pre>`;
813
923
  const view = await this.manager.getView(route);
814
924
  console.log("Fallback view", view);
815
925
  console.log("Fallback layouts", layouts);
816
- let { head: head_render, body: body_render, css } = render(ApplicationRenderer, {
926
+ const loader = ((_a = this.manager) == null ? void 0 : _a["componentLoader"]) || {};
927
+ const componentRoot = loader["base_path"] || loader["basePath"] || "";
928
+ const applicationRenderer = await this.loadApplicationRenderer(componentRoot);
929
+ let { head: head_render, html, css } = render(applicationRenderer, {
817
930
  props: {
818
931
  layouts,
819
932
  view,
@@ -821,6 +934,7 @@ view: ${route.view}</pre>`;
821
934
  params: request_data.params
822
935
  }
823
936
  });
937
+ const body_render = html;
824
938
  const html_render = await this.htmlRender.renderHTML({
825
939
  HEAD: head_render,
826
940
  CSS: css,
@@ -829,21 +943,53 @@ view: ${route.view}</pre>`;
829
943
  res.type("text/html").status(404).send(html_render);
830
944
  }
831
945
  }
946
+ function pathExistsSync(p) {
947
+ try {
948
+ return fs.existsSync(p);
949
+ } catch {
950
+ return false;
951
+ }
952
+ }
953
+ function resolveRuntimeRoot(candidate) {
954
+ var _a;
955
+ const envRoot = process.env.FORGE_ROOT;
956
+ if (envRoot && path.isAbsolute(envRoot) && pathExistsSync(envRoot)) {
957
+ return path.normalize(envRoot);
958
+ }
959
+ if (candidate && path.isAbsolute(candidate) && pathExistsSync(candidate)) {
960
+ return path.normalize(candidate);
961
+ }
962
+ const entry = (_a = process.argv) == null ? void 0 : _a[1];
963
+ if (entry) {
964
+ const entryDir = path.dirname(path.resolve(entry));
965
+ if (pathExistsSync(entryDir)) return entryDir;
966
+ }
967
+ return process.cwd();
968
+ }
832
969
  async function createServer(app, options) {
970
+ var _a;
833
971
  options = options || defaultOptions;
834
972
  const full_options = deepmerge(defaultOptions, options);
835
973
  full_options.open_api_path = ensureFullPath(full_options.viteOptions.root, full_options.open_api_path);
836
- const isProd = full_options.development === false;
837
- console.log(`Running in ${isProd ? "production" : "development"} mode`);
838
- const COMPONENT_DIR = !full_options.component_dir ? full_options.viteOptions.root : path.join(full_options.viteOptions.root, full_options.component_dir);
839
- const root = full_options.viteOptions.root;
974
+ const root = resolveRuntimeRoot((_a = full_options.viteOptions) == null ? void 0 : _a.root);
975
+ const COMPONENT_DIR = !full_options.component_dir ? root : path.join(root, full_options.component_dir);
976
+ const isBuiltEnvironment = process.env.FORGE_BUILT === "true";
977
+ const isProd = isBuiltEnvironment || full_options.development === false;
978
+ console.log(`Running in ${isProd ? "production" : "development"} mode (built environment: ${isBuiltEnvironment}, development flag: ${full_options.development}, NODE_ENV: ${process.env.NODE_ENV})`);
840
979
  let componentLoader;
841
980
  let vite;
842
981
  console.log(`Serving components from ${COMPONENT_DIR}`);
982
+ const rendererFullPath = typeof full_options.renderer === "string" && full_options.renderer !== "default" ? ensureFullPath(root, full_options.renderer) : ensureFullPath(root, "index.html");
983
+ path.dirname(rendererFullPath);
984
+ const resolveAssetRoot = (entry) => {
985
+ if (!entry || typeof entry !== "string") return root;
986
+ const cleaned = entry.replace(/^\/+/, "");
987
+ return path.resolve(root, cleaned);
988
+ };
843
989
  if (full_options.assets) {
844
990
  for (const [asset_path, asset_dir] of Object.entries(full_options.assets)) {
845
991
  for (const asset of asset_dir) {
846
- const asset_root = path.join(full_options.viteOptions.root, asset);
992
+ const asset_root = resolveAssetRoot(asset);
847
993
  app.use(asset_path, express.static(asset_root));
848
994
  console.log(`Serving assets from ${asset_root} at ${asset_path}`);
849
995
  }
@@ -860,8 +1006,16 @@ ${JSON.stringify(options, null, 2)}`);
860
1006
  componentLoader = new ViteComponentLoader(COMPONENT_DIR, vite);
861
1007
  } else {
862
1008
  console.log("Starting Vite in production mode...");
863
- app.use("/", express.static(path.join(full_options.viteOptions.root, full_options.build_dir)));
864
- console.log(`Serving static files from ${path.join(full_options.viteOptions.root, full_options.build_dir)} at /`);
1009
+ const staticDir = path.join(full_options.viteOptions.root, full_options.build_dir);
1010
+ if (pathExistsSync(staticDir)) {
1011
+ app.use("/", express.static(staticDir));
1012
+ console.log(`Serving static files from ${staticDir} at /`);
1013
+ } else {
1014
+ console.log(`Skipping static file serving (build_dir ${staticDir} not found - using asset configuration)`);
1015
+ }
1016
+ const componentPath = `/${full_options.component_dir}`;
1017
+ app.use(componentPath, express.static(COMPONENT_DIR));
1018
+ console.log(`Serving components at ${componentPath} from ${COMPONENT_DIR}`);
865
1019
  componentLoader = new ProdComponentLoader(COMPONENT_DIR);
866
1020
  }
867
1021
  const manifest = await new ManifestBuilder(
@@ -885,7 +1039,9 @@ ${JSON.stringify(options, null, 2)}`);
885
1039
  htmlRenderer,
886
1040
  api_adapter,
887
1041
  middleware_adapter,
888
- full_options.context_builder
1042
+ full_options.context_builder,
1043
+ isProd,
1044
+ full_options.component_dir
889
1045
  );
890
1046
  await adapter.handleRoutes(routeDefs, manifest);
891
1047
  console.log("Routes registered");