@nuraly/lumenjs 0.1.3 → 0.2.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.
Files changed (306) hide show
  1. package/README.md +62 -282
  2. package/dist/auth/config.d.ts +23 -0
  3. package/dist/auth/config.js +115 -0
  4. package/dist/auth/guard.d.ts +12 -0
  5. package/dist/auth/guard.js +28 -0
  6. package/dist/auth/index.d.ts +3 -0
  7. package/dist/auth/index.js +1 -0
  8. package/dist/auth/middleware.d.ts +23 -0
  9. package/dist/auth/middleware.js +89 -0
  10. package/dist/auth/native-auth.d.ts +82 -0
  11. package/dist/auth/native-auth.js +340 -0
  12. package/dist/auth/oidc-client.d.ts +17 -0
  13. package/dist/auth/oidc-client.js +123 -0
  14. package/dist/auth/providers/google.d.ts +23 -0
  15. package/dist/auth/providers/google.js +25 -0
  16. package/dist/auth/providers/index.d.ts +2 -0
  17. package/dist/auth/providers/index.js +1 -0
  18. package/dist/auth/routes/login.d.ts +8 -0
  19. package/dist/auth/routes/login.js +121 -0
  20. package/dist/auth/routes/logout.d.ts +4 -0
  21. package/dist/auth/routes/logout.js +79 -0
  22. package/dist/auth/routes/oidc-callback.d.ts +3 -0
  23. package/dist/auth/routes/oidc-callback.js +70 -0
  24. package/dist/auth/routes/password.d.ts +5 -0
  25. package/dist/auth/routes/password.js +149 -0
  26. package/dist/auth/routes/signup.d.ts +3 -0
  27. package/dist/auth/routes/signup.js +81 -0
  28. package/dist/auth/routes/token.d.ts +4 -0
  29. package/dist/auth/routes/token.js +70 -0
  30. package/dist/auth/routes/totp.d.ts +22 -0
  31. package/dist/auth/routes/totp.js +232 -0
  32. package/dist/auth/routes/utils.d.ts +7 -0
  33. package/dist/auth/routes/utils.js +35 -0
  34. package/dist/auth/routes/verify.d.ts +3 -0
  35. package/dist/auth/routes/verify.js +26 -0
  36. package/dist/auth/routes.d.ts +8 -0
  37. package/dist/auth/routes.js +124 -0
  38. package/dist/auth/session.d.ts +8 -0
  39. package/dist/auth/session.js +54 -0
  40. package/dist/auth/token.d.ts +33 -0
  41. package/dist/auth/token.js +90 -0
  42. package/dist/auth/types.d.ts +156 -0
  43. package/dist/auth/types.js +2 -0
  44. package/dist/build/build-client.d.ts +15 -0
  45. package/dist/build/build-client.js +45 -0
  46. package/dist/build/build-prerender.d.ts +11 -0
  47. package/dist/build/build-prerender.js +159 -0
  48. package/dist/build/build-server.d.ts +18 -0
  49. package/dist/build/build-server.js +107 -0
  50. package/dist/build/build.js +60 -123
  51. package/dist/build/scan.d.ts +18 -0
  52. package/dist/build/scan.js +77 -6
  53. package/dist/build/serve-api.js +8 -2
  54. package/dist/build/serve-loaders.d.ts +4 -4
  55. package/dist/build/serve-loaders.js +26 -18
  56. package/dist/build/serve-ssr.js +38 -11
  57. package/dist/build/serve-static.js +3 -3
  58. package/dist/build/serve.js +341 -18
  59. package/dist/cli.js +37 -6
  60. package/dist/communication/encryption.d.ts +35 -0
  61. package/dist/communication/encryption.js +90 -0
  62. package/dist/communication/handlers/context.d.ts +27 -0
  63. package/dist/communication/handlers/context.js +1 -0
  64. package/dist/communication/handlers/conversation.d.ts +24 -0
  65. package/dist/communication/handlers/conversation.js +113 -0
  66. package/dist/communication/handlers/file-upload.d.ts +17 -0
  67. package/dist/communication/handlers/file-upload.js +62 -0
  68. package/dist/communication/handlers/messaging.d.ts +30 -0
  69. package/dist/communication/handlers/messaging.js +237 -0
  70. package/dist/communication/handlers/presence.d.ts +15 -0
  71. package/dist/communication/handlers/presence.js +76 -0
  72. package/dist/communication/handlers.d.ts +5 -0
  73. package/dist/communication/handlers.js +5 -0
  74. package/dist/communication/index.d.ts +9 -0
  75. package/dist/communication/index.js +7 -0
  76. package/dist/communication/link-preview.d.ts +18 -0
  77. package/dist/communication/link-preview.js +115 -0
  78. package/dist/communication/schema.d.ts +10 -0
  79. package/dist/communication/schema.js +101 -0
  80. package/dist/communication/server.d.ts +86 -0
  81. package/dist/communication/server.js +212 -0
  82. package/dist/communication/signaling.d.ts +43 -0
  83. package/dist/communication/signaling.js +271 -0
  84. package/dist/communication/store.d.ts +71 -0
  85. package/dist/communication/store.js +289 -0
  86. package/dist/communication/types.d.ts +454 -0
  87. package/dist/communication/types.js +1 -0
  88. package/dist/create.d.ts +1 -0
  89. package/dist/create.js +55 -0
  90. package/dist/db/auto-migrate.d.ts +3 -0
  91. package/dist/db/auto-migrate.js +100 -0
  92. package/dist/db/client.d.ts +3 -0
  93. package/dist/db/client.js +18 -0
  94. package/dist/db/index.d.ts +17 -13
  95. package/dist/db/index.js +205 -26
  96. package/dist/db/seed.d.ts +12 -0
  97. package/dist/db/seed.js +88 -0
  98. package/dist/db/table.d.ts +10 -0
  99. package/dist/db/table.js +12 -0
  100. package/dist/dev-server/config.d.ts +11 -0
  101. package/dist/dev-server/config.js +40 -20
  102. package/dist/dev-server/index-html.d.ts +4 -0
  103. package/dist/dev-server/index-html.js +21 -6
  104. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  105. package/dist/dev-server/nuralyui-aliases.js +115 -94
  106. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  107. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  108. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  109. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  110. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  111. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  113. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  114. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  115. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  116. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  117. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  118. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  119. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  120. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  121. package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
  122. package/dist/dev-server/plugins/vite-plugin-routes.js +16 -5
  123. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  124. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  125. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  127. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  128. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  129. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +140 -3
  130. package/dist/dev-server/server.js +242 -70
  131. package/dist/dev-server/ssr-render.d.ts +2 -1
  132. package/dist/dev-server/ssr-render.js +117 -50
  133. package/dist/editor/ai/backend.d.ts +20 -0
  134. package/dist/editor/ai/backend.js +113 -0
  135. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  136. package/dist/editor/ai/claude-code-client.js +145 -0
  137. package/dist/editor/ai/deepseek-client.d.ts +7 -0
  138. package/dist/editor/ai/deepseek-client.js +113 -0
  139. package/dist/editor/ai/opencode-client.d.ts +14 -0
  140. package/dist/editor/ai/opencode-client.js +99 -0
  141. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  142. package/dist/editor/ai/snapshot-store.js +35 -0
  143. package/dist/editor/ai/types.d.ts +30 -0
  144. package/dist/editor/ai/types.js +136 -0
  145. package/dist/editor/ai-chat-panel.d.ts +13 -0
  146. package/dist/editor/ai-chat-panel.js +613 -0
  147. package/dist/editor/ai-markdown.d.ts +10 -0
  148. package/dist/editor/ai-markdown.js +70 -0
  149. package/dist/editor/ai-project-panel.d.ts +11 -0
  150. package/dist/editor/ai-project-panel.js +332 -0
  151. package/dist/editor/ast-modification.d.ts +11 -0
  152. package/dist/editor/ast-modification.js +1 -0
  153. package/dist/editor/ast-service.d.ts +30 -0
  154. package/dist/editor/ast-service.js +180 -0
  155. package/dist/editor/css-rules.d.ts +54 -0
  156. package/dist/editor/css-rules.js +423 -0
  157. package/dist/editor/editor-api-client.d.ts +51 -0
  158. package/dist/editor/editor-api-client.js +162 -0
  159. package/dist/editor/editor-bridge.d.ts +1 -0
  160. package/dist/editor/editor-bridge.js +18 -8
  161. package/dist/editor/editor-toolbar.d.ts +14 -0
  162. package/dist/editor/editor-toolbar.js +115 -0
  163. package/dist/editor/file-editor.d.ts +9 -0
  164. package/dist/editor/file-editor.js +236 -0
  165. package/dist/editor/file-service.d.ts +16 -0
  166. package/dist/editor/file-service.js +52 -0
  167. package/dist/editor/i18n-key-gen.d.ts +1 -0
  168. package/dist/editor/i18n-key-gen.js +7 -0
  169. package/dist/editor/inline-text-edit.d.ts +5 -0
  170. package/dist/editor/inline-text-edit.js +173 -92
  171. package/dist/editor/overlay-events.d.ts +5 -0
  172. package/dist/editor/overlay-events.js +364 -0
  173. package/dist/editor/overlay-hmr.d.ts +2 -0
  174. package/dist/editor/overlay-hmr.js +76 -0
  175. package/dist/editor/overlay-selection.d.ts +29 -0
  176. package/dist/editor/overlay-selection.js +148 -0
  177. package/dist/editor/overlay-utils.d.ts +12 -0
  178. package/dist/editor/overlay-utils.js +59 -0
  179. package/dist/editor/properties-panel-persist.d.ts +14 -0
  180. package/dist/editor/properties-panel-persist.js +70 -0
  181. package/dist/editor/properties-panel-rows.d.ts +10 -0
  182. package/dist/editor/properties-panel-rows.js +349 -0
  183. package/dist/editor/properties-panel-styles.d.ts +4 -0
  184. package/dist/editor/properties-panel-styles.js +174 -0
  185. package/dist/editor/properties-panel.d.ts +4 -0
  186. package/dist/editor/properties-panel.js +148 -0
  187. package/dist/editor/property-registry.d.ts +16 -0
  188. package/dist/editor/property-registry.js +303 -0
  189. package/dist/editor/standalone-file-panel.d.ts +0 -0
  190. package/dist/editor/standalone-file-panel.js +1 -0
  191. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  192. package/dist/editor/standalone-overlay-dom.js +1 -0
  193. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  194. package/dist/editor/standalone-overlay-styles.js +1 -0
  195. package/dist/editor/standalone-overlay.d.ts +1 -0
  196. package/dist/editor/standalone-overlay.js +76 -0
  197. package/dist/editor/syntax-highlighter.d.ts +4 -0
  198. package/dist/editor/syntax-highlighter.js +81 -0
  199. package/dist/editor/text-toolbar.d.ts +11 -0
  200. package/dist/editor/text-toolbar.js +327 -0
  201. package/dist/editor/toolbar-styles.d.ts +4 -0
  202. package/dist/editor/toolbar-styles.js +198 -0
  203. package/dist/email/index.d.ts +32 -0
  204. package/dist/email/index.js +154 -0
  205. package/dist/email/providers/resend.d.ts +2 -0
  206. package/dist/email/providers/resend.js +24 -0
  207. package/dist/email/providers/sendgrid.d.ts +2 -0
  208. package/dist/email/providers/sendgrid.js +31 -0
  209. package/dist/email/providers/smtp.d.ts +13 -0
  210. package/dist/email/providers/smtp.js +125 -0
  211. package/dist/email/template-engine.d.ts +18 -0
  212. package/dist/email/template-engine.js +116 -0
  213. package/dist/email/templates/base.d.ts +9 -0
  214. package/dist/email/templates/base.js +65 -0
  215. package/dist/email/templates/password-reset.d.ts +5 -0
  216. package/dist/email/templates/password-reset.js +15 -0
  217. package/dist/email/templates/verify-email.d.ts +5 -0
  218. package/dist/email/templates/verify-email.js +15 -0
  219. package/dist/email/templates/welcome.d.ts +5 -0
  220. package/dist/email/templates/welcome.js +13 -0
  221. package/dist/email/types.d.ts +49 -0
  222. package/dist/email/types.js +1 -0
  223. package/dist/llms/generate.d.ts +46 -0
  224. package/dist/llms/generate.js +185 -0
  225. package/dist/permissions/guard.d.ts +28 -0
  226. package/dist/permissions/guard.js +30 -0
  227. package/dist/permissions/index.d.ts +6 -0
  228. package/dist/permissions/index.js +3 -0
  229. package/dist/permissions/service.d.ts +80 -0
  230. package/dist/permissions/service.js +210 -0
  231. package/dist/permissions/tables.d.ts +5 -0
  232. package/dist/permissions/tables.js +68 -0
  233. package/dist/permissions/types.d.ts +33 -0
  234. package/dist/permissions/types.js +1 -0
  235. package/dist/runtime/app-shell.d.ts +1 -1
  236. package/dist/runtime/app-shell.js +164 -0
  237. package/dist/runtime/auth.d.ts +10 -0
  238. package/dist/runtime/auth.js +30 -0
  239. package/dist/runtime/communication.d.ts +137 -0
  240. package/dist/runtime/communication.js +228 -0
  241. package/dist/runtime/error-boundary.d.ts +23 -0
  242. package/dist/runtime/error-boundary.js +120 -0
  243. package/dist/runtime/i18n.d.ts +6 -1
  244. package/dist/runtime/i18n.js +42 -21
  245. package/dist/runtime/island.d.ts +16 -0
  246. package/dist/runtime/island.js +80 -0
  247. package/dist/runtime/router-data.d.ts +3 -0
  248. package/dist/runtime/router-data.js +102 -17
  249. package/dist/runtime/router-hydration.js +34 -2
  250. package/dist/runtime/router.d.ts +19 -2
  251. package/dist/runtime/router.js +237 -43
  252. package/dist/runtime/socket-client.d.ts +2 -0
  253. package/dist/runtime/socket-client.js +30 -0
  254. package/dist/runtime/webrtc.d.ts +91 -0
  255. package/dist/runtime/webrtc.js +428 -0
  256. package/dist/shared/dom-shims.js +4 -2
  257. package/dist/shared/graceful-shutdown.d.ts +8 -0
  258. package/dist/shared/graceful-shutdown.js +36 -0
  259. package/dist/shared/health.d.ts +8 -0
  260. package/dist/shared/health.js +25 -0
  261. package/dist/shared/llms-txt.d.ts +31 -0
  262. package/dist/shared/llms-txt.js +85 -0
  263. package/dist/shared/logger.d.ts +32 -0
  264. package/dist/shared/logger.js +93 -0
  265. package/dist/shared/meta.d.ts +27 -0
  266. package/dist/shared/meta.js +71 -0
  267. package/dist/shared/middleware-runner.d.ts +9 -0
  268. package/dist/shared/middleware-runner.js +29 -0
  269. package/dist/shared/rate-limit.d.ts +18 -0
  270. package/dist/shared/rate-limit.js +71 -0
  271. package/dist/shared/request-id.d.ts +5 -0
  272. package/dist/shared/request-id.js +18 -0
  273. package/dist/shared/route-matching.js +16 -1
  274. package/dist/shared/security-headers.d.ts +18 -0
  275. package/dist/shared/security-headers.js +38 -0
  276. package/dist/shared/socket-io-setup.d.ts +11 -0
  277. package/dist/shared/socket-io-setup.js +51 -0
  278. package/dist/shared/types.d.ts +15 -0
  279. package/dist/shared/utils.d.ts +33 -7
  280. package/dist/shared/utils.js +164 -27
  281. package/dist/storage/adapters/local.d.ts +44 -0
  282. package/dist/storage/adapters/local.js +85 -0
  283. package/dist/storage/adapters/s3.d.ts +32 -0
  284. package/dist/storage/adapters/s3.js +119 -0
  285. package/dist/storage/adapters/types.d.ts +53 -0
  286. package/dist/storage/adapters/types.js +1 -0
  287. package/dist/storage/index.d.ts +76 -0
  288. package/dist/storage/index.js +83 -0
  289. package/package.json +45 -7
  290. package/templates/blog/api/posts.ts +4 -18
  291. package/templates/blog/data/migrations/001_init.sql +6 -5
  292. package/templates/blog/lumenjs.config.ts +3 -0
  293. package/templates/blog/package.json +14 -0
  294. package/templates/blog/pages/_layout.ts +25 -0
  295. package/templates/blog/pages/index.ts +48 -22
  296. package/templates/blog/pages/posts/[slug].ts +45 -20
  297. package/templates/blog/pages/tag/[tag].ts +44 -0
  298. package/templates/dashboard/api/stats.ts +8 -5
  299. package/templates/dashboard/lumenjs.config.ts +3 -0
  300. package/templates/dashboard/package.json +14 -0
  301. package/templates/dashboard/pages/_layout.ts +25 -0
  302. package/templates/dashboard/pages/index.ts +54 -23
  303. package/templates/dashboard/pages/settings/index.ts +29 -0
  304. package/templates/default/lumenjs.config.ts +3 -0
  305. package/templates/default/package.json +14 -0
  306. package/templates/default/pages/index.ts +24 -0
@@ -11,13 +11,21 @@ import { ssrRenderPage } from './ssr-render.js';
11
11
  import { readProjectConfig, getLumenJSNodeModules, getLumenJSDirs } from './config.js';
12
12
  import { getNuralyUIAliases, resolveNuralyUIPaths } from './nuralyui-aliases.js';
13
13
  import { litDedupPlugin } from './plugins/vite-plugin-lit-dedup.js';
14
+ import { autoDefinePlugin } from './plugins/vite-plugin-auto-define.js';
14
15
  import { autoImportPlugin } from './plugins/vite-plugin-auto-import.js';
15
16
  import { litHmrPlugin } from './plugins/vite-plugin-lit-hmr.js';
16
17
  import { sourceAnnotatorPlugin } from './plugins/vite-plugin-source-annotator.js';
18
+ import { editorApiPlugin } from './plugins/vite-plugin-editor-api.js';
17
19
  import { virtualModulesPlugin } from './plugins/vite-plugin-virtual-modules.js';
18
20
  import { i18nPlugin, loadTranslationsFromDisk } from './plugins/vite-plugin-i18n.js';
21
+ import { authPlugin } from './plugins/vite-plugin-auth.js';
22
+ import { communicationPlugin } from './plugins/vite-plugin-communication.js';
23
+ import { lumenStoragePlugin } from './plugins/vite-plugin-storage.js';
24
+ import { lumenSocketIOPlugin } from './plugins/vite-plugin-socketio.js';
19
25
  import { resolveLocale } from './middleware/locale.js';
20
26
  import { setProjectDir } from '../db/context.js';
27
+ import { scanMiddleware, getMiddlewareDirsForPathname } from '../build/scan.js';
28
+ import { runMiddlewareChain, extractMiddleware } from '../shared/middleware-runner.js';
21
29
  // Re-export for backwards compatibility
22
30
  export { readProjectConfig, readProjectTitle, getLumenJSNodeModules, getLumenJSDirs } from './config.js';
23
31
  export { getNuralyUIAliases, resolveNuralyUIPaths } from './nuralyui-aliases.js';
@@ -30,24 +38,37 @@ export function getSharedViteConfig(projectDir, options) {
30
38
  const isDev = mode === 'development';
31
39
  const pagesDir = path.join(projectDir, 'pages');
32
40
  const lumenNodeModules = getLumenJSNodeModules();
33
- const { runtimeDir, editorDir } = getLumenJSDirs();
41
+ const { distDir, runtimeDir, editorDir } = getLumenJSDirs();
34
42
  // Resolve NuralyUI paths for aliases (only when nuralyui integration is enabled)
35
43
  const aliases = {};
36
44
  if (options?.integrations?.includes('nuralyui')) {
37
45
  const nuralyUIPaths = resolveNuralyUIPaths(projectDir);
38
46
  if (nuralyUIPaths) {
39
47
  Object.assign(aliases, getNuralyUIAliases(nuralyUIPaths.componentsPath, nuralyUIPaths.commonPath));
48
+ // Add root aliases for theme CSS imports
49
+ const nuralyUIRoot = path.resolve(nuralyUIPaths.componentsPath, '..');
50
+ aliases['@nuralyui-theme'] = path.join(nuralyUIRoot, 'shared/themes');
51
+ aliases['@nuralyui-common'] = nuralyUIPaths.commonPath;
40
52
  }
41
53
  }
42
54
  const resolve = {
43
55
  alias: {
44
56
  ...aliases,
45
- // Map @lumenjs/i18n to the physical dist file so Vite resolves it
46
- // without going through node_modules (it's not an npm package).
47
57
  '@lumenjs/i18n': path.join(runtimeDir, 'i18n.js'),
58
+ '@lumenjs/auth': path.join(runtimeDir, 'auth.js'),
59
+ '@nuraly/lumenjs-auth': path.join(runtimeDir, 'auth.js'),
60
+ '@lumenjs/communication': path.join(runtimeDir, 'communication.js'),
61
+ '@lumenjs/webrtc': path.join(runtimeDir, 'webrtc.js'),
62
+ '@lumenjs/db': path.join(distDir, 'db', 'client.js'),
63
+ '@lumenjs/permissions': path.join(distDir, 'permissions', 'index.js'),
64
+ '@lumenjs/storage': path.join(distDir, 'storage', 'index.js'),
65
+ '@nuraly/lumenjs': path.resolve(distDir, '..'),
48
66
  },
49
67
  conditions: isDev ? ['development', 'browser'] : ['browser'],
50
- dedupe: ['lit', 'lit-html', 'lit-element', '@lit/reactive-element'],
68
+ // Note: resolve.dedupe is NOT used — it resolves via Node's algorithm
69
+ // which ignores Vite's resolve.conditions, picking the `default` export
70
+ // (prod proxy) instead of `development`. The litDedupPlugin handles
71
+ // single-copy resolution with correct conditions instead.
51
72
  };
52
73
  const esbuild = {
53
74
  tsconfigRaw: {
@@ -60,6 +81,7 @@ export function getSharedViteConfig(projectDir, options) {
60
81
  const plugins = [
61
82
  lumenRoutesPlugin(pagesDir),
62
83
  lumenLoadersPlugin(pagesDir),
84
+ autoDefinePlugin(pagesDir),
63
85
  litDedupPlugin(lumenNodeModules, isDev),
64
86
  virtualModulesPlugin(runtimeDir, editorDir),
65
87
  ];
@@ -83,15 +105,41 @@ export function getSharedViteConfig(projectDir, options) {
83
105
  }
84
106
  export async function createDevServer(options) {
85
107
  const { projectDir, port, editorMode = false, base = '/' } = options;
86
- setProjectDir(projectDir);
87
108
  const pagesDir = path.join(projectDir, 'pages');
88
109
  const apiDir = path.join(projectDir, 'api');
89
110
  const publicDir = path.join(projectDir, 'public');
90
111
  const config = readProjectConfig(projectDir);
91
- const { title, integrations, i18n: i18nConfig } = config;
112
+ const { title, integrations, i18n: i18nConfig, prefetch: prefetchStrategy } = config;
113
+ // Read optional head.html for blocking scripts (e.g. theme initialization)
114
+ const headHtmlPath = path.join(projectDir, 'head.html');
115
+ const headContent = fs.existsSync(headHtmlPath) ? fs.readFileSync(headHtmlPath, 'utf-8') : undefined;
116
+ // Set project dir for DB context (used by loaders, API routes, plugins)
117
+ setProjectDir(projectDir);
118
+ process.env.LUMENJS_PROJECT_DIR = projectDir;
92
119
  const shared = getSharedViteConfig(projectDir, { integrations });
120
+ // Load user-defined Vite plugins from lumenjs.plugins.js (if present).
121
+ // This allows apps to add custom Vite plugins (e.g. proxy middleware)
122
+ // that run at the raw Connect level, before LumenJS's own middleware.
123
+ let userPlugins = [];
124
+ const pluginsPath = path.join(projectDir, 'lumenjs.plugins.js');
125
+ if (fs.existsSync(pluginsPath)) {
126
+ try {
127
+ // Use a temporary Vite server to load the TS file via ssrLoadModule
128
+ // would be circular, so we import it directly via dynamic import
129
+ // after Vite transforms it. Instead, read and eval the JS-compatible parts.
130
+ // Simplest: the file exports an array of plugin objects.
131
+ const pluginsMod = await import(pathToFileURL(pluginsPath).href);
132
+ const exported = pluginsMod.default || pluginsMod.plugins || pluginsMod;
133
+ if (Array.isArray(exported))
134
+ userPlugins = exported;
135
+ }
136
+ catch (err) {
137
+ console.warn(`[LumenJS] Failed to load lumenjs.plugins.js:`, err?.message);
138
+ }
139
+ }
93
140
  const server = await createViteServer({
94
141
  root: projectDir,
142
+ base,
95
143
  publicDir: fs.existsSync(publicDir) ? publicDir : undefined,
96
144
  server: {
97
145
  port,
@@ -99,93 +147,217 @@ export async function createDevServer(options) {
99
147
  strictPort: false,
100
148
  allowedHosts: true,
101
149
  cors: true,
102
- hmr: true,
150
+ hmr: process.env.HMR_CLIENT_PORT ? {
151
+ clientPort: parseInt(process.env.HMR_CLIENT_PORT),
152
+ port: parseInt(process.env.HMR_CLIENT_PORT),
153
+ ...(process.env.HMR_PROTOCOL ? { protocol: process.env.HMR_PROTOCOL } : {}),
154
+ ...(process.env.HMR_HOST ? { host: process.env.HMR_HOST } : {}),
155
+ } : true,
156
+ fs: {
157
+ allow: [projectDir, getLumenJSNodeModules(), path.resolve(getLumenJSNodeModules(), '..')],
158
+ },
103
159
  },
104
160
  resolve: shared.resolve,
161
+ // 'custom' prevents Vite from adding SPA fallback and indexHtml middleware,
162
+ // which would interfere with LumenJS's own HTML handler (especially when base != '/')
163
+ appType: 'custom',
105
164
  plugins: [
165
+ ...userPlugins,
166
+ ...(integrations.includes('auth') ? [authPlugin(projectDir)] : []),
106
167
  ...shared.plugins,
168
+ ...(integrations.includes('communication') ? [communicationPlugin(projectDir)] : []),
169
+ lumenStoragePlugin(projectDir),
107
170
  lumenApiRoutesPlugin(apiDir, projectDir),
108
171
  litHmrPlugin(projectDir),
109
172
  ...(i18nConfig ? [i18nPlugin(projectDir, i18nConfig)] : []),
110
- ...(editorMode ? [sourceAnnotatorPlugin(projectDir)] : []),
111
- {
112
- name: 'lumenjs-index-html',
113
- configureServer(server) {
114
- server.middlewares.use((req, res, next) => {
115
- // Guard against malformed percent-encoded URLs that crash Vite's transformIndexHtml
116
- if (req.url) {
117
- try {
118
- decodeURIComponent(req.url);
173
+ ...(editorMode ? [sourceAnnotatorPlugin(projectDir), editorApiPlugin(projectDir)] : []),
174
+ lumenSocketIOPlugin(pagesDir),
175
+ ...(base !== '/' ? [{
176
+ // Fix HMR fetch URLs when Vite runs behind a base path.
177
+ // Vite's import analysis injects createHotContext() with the full filesystem
178
+ // path (e.g. /data/user-apps/.../bb2/pages/index.ts) instead of root-relative.
179
+ // When @vite/client fetches the updated module it builds the URL as
180
+ // base + filesystemPath.slice(1) → /__app_dev/{id}/data/.../pages/index.ts
181
+ // which 404s because transformMiddleware resolves relative to root, doubling
182
+ // the path. This pre-hook middleware strips the projectDir prefix so
183
+ // baseMiddleware sees the correct root-relative path.
184
+ name: 'lumenjs-hmr-path-fix',
185
+ configureServer(server) {
186
+ const projSlash = projectDir.replace(/\\/g, '/');
187
+ server.middlewares.use((req, _res, next) => {
188
+ if (req.url) {
189
+ const prefix = base + projSlash.slice(1) + '/';
190
+ if (req.url.startsWith(prefix)) {
191
+ req.url = base + req.url.slice(prefix.length);
192
+ }
119
193
  }
120
- catch {
121
- res.statusCode = 400;
122
- res.end('Bad Request');
123
- return;
194
+ next();
195
+ });
196
+ },
197
+ }] : []),
198
+ {
199
+ // Clear SSR module cache on file changes so the next SSR request uses fresh code.
200
+ // Without this, HMR updates the client but SSR keeps serving stale modules.
201
+ name: 'lumenjs-ssr-invalidate-on-change',
202
+ handleHotUpdate({ file, server }) {
203
+ const mods = server.moduleGraph.getModulesByFile(file);
204
+ if (mods) {
205
+ for (const m of mods) {
206
+ m.ssrModule = null;
207
+ m.ssrTransformResult = null;
208
+ }
209
+ }
210
+ },
211
+ },
212
+ {
213
+ name: 'lumenjs-user-middleware',
214
+ config(config) {
215
+ const entries = scanMiddleware(pagesDir);
216
+ if (entries.length === 0)
217
+ return;
218
+ const npmDeps = new Set();
219
+ for (const entry of entries) {
220
+ try {
221
+ const content = fs.readFileSync(entry.filePath, 'utf-8');
222
+ const importMatches = content.matchAll(/(?:import|require)\s*(?:\(?\s*['"]([^./][^'"]*)['"]\s*\)?|.*from\s*['"]([^./][^'"]*)['"]\s*)/g);
223
+ for (const m of importMatches) {
224
+ const pkg = m[1] || m[2];
225
+ if (pkg) {
226
+ const pkgName = pkg.startsWith('@') ? pkg.split('/').slice(0, 2).join('/') : pkg.split('/')[0];
227
+ npmDeps.add(pkgName);
228
+ }
124
229
  }
125
230
  }
126
- if (req.url && !req.url.startsWith('/@') && !req.url.startsWith('/node_modules') &&
127
- !req.url.startsWith('/api/') && !req.url.startsWith('/__nk_loader/') &&
128
- !req.url.startsWith('/__nk_i18n/') &&
129
- !req.url.includes('.') && req.method === 'GET') {
130
- let pathname = req.url.split('?')[0];
131
- // Resolve locale from URL/cookie/header
132
- let locale;
133
- let translations;
134
- if (i18nConfig) {
135
- const localeResult = resolveLocale(pathname, i18nConfig, req.headers);
136
- locale = localeResult.locale;
137
- pathname = localeResult.pathname;
138
- translations = loadTranslationsFromDisk(projectDir, locale);
231
+ catch { }
232
+ }
233
+ if (npmDeps.size > 0) {
234
+ const existing = config.ssr?.external || [];
235
+ return { ssr: { external: [...existing, ...npmDeps] } };
236
+ }
237
+ },
238
+ configureServer(server) {
239
+ return () => {
240
+ server.middlewares.use(async (req, res, next) => {
241
+ const pathname = (req.url || '/').split('?')[0];
242
+ if (pathname.startsWith('/@') || pathname.startsWith('/node_modules') || pathname.includes('.')) {
243
+ return next();
139
244
  }
140
- const SSR_PLACEHOLDER = '<!--__NK_SSR_CONTENT__-->';
141
- ssrRenderPage(server, pagesDir, pathname, req.headers, locale).then(async (ssrResult) => {
142
- if (ssrResult?.redirect) {
143
- res.writeHead(ssrResult.redirect.status, { Location: ssrResult.redirect.location });
144
- res.end();
245
+ const middlewareEntries = scanMiddleware(pagesDir);
246
+ if (middlewareEntries.length === 0)
247
+ return next();
248
+ const matchingDirs = getMiddlewareDirsForPathname(pathname, middlewareEntries);
249
+ if (matchingDirs.length === 0)
250
+ return next();
251
+ const allMw = [];
252
+ for (const entry of matchingDirs) {
253
+ try {
254
+ const mod = await server.ssrLoadModule(entry.filePath);
255
+ allMw.push(...extractMiddleware(mod));
256
+ }
257
+ catch (err) {
258
+ console.error(`[LumenJS] Failed to load _middleware.ts (${entry.dir || 'root'}):`, err);
259
+ }
260
+ }
261
+ if (allMw.length === 0)
262
+ return next();
263
+ runMiddlewareChain(allMw, req, res, next);
264
+ });
265
+ };
266
+ }
267
+ },
268
+ {
269
+ name: 'lumenjs-index-html',
270
+ configureServer(server) {
271
+ return () => {
272
+ server.middlewares.use((req, res, next) => {
273
+ // Guard against malformed percent-encoded URLs that crash Vite's transformIndexHtml
274
+ if (req.url) {
275
+ try {
276
+ decodeURIComponent(req.url);
277
+ }
278
+ catch {
279
+ res.statusCode = 400;
280
+ res.end('Bad Request');
145
281
  return;
146
282
  }
147
- const shellHtml = generateIndexHtml({
148
- title,
149
- editorMode,
150
- ssrContent: ssrResult ? SSR_PLACEHOLDER : undefined,
151
- loaderData: ssrResult?.loaderData,
152
- layoutsData: ssrResult?.layoutsData,
153
- integrations,
154
- locale,
155
- i18nConfig: i18nConfig || undefined,
156
- translations,
157
- });
158
- const transformed = await server.transformIndexHtml(req.url, shellHtml);
159
- const finalHtml = ssrResult
160
- ? transformed.replace(SSR_PLACEHOLDER, ssrResult.html)
161
- : transformed;
162
- res.setHeader('Content-Type', 'text/html');
163
- res.setHeader('Cache-Control', 'no-store');
164
- res.end(finalHtml);
165
- }).catch(err => {
166
- console.error('[LumenJS] SSR/HTML generation error:', err);
167
- const html = generateIndexHtml({ title, editorMode, integrations, locale, i18nConfig: i18nConfig || undefined, translations });
168
- server.transformIndexHtml(req.url, html).then(transformed => {
283
+ }
284
+ if (req.url && !req.url.startsWith('/@') && !req.url.startsWith('/node_modules') &&
285
+ !req.url.startsWith('/api/') && !req.url.startsWith('/__nk_loader/') &&
286
+ !req.url.startsWith('/__nk_i18n/') &&
287
+ !req.url.includes('.') && req.method === 'GET') {
288
+ let pathname = req.url.split('?')[0];
289
+ // Resolve locale from URL/cookie/header
290
+ let locale;
291
+ let translations;
292
+ if (i18nConfig) {
293
+ const localeResult = resolveLocale(pathname, i18nConfig, req.headers);
294
+ locale = localeResult.locale;
295
+ pathname = localeResult.pathname;
296
+ translations = loadTranslationsFromDisk(projectDir, locale);
297
+ }
298
+ const SSR_PLACEHOLDER = '<!--__NK_SSR_CONTENT__-->';
299
+ ssrRenderPage(server, pagesDir, pathname, req.headers, locale, req.nkAuth?.user ?? undefined).then(async (ssrResult) => {
300
+ if (ssrResult?.redirect) {
301
+ res.writeHead(ssrResult.redirect.status, { Location: ssrResult.redirect.location });
302
+ res.end();
303
+ return;
304
+ }
305
+ const shellHtml = generateIndexHtml({
306
+ title,
307
+ editorMode,
308
+ ssrContent: ssrResult ? SSR_PLACEHOLDER : undefined,
309
+ loaderData: ssrResult?.loaderData,
310
+ layoutsData: ssrResult?.layoutsData,
311
+ integrations,
312
+ locale,
313
+ i18nConfig: i18nConfig || undefined,
314
+ translations,
315
+ prefetch: prefetchStrategy,
316
+ authUser: ssrResult?.authUser ?? req.nkAuth?.user ?? undefined,
317
+ headContent,
318
+ base,
319
+ });
320
+ const transformed = await server.transformIndexHtml(req.url, shellHtml);
321
+ const finalHtml = ssrResult
322
+ ? transformed.replace(SSR_PLACEHOLDER, ssrResult.html)
323
+ : transformed;
169
324
  res.setHeader('Content-Type', 'text/html');
170
325
  res.setHeader('Cache-Control', 'no-store');
171
- res.end(transformed);
172
- }).catch(next);
173
- });
174
- return;
175
- }
176
- next();
177
- });
326
+ res.end(finalHtml);
327
+ }).catch(err => {
328
+ console.error('[LumenJS] SSR/HTML generation error:', err);
329
+ const html = generateIndexHtml({ title, editorMode, integrations, locale, i18nConfig: i18nConfig || undefined, translations, prefetch: prefetchStrategy, headContent, base });
330
+ server.transformIndexHtml(req.url, html).then(transformed => {
331
+ res.setHeader('Content-Type', 'text/html');
332
+ res.setHeader('Cache-Control', 'no-store');
333
+ res.end(transformed);
334
+ }).catch(next);
335
+ });
336
+ return;
337
+ }
338
+ next();
339
+ });
340
+ };
178
341
  }
179
342
  }
180
343
  ],
181
344
  esbuild: shared.esbuild,
182
345
  optimizeDeps: {
183
- include: ['lit', 'lit/decorators.js', 'lit/directive.js', 'lit/directive-helpers.js', 'lit/async-directive.js', 'lit-html', 'lit-element', '@lit/reactive-element'],
184
- exclude: ['@lumenjs/i18n'],
346
+ exclude: [
347
+ '@lumenjs/i18n',
348
+ '@nuraly/lumenjs-auth',
349
+ // Lit packages must NOT be pre-bundled — pre-bundling creates separate
350
+ // module entries (/.vite/deps/) alongside raw /@fs/ files, causing
351
+ // multiple lit-html instances. Instead, resolve.dedupe forces all lit
352
+ // imports to a single copy. The project's lit version MUST match
353
+ // lumenjs's lit version for dedupe to work.
354
+ 'lit', 'lit-html', 'lit-element', '@lit/reactive-element',
355
+ '@lit-labs/ssr-client',
356
+ ],
185
357
  },
186
358
  ssr: {
187
359
  noExternal: true,
188
- external: ['node-domexception'],
360
+ external: ['node-domexception', 'socket.io-client', 'xmlhttprequest-ssl', 'engine.io-client', 'better-sqlite3', '@lumenjs/db', '@lumenjs/permissions', 'amqplib'],
189
361
  resolve: {
190
362
  conditions: ['node', 'import'],
191
363
  },
@@ -9,7 +9,7 @@ export interface LayoutSSRData {
9
9
  *
10
10
  * Returns pre-rendered HTML and loader data, or null on failure (falls back to CSR).
11
11
  */
12
- export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, pathname: string, headers?: Record<string, string | string[] | undefined>, locale?: string): Promise<{
12
+ export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, pathname: string, headers?: Record<string, string | string[] | undefined>, locale?: string, user?: any): Promise<{
13
13
  html: string;
14
14
  loaderData: any;
15
15
  layoutsData?: LayoutSSRData[];
@@ -17,4 +17,5 @@ export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, p
17
17
  location: string;
18
18
  status: number;
19
19
  };
20
+ authUser?: any;
20
21
  } | null>;