@nuraly/lumenjs 0.1.2 → 0.1.4

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 (337) hide show
  1. package/README.md +76 -235
  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 +73 -0
  11. package/dist/auth/native-auth.js +293 -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 +98 -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/utils.d.ts +7 -0
  31. package/dist/auth/routes/utils.js +35 -0
  32. package/dist/auth/routes/verify.d.ts +3 -0
  33. package/dist/auth/routes/verify.js +26 -0
  34. package/dist/auth/routes.d.ts +8 -0
  35. package/dist/auth/routes.js +110 -0
  36. package/dist/auth/session.d.ts +8 -0
  37. package/dist/auth/session.js +54 -0
  38. package/dist/auth/token.d.ts +33 -0
  39. package/dist/auth/token.js +90 -0
  40. package/dist/auth/types.d.ts +156 -0
  41. package/dist/auth/types.js +2 -0
  42. package/dist/build/build-client.d.ts +15 -0
  43. package/dist/build/build-client.js +45 -0
  44. package/dist/build/build-prerender.d.ts +11 -0
  45. package/dist/build/build-prerender.js +159 -0
  46. package/dist/build/build-server.d.ts +17 -0
  47. package/dist/build/build-server.js +98 -0
  48. package/dist/build/build.js +52 -120
  49. package/dist/build/scan.d.ts +19 -0
  50. package/dist/build/scan.js +77 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -2
  53. package/dist/build/serve-loaders.js +128 -10
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +229 -14
  57. package/dist/cli.js +37 -6
  58. package/dist/communication/encryption.d.ts +35 -0
  59. package/dist/communication/encryption.js +90 -0
  60. package/dist/communication/handlers/context.d.ts +27 -0
  61. package/dist/communication/handlers/context.js +1 -0
  62. package/dist/communication/handlers/conversation.d.ts +24 -0
  63. package/dist/communication/handlers/conversation.js +113 -0
  64. package/dist/communication/handlers/file-upload.d.ts +17 -0
  65. package/dist/communication/handlers/file-upload.js +62 -0
  66. package/dist/communication/handlers/messaging.d.ts +30 -0
  67. package/dist/communication/handlers/messaging.js +237 -0
  68. package/dist/communication/handlers/presence.d.ts +15 -0
  69. package/dist/communication/handlers/presence.js +76 -0
  70. package/dist/communication/handlers.d.ts +5 -0
  71. package/dist/communication/handlers.js +5 -0
  72. package/dist/communication/index.d.ts +9 -0
  73. package/dist/communication/index.js +7 -0
  74. package/dist/communication/link-preview.d.ts +18 -0
  75. package/dist/communication/link-preview.js +115 -0
  76. package/dist/communication/schema.d.ts +10 -0
  77. package/dist/communication/schema.js +101 -0
  78. package/dist/communication/server.d.ts +86 -0
  79. package/dist/communication/server.js +212 -0
  80. package/dist/communication/signaling.d.ts +43 -0
  81. package/dist/communication/signaling.js +271 -0
  82. package/dist/communication/store.d.ts +71 -0
  83. package/dist/communication/store.js +289 -0
  84. package/dist/communication/types.d.ts +454 -0
  85. package/dist/communication/types.js +1 -0
  86. package/dist/create.d.ts +1 -0
  87. package/dist/create.js +55 -0
  88. package/dist/db/auto-migrate.d.ts +3 -0
  89. package/dist/db/auto-migrate.js +100 -0
  90. package/dist/db/client.d.ts +3 -0
  91. package/dist/db/client.js +18 -0
  92. package/dist/db/context.d.ts +2 -0
  93. package/dist/db/context.js +9 -0
  94. package/dist/db/index.d.ts +23 -0
  95. package/dist/db/index.js +258 -0
  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 +14 -0
  101. package/dist/dev-server/config.js +26 -9
  102. package/dist/dev-server/index-html.d.ts +3 -0
  103. package/dist/dev-server/index-html.js +18 -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.d.ts +0 -1
  122. package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
  123. package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
  124. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  125. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  127. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  128. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  129. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  130. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  131. package/dist/dev-server/server.js +128 -12
  132. package/dist/dev-server/ssr-render.d.ts +2 -1
  133. package/dist/dev-server/ssr-render.js +107 -48
  134. package/dist/editor/ai/backend.d.ts +20 -0
  135. package/dist/editor/ai/backend.js +104 -0
  136. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  137. package/dist/editor/ai/claude-code-client.js +145 -0
  138. package/dist/editor/ai/opencode-client.d.ts +14 -0
  139. package/dist/editor/ai/opencode-client.js +125 -0
  140. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  141. package/dist/editor/ai/snapshot-store.js +35 -0
  142. package/dist/editor/ai/types.d.ts +30 -0
  143. package/dist/editor/ai/types.js +136 -0
  144. package/dist/editor/ai-chat-panel.d.ts +13 -0
  145. package/dist/editor/ai-chat-panel.js +587 -0
  146. package/dist/editor/ai-markdown.d.ts +10 -0
  147. package/dist/editor/ai-markdown.js +70 -0
  148. package/dist/editor/ai-project-panel.d.ts +11 -0
  149. package/dist/editor/ai-project-panel.js +332 -0
  150. package/dist/editor/ast-modification.d.ts +11 -0
  151. package/dist/editor/ast-modification.js +1 -0
  152. package/dist/editor/ast-service.d.ts +30 -0
  153. package/dist/editor/ast-service.js +180 -0
  154. package/dist/editor/css-rules.d.ts +54 -0
  155. package/dist/editor/css-rules.js +423 -0
  156. package/dist/editor/editor-api-client.d.ts +51 -0
  157. package/dist/editor/editor-api-client.js +162 -0
  158. package/dist/editor/editor-bridge.d.ts +1 -0
  159. package/dist/editor/editor-bridge.js +17 -8
  160. package/dist/editor/editor-toolbar.d.ts +14 -0
  161. package/dist/editor/editor-toolbar.js +115 -0
  162. package/dist/editor/file-editor.d.ts +9 -0
  163. package/dist/editor/file-editor.js +236 -0
  164. package/dist/editor/file-service.d.ts +16 -0
  165. package/dist/editor/file-service.js +52 -0
  166. package/dist/editor/i18n-key-gen.d.ts +1 -0
  167. package/dist/editor/i18n-key-gen.js +7 -0
  168. package/dist/editor/inline-text-edit.d.ts +5 -0
  169. package/dist/editor/inline-text-edit.js +173 -92
  170. package/dist/editor/overlay-events.d.ts +5 -0
  171. package/dist/editor/overlay-events.js +364 -0
  172. package/dist/editor/overlay-hmr.d.ts +2 -0
  173. package/dist/editor/overlay-hmr.js +75 -0
  174. package/dist/editor/overlay-selection.d.ts +29 -0
  175. package/dist/editor/overlay-selection.js +148 -0
  176. package/dist/editor/overlay-utils.d.ts +12 -0
  177. package/dist/editor/overlay-utils.js +59 -0
  178. package/dist/editor/properties-panel-persist.d.ts +14 -0
  179. package/dist/editor/properties-panel-persist.js +70 -0
  180. package/dist/editor/properties-panel-rows.d.ts +10 -0
  181. package/dist/editor/properties-panel-rows.js +349 -0
  182. package/dist/editor/properties-panel-styles.d.ts +4 -0
  183. package/dist/editor/properties-panel-styles.js +174 -0
  184. package/dist/editor/properties-panel.d.ts +4 -0
  185. package/dist/editor/properties-panel.js +148 -0
  186. package/dist/editor/property-registry.d.ts +16 -0
  187. package/dist/editor/property-registry.js +303 -0
  188. package/dist/editor/standalone-file-panel.d.ts +0 -0
  189. package/dist/editor/standalone-file-panel.js +1 -0
  190. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  191. package/dist/editor/standalone-overlay-dom.js +1 -0
  192. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  193. package/dist/editor/standalone-overlay-styles.js +1 -0
  194. package/dist/editor/standalone-overlay.d.ts +1 -0
  195. package/dist/editor/standalone-overlay.js +76 -0
  196. package/dist/editor/syntax-highlighter.d.ts +4 -0
  197. package/dist/editor/syntax-highlighter.js +81 -0
  198. package/dist/editor/text-toolbar.d.ts +11 -0
  199. package/dist/editor/text-toolbar.js +327 -0
  200. package/dist/editor/toolbar-styles.d.ts +4 -0
  201. package/dist/editor/toolbar-styles.js +198 -0
  202. package/dist/email/index.d.ts +32 -0
  203. package/dist/email/index.js +154 -0
  204. package/dist/email/providers/resend.d.ts +2 -0
  205. package/dist/email/providers/resend.js +24 -0
  206. package/dist/email/providers/sendgrid.d.ts +2 -0
  207. package/dist/email/providers/sendgrid.js +31 -0
  208. package/dist/email/providers/smtp.d.ts +13 -0
  209. package/dist/email/providers/smtp.js +125 -0
  210. package/dist/email/template-engine.d.ts +18 -0
  211. package/dist/email/template-engine.js +116 -0
  212. package/dist/email/templates/base.d.ts +9 -0
  213. package/dist/email/templates/base.js +65 -0
  214. package/dist/email/templates/password-reset.d.ts +5 -0
  215. package/dist/email/templates/password-reset.js +15 -0
  216. package/dist/email/templates/verify-email.d.ts +5 -0
  217. package/dist/email/templates/verify-email.js +15 -0
  218. package/dist/email/templates/welcome.d.ts +5 -0
  219. package/dist/email/templates/welcome.js +13 -0
  220. package/dist/email/types.d.ts +49 -0
  221. package/dist/email/types.js +1 -0
  222. package/dist/llms/generate.d.ts +46 -0
  223. package/dist/llms/generate.js +185 -0
  224. package/dist/permissions/guard.d.ts +28 -0
  225. package/dist/permissions/guard.js +30 -0
  226. package/dist/permissions/index.d.ts +6 -0
  227. package/dist/permissions/index.js +3 -0
  228. package/dist/permissions/service.d.ts +80 -0
  229. package/dist/permissions/service.js +210 -0
  230. package/dist/permissions/tables.d.ts +5 -0
  231. package/dist/permissions/tables.js +68 -0
  232. package/dist/permissions/types.d.ts +33 -0
  233. package/dist/permissions/types.js +1 -0
  234. package/dist/runtime/app-shell.js +163 -0
  235. package/dist/runtime/auth.d.ts +10 -0
  236. package/dist/runtime/auth.js +30 -0
  237. package/dist/runtime/communication.d.ts +137 -0
  238. package/dist/runtime/communication.js +228 -0
  239. package/dist/runtime/error-boundary.d.ts +23 -0
  240. package/dist/runtime/error-boundary.js +120 -0
  241. package/dist/runtime/i18n.d.ts +6 -1
  242. package/dist/runtime/i18n.js +42 -21
  243. package/dist/runtime/router-data.d.ts +5 -0
  244. package/dist/runtime/router-data.js +121 -16
  245. package/dist/runtime/router-hydration.js +25 -0
  246. package/dist/runtime/router.d.ts +21 -1
  247. package/dist/runtime/router.js +221 -39
  248. package/dist/runtime/socket-client.d.ts +2 -0
  249. package/dist/runtime/socket-client.js +30 -0
  250. package/dist/runtime/webrtc.d.ts +47 -0
  251. package/dist/runtime/webrtc.js +178 -0
  252. package/dist/shared/graceful-shutdown.d.ts +8 -0
  253. package/dist/shared/graceful-shutdown.js +36 -0
  254. package/dist/shared/health.d.ts +8 -0
  255. package/dist/shared/health.js +25 -0
  256. package/dist/shared/llms-txt.d.ts +31 -0
  257. package/dist/shared/llms-txt.js +85 -0
  258. package/dist/shared/logger.d.ts +32 -0
  259. package/dist/shared/logger.js +93 -0
  260. package/dist/shared/meta.d.ts +27 -0
  261. package/dist/shared/meta.js +71 -0
  262. package/dist/shared/middleware-runner.d.ts +9 -0
  263. package/dist/shared/middleware-runner.js +29 -0
  264. package/dist/shared/rate-limit.d.ts +18 -0
  265. package/dist/shared/rate-limit.js +71 -0
  266. package/dist/shared/request-id.d.ts +5 -0
  267. package/dist/shared/request-id.js +18 -0
  268. package/dist/shared/route-matching.js +16 -1
  269. package/dist/shared/security-headers.d.ts +18 -0
  270. package/dist/shared/security-headers.js +38 -0
  271. package/dist/shared/socket-io-setup.d.ts +11 -0
  272. package/dist/shared/socket-io-setup.js +51 -0
  273. package/dist/shared/types.d.ts +16 -0
  274. package/dist/shared/utils.d.ts +37 -7
  275. package/dist/shared/utils.js +175 -26
  276. package/dist/storage/adapters/local.d.ts +44 -0
  277. package/dist/storage/adapters/local.js +85 -0
  278. package/dist/storage/adapters/s3.d.ts +32 -0
  279. package/dist/storage/adapters/s3.js +116 -0
  280. package/dist/storage/adapters/types.d.ts +53 -0
  281. package/dist/storage/adapters/types.js +1 -0
  282. package/dist/storage/index.d.ts +76 -0
  283. package/dist/storage/index.js +83 -0
  284. package/package.json +20 -1
  285. package/templates/blog/api/posts.ts +6 -0
  286. package/templates/blog/data/migrations/001_init.sql +13 -0
  287. package/templates/blog/lumenjs.config.ts +3 -0
  288. package/templates/blog/package.json +14 -0
  289. package/templates/blog/pages/_layout.ts +25 -0
  290. package/templates/blog/pages/index.ts +65 -0
  291. package/templates/blog/pages/posts/[slug].ts +60 -0
  292. package/templates/blog/pages/tag/[tag].ts +44 -0
  293. package/templates/dashboard/api/stats.ts +10 -0
  294. package/templates/dashboard/data/migrations/001_init.sql +13 -0
  295. package/templates/dashboard/lumenjs.config.ts +3 -0
  296. package/templates/dashboard/package.json +14 -0
  297. package/templates/dashboard/pages/_layout.ts +25 -0
  298. package/templates/dashboard/pages/index.ts +72 -0
  299. package/templates/dashboard/pages/settings/index.ts +29 -0
  300. package/templates/default/lumenjs.config.ts +3 -0
  301. package/templates/default/package.json +14 -0
  302. package/templates/default/pages/index.ts +24 -0
  303. package/templates/social/api/posts/[id].ts +14 -0
  304. package/templates/social/api/posts.ts +11 -0
  305. package/templates/social/api/profile/[username].ts +10 -0
  306. package/templates/social/api/upload.ts +19 -0
  307. package/templates/social/data/migrations/001_init.sql +78 -0
  308. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  309. package/templates/social/data/migrations/003_auth.sql +7 -0
  310. package/templates/social/docs/architecture.md +76 -0
  311. package/templates/social/docs/components.md +100 -0
  312. package/templates/social/docs/data.md +89 -0
  313. package/templates/social/docs/pages.md +96 -0
  314. package/templates/social/docs/theming.md +52 -0
  315. package/templates/social/lib/media.ts +130 -0
  316. package/templates/social/lumenjs.auth.ts +21 -0
  317. package/templates/social/lumenjs.config.ts +3 -0
  318. package/templates/social/package.json +5 -0
  319. package/templates/social/pages/_layout.ts +239 -0
  320. package/templates/social/pages/apps/[id].ts +173 -0
  321. package/templates/social/pages/apps/index.ts +116 -0
  322. package/templates/social/pages/auth/login.ts +92 -0
  323. package/templates/social/pages/bookmarks.ts +57 -0
  324. package/templates/social/pages/explore.ts +73 -0
  325. package/templates/social/pages/index.ts +351 -0
  326. package/templates/social/pages/messages.ts +298 -0
  327. package/templates/social/pages/new.ts +77 -0
  328. package/templates/social/pages/notifications.ts +73 -0
  329. package/templates/social/pages/post/[id].ts +124 -0
  330. package/templates/social/pages/profile/[username].ts +100 -0
  331. package/templates/social/pages/settings/accessibility.ts +153 -0
  332. package/templates/social/pages/settings/account.ts +260 -0
  333. package/templates/social/pages/settings/help.ts +141 -0
  334. package/templates/social/pages/settings/language.ts +103 -0
  335. package/templates/social/pages/settings/privacy.ts +183 -0
  336. package/templates/social/pages/settings/security.ts +133 -0
  337. package/templates/social/pages/settings.ts +185 -0
package/README.md CHANGED
@@ -1,57 +1,53 @@
1
+ <p align="center">
2
+ <img src="https://img.shields.io/npm/v/@nuraly/lumenjs?color=7c3aed&label=npm" alt="npm version" />
3
+ <img src="https://img.shields.io/badge/license-MIT-blue" alt="license" />
4
+ <img src="https://img.shields.io/badge/lit-3.x-324fff" alt="Lit 3" />
5
+ <img src="https://img.shields.io/badge/node-%3E%3D18-green" alt="node" />
6
+ </p>
7
+
1
8
  # LumenJS
2
9
 
3
- A full-stack web framework for [Lit](https://lit.dev/) web components. File-based routing, server loaders, SSR with hydration, nested layouts, API routes, and a Vite-powered dev server.
10
+ A full-stack web framework for [Lit](https://lit.dev/) web components. File-based routing, server loaders, real-time subscriptions (SSE), SSR with hydration, nested layouts, API routes, i18n, and a visual editor — all powered by Vite.
4
11
 
5
- ## Quick Start
12
+ ## Getting Started
6
13
 
7
14
  ```bash
8
- npx lumenjs dev --project ./my-app
15
+ npx @nuraly/lumenjs create my-app
16
+ cd my-app
17
+ npm install
18
+ npx lumenjs dev
9
19
  ```
10
20
 
11
- ## Project Structure
12
-
13
- ```
14
- my-app/
15
- ├── lumenjs.config.ts # Project config
16
- ├── package.json
17
- ├── pages/ # File-based routes
18
- │ ├── _layout.ts # Root layout
19
- │ ├── index.ts # → /
20
- │ ├── about.ts # → /about
21
- │ └── blog/
22
- │ ├── _layout.ts # Nested layout (wraps blog/*)
23
- │ ├── index.ts # → /blog
24
- │ └── [slug].ts # → /blog/:slug
25
- ├── api/ # API routes
26
- │ └── hello.ts # → /api/hello
27
- └── public/ # Static assets
28
- ```
21
+ Open [http://localhost:3000](http://localhost:3000) — you're live.
29
22
 
30
- ## Configuration
23
+ ### Templates
31
24
 
32
- ```typescript
33
- // lumenjs.config.ts
34
- export default {
35
- title: 'My App',
36
- integrations: ['tailwind'],
37
- };
25
+ ```bash
26
+ npx @nuraly/lumenjs create my-app # default starter
27
+ npx @nuraly/lumenjs create my-blog --template blog # blog with file-based posts
28
+ npx @nuraly/lumenjs create my-dash --template dashboard # real-time dashboard with SSE
38
29
  ```
39
30
 
40
- | Option | Type | Description |
41
- |---|---|---|
42
- | `title` | `string` | HTML page title |
43
- | `integrations` | `string[]` | Optional integrations: `'tailwind'`, `'nuralyui'` |
31
+ ## Features
32
+
33
+ - **File-based routing** `pages/about.ts` `/about`, `pages/blog/[slug].ts` `/blog/:slug`
34
+ - **Server loaders** fetch data server-side, hydrate on the client
35
+ - **Live data (SSE)** — `subscribe()` pushes real-time updates to the browser
36
+ - **SSR + hydration** — pre-rendered HTML with `@lit-labs/ssr`, zero flash
37
+ - **Nested layouts** — `_layout.ts` wraps child routes, persists across navigation
38
+ - **API routes** — `api/users.ts` → REST endpoints with file uploads
39
+ - **i18n** — URL-prefix routing, JSON translations, SSR-safe
40
+ - **Visual editor** — click-to-select, inline text editing, file browser
41
+ - **Tailwind & NuralyUI** — one command to add integrations
44
42
 
45
43
  ## Pages
46
44
 
47
- Pages are Lit components in the `pages/` directory. The file path determines the URL.
45
+ Pages are Lit components in `pages/`. The file path determines the URL.
48
46
 
49
47
  ```typescript
50
48
  // pages/index.ts
51
49
  import { LitElement, html, css } from 'lit';
52
- import { customElement } from 'lit/decorators.js';
53
50
 
54
- @customElement('page-index')
55
51
  export class PageIndex extends LitElement {
56
52
  static styles = css`:host { display: block; }`;
57
53
 
@@ -61,33 +57,28 @@ export class PageIndex extends LitElement {
61
57
  }
62
58
  ```
63
59
 
64
- ### Routing
65
-
66
60
  | File | URL | Tag |
67
61
  |---|---|---|
68
62
  | `pages/index.ts` | `/` | `<page-index>` |
69
63
  | `pages/about.ts` | `/about` | `<page-about>` |
70
- | `pages/blog/index.ts` | `/blog` | `<page-blog-index>` |
71
64
  | `pages/blog/[slug].ts` | `/blog/:slug` | `<page-blog-slug>` |
72
65
  | `pages/[...slug].ts` | `/*` (catch-all) | `<page-slug>` |
73
66
 
74
- Static routes take priority over dynamic ones. Dynamic `[param]` routes take priority over catch-all `[...param]` routes.
75
-
76
67
  ## Loaders
77
68
 
78
- Export a `loader()` function from any page or layout to fetch data on the server.
69
+ Export a `loader()` to fetch data server-side. It runs on SSR and via `/__nk_loader/<path>` during client-side navigation. Automatically stripped from client bundles.
79
70
 
80
71
  ```typescript
81
72
  // pages/blog/[slug].ts
82
- export async function loader({ params, headers, query, url }) {
73
+ export async function loader({ params }) {
83
74
  const post = await db.posts.findOne({ slug: params.slug });
84
75
  if (!post) return { __nk_redirect: true, location: '/404', status: 302 };
85
76
  return { post };
86
77
  }
87
78
 
88
- @customElement('page-blog-slug')
89
79
  export class BlogPost extends LitElement {
90
- @property({ type: Object }) loaderData: any = {};
80
+ static properties = { loaderData: { type: Object } };
81
+ loaderData: any = {};
91
82
 
92
83
  render() {
93
84
  return html`<h1>${this.loaderData.post?.title}</h1>`;
@@ -95,8 +86,6 @@ export class BlogPost extends LitElement {
95
86
  }
96
87
  ```
97
88
 
98
- Loaders run server-side on initial load (SSR) and are fetched via `/__nk_loader/<path>` during client-side navigation. The `loader()` export is automatically stripped from client bundles.
99
-
100
89
  ### Loader Context
101
90
 
102
91
  | Property | Type | Description |
@@ -107,62 +96,52 @@ Loaders run server-side on initial load (SSR) and are fetched via `/__nk_loader/
107
96
  | `headers` | `Record<string, any>` | Request headers |
108
97
  | `locale` | `string` | Current locale (when i18n is configured) |
109
98
 
110
- ### Redirects
99
+ ## Live Data (subscribe)
100
+
101
+ Export a `subscribe()` to push real-time data over Server-Sent Events.
111
102
 
112
103
  ```typescript
113
- export async function loader({ headers }) {
114
- const user = await getUser(headers.authorization);
115
- if (!user) return { __nk_redirect: true, location: '/login', status: 302 };
116
- return { user };
104
+ // pages/dashboard.ts
105
+ export function subscribe({ push }) {
106
+ const interval = setInterval(() => {
107
+ push({ time: new Date().toISOString(), count: ++n });
108
+ }, 1000);
109
+ return () => clearInterval(interval);
117
110
  }
118
- ```
119
111
 
120
- ## Nested Layouts
112
+ export class PageDashboard extends LitElement {
113
+ static properties = { liveData: { type: Object } };
114
+ liveData: any = null;
121
115
 
122
- Create `_layout.ts` in any directory to wrap all pages in that directory and its subdirectories.
123
-
124
- ```typescript
125
- // pages/_layout.ts
126
- @customElement('layout-root')
127
- export class RootLayout extends LitElement {
128
116
  render() {
129
- return html`
130
- <header>My App</header>
131
- <main><slot></slot></main>
132
- <footer>Footer</footer>
133
- `;
117
+ return html`<p>Server time: ${this.liveData?.time}</p>`;
134
118
  }
135
119
  }
136
120
  ```
137
121
 
138
- Layouts persist across navigationwhen navigating between pages that share the same layout, only the page component is swapped.
122
+ Return a cleanup functionit runs when the client disconnects.
139
123
 
140
- Layouts can have their own `loader()` function for shared data like auth or navigation:
124
+ ## Layouts
141
125
 
142
- ```typescript
143
- // pages/dashboard/_layout.ts
144
- export async function loader({ headers }) {
145
- const user = await getUser(headers.authorization);
146
- if (!user) return { __nk_redirect: true, location: '/login', status: 302 };
147
- return { user };
148
- }
149
-
150
- @customElement('layout-dashboard')
151
- export class DashboardLayout extends LitElement {
152
- @property({ type: Object }) loaderData: any = {};
126
+ Create `_layout.ts` in any directory. It wraps all pages below it and persists across navigation.
153
127
 
128
+ ```typescript
129
+ // pages/_layout.ts
130
+ export class RootLayout extends LitElement {
154
131
  render() {
155
132
  return html`
156
- <nav>Welcome, ${this.loaderData.user?.name}</nav>
157
- <slot></slot>
133
+ <header>My App</header>
134
+ <main><slot></slot></main>
158
135
  `;
159
136
  }
160
137
  }
161
138
  ```
162
139
 
140
+ Layouts can have their own `loader()` and `subscribe()` for shared data (auth, notifications, etc.).
141
+
163
142
  ## API Routes
164
143
 
165
- Create files in `api/` and export named functions for each HTTP method.
144
+ Files in `api/` become REST endpoints. Export named functions for each HTTP method.
166
145
 
167
146
  ```typescript
168
147
  // api/users/[id].ts
@@ -176,197 +155,59 @@ export async function POST(req) {
176
155
  }
177
156
  ```
178
157
 
179
- ### Request Object
180
-
181
- | Property | Type | Description |
182
- |---|---|---|
183
- | `method` | `string` | HTTP method |
184
- | `url` | `string` | Request pathname |
185
- | `query` | `Record<string, string>` | Query string parameters |
186
- | `params` | `Record<string, string>` | Dynamic route parameters |
187
- | `body` | `any` | Parsed JSON body (non-GET) |
188
- | `files` | `NkUploadedFile[]` | Uploaded files (multipart) |
189
- | `headers` | `Record<string, any>` | Request headers |
190
-
191
- ### Error Responses
192
-
193
- ```typescript
194
- export async function GET(req) {
195
- const item = await db.find(req.params.id);
196
- if (!item) throw { status: 404, message: 'Not found' };
197
- return item;
198
- }
199
- ```
200
-
201
- ### File Uploads
202
-
203
- Multipart form data is parsed automatically:
204
-
205
- ```typescript
206
- export async function POST(req) {
207
- for (const file of req.files) {
208
- console.log(file.fileName, file.size, file.contentType);
209
- // file.data is a Buffer
210
- }
211
- return { uploaded: req.files.length };
212
- }
213
- ```
214
-
215
- ## SSR & Hydration
216
-
217
- Pages with loaders are automatically server-rendered using `@lit-labs/ssr`:
158
+ Supports JSON bodies, query params, dynamic routes, file uploads (`req.files`), and error handling via `throw { status, message }`.
218
159
 
219
- 1. Loader runs on the server
220
- 2. Lit component renders to HTML
221
- 3. Loader data is embedded as JSON in the response
222
- 4. Browser receives pre-rendered HTML (fast first paint)
223
- 5. Client hydrates the existing DOM without re-rendering
224
-
225
- Pages without loaders render client-side only (SPA mode). If SSR fails, LumenJS falls back gracefully to client-side rendering.
226
-
227
- ## Internationalization (i18n)
228
-
229
- LumenJS has built-in i18n support with URL-prefix-based locale routing.
230
-
231
- ### Setup
232
-
233
- 1. Add i18n config to `lumenjs.config.ts`:
160
+ ## i18n
234
161
 
235
162
  ```typescript
163
+ // lumenjs.config.ts
236
164
  export default {
237
- title: 'My App',
238
- i18n: {
239
- locales: ['en', 'fr'],
240
- defaultLocale: 'en',
241
- prefixDefault: false, // / instead of /en/
242
- },
165
+ i18n: { locales: ['en', 'fr'], defaultLocale: 'en' },
243
166
  };
244
167
  ```
245
168
 
246
- 2. Create translation files in `locales/`:
247
-
248
- ```
249
- my-app/
250
- ├── locales/
251
- │ ├── en.json # { "home.title": "Welcome", "nav.docs": "Docs" }
252
- │ └── fr.json # { "home.title": "Bienvenue", "nav.docs": "Documentation" }
253
- ├── pages/
254
- └── lumenjs.config.ts
255
- ```
256
-
257
- ### Usage
258
-
259
169
  ```typescript
260
- import { t, getLocale, setLocale } from '@lumenjs/i18n';
170
+ import { t, setLocale } from '@lumenjs/i18n';
261
171
 
262
- @customElement('page-index')
263
- export class PageIndex extends LitElement {
264
- render() {
265
- return html`<h1>${t('home.title')}</h1>`;
266
- }
267
- }
172
+ html`<h1>${t('home.title')}</h1>
173
+ <button @click=${() => setLocale('fr')}>FR</button>`;
268
174
  ```
269
175
 
270
- ### API
271
-
272
- | Function | Description |
273
- |---|---|
274
- | `t(key)` | Returns the translated string for the key, or the key itself if not found |
275
- | `getLocale()` | Returns the current locale string |
276
- | `setLocale(locale)` | Switches locale — sets cookie, navigates to the localized URL |
277
-
278
- ### Locale Resolution
279
-
280
- Locale is resolved in this order:
281
-
282
- 1. URL prefix: `/fr/about` → locale `fr`, pathname `/about`
283
- 2. Cookie `nk-locale` (set on explicit locale switch)
284
- 3. `Accept-Language` header (SSR)
285
- 4. Config `defaultLocale`
286
-
287
- ### URL Routing
288
-
289
- With `prefixDefault: false`, the default locale uses clean URLs:
290
-
291
- | URL | Locale | Page |
292
- |---|---|---|
293
- | `/about` | `en` (default) | `pages/about.ts` |
294
- | `/fr/about` | `fr` | `pages/about.ts` |
295
-
296
- Routes are locale-agnostic — you don't need separate pages per locale. The router strips the locale prefix before matching and prepends it during navigation.
297
-
298
- ### SSR
299
-
300
- Translations are server-rendered. The `<html lang="...">` attribute is set dynamically, and translations are inlined in the response for hydration without flash of untranslated content.
176
+ Translations live in `locales/en.json`, `locales/fr.json`. URL routing: `/about` (default), `/fr/about` (French). Server-rendered, no flash.
301
177
 
302
178
  ## Integrations
303
179
 
304
- ### Tailwind CSS
305
-
306
180
  ```bash
307
- npx lumenjs add tailwind
308
- ```
309
-
310
- This installs `tailwindcss` and `@tailwindcss/vite`, creates `styles/tailwind.css`, and updates your config. For pages using Tailwind classes in light DOM:
311
-
312
- ```typescript
313
- createRenderRoot() { return this; }
181
+ npx lumenjs add tailwind # Tailwind CSS via @tailwindcss/vite
314
182
  ```
315
183
 
316
- ### NuralyUI
317
-
318
- Add `'nuralyui'` to integrations to enable auto-import of `<nr-*>` components:
319
-
320
184
  ```typescript
321
- // lumenjs.config.ts
322
- export default {
323
- title: 'My App',
324
- integrations: ['nuralyui'],
325
- };
185
+ // lumenjs.config.ts — NuralyUI auto-import
186
+ export default { integrations: ['nuralyui'] };
326
187
  ```
327
188
 
328
- NuralyUI components are detected in `html\`\`` templates and imported automatically, including implicit dependencies (e.g., `nr-button` auto-imports `nr-icon`).
329
-
330
189
  ## CLI
331
190
 
332
191
  ```
333
- lumenjs dev [--project <dir>] [--port <port>] [--base <path>] [--editor-mode]
192
+ lumenjs create <name> [--template <default|blog|dashboard>]
193
+ lumenjs dev [--project <dir>] [--port <port>] [--editor-mode]
334
194
  lumenjs build [--project <dir>] [--out <dir>]
335
195
  lumenjs serve [--project <dir>] [--port <port>]
336
196
  lumenjs add <integration>
337
197
  ```
338
198
 
339
- | Command | Description |
340
- |---|---|
341
- | `dev` | Start Vite dev server with HMR, SSR, and API routes |
342
- | `build` | Bundle client assets and server modules for production |
343
- | `serve` | Serve the production build with SSR and gzip compression |
344
- | `add` | Add an integration (e.g., `tailwind`) |
345
-
346
- ### Default Ports
347
-
348
- | Mode | Default |
349
- |---|---|
350
- | `dev` | 3000 |
351
- | `serve` | 3000 |
352
-
353
- ## Production Build
199
+ ## Production
354
200
 
355
201
  ```bash
356
202
  npx lumenjs build --project ./my-app
357
203
  npx lumenjs serve --project ./my-app --port 8080
358
204
  ```
359
205
 
360
- The build outputs to `.lumenjs/`:
206
+ Outputs to `.lumenjs/` — pre-built client assets, server modules, route manifest. The production server handles SSR, loaders, API routes, and gzip compression.
361
207
 
362
- ```
363
- .lumenjs/
364
- ├── client/ # Static assets (HTML, JS, CSS)
365
- ├── server/ # Server modules (loaders, API routes, SSR runtime)
366
- └── manifest.json # Route manifest
367
- ```
208
+ ## Contributing
368
209
 
369
- The production server includes gzip compression and serves pre-built assets while executing loaders and API routes on demand.
210
+ Contributions are welcome! Please open an issue or submit a pull request.
370
211
 
371
212
  ## License
372
213
 
@@ -0,0 +1,23 @@
1
+ import type { ResolvedAuthConfig, AuthProvider } from './types.js';
2
+ /** Get a provider by name */
3
+ export declare function getProvider(config: ResolvedAuthConfig, name: string): AuthProvider | undefined;
4
+ /** Get the first OIDC provider */
5
+ export declare function getOidcProvider(config: ResolvedAuthConfig): (AuthProvider & {
6
+ type: "oidc";
7
+ }) | undefined;
8
+ /** Get the native provider */
9
+ export declare function getNativeProvider(config: ResolvedAuthConfig): (AuthProvider & {
10
+ type: "native";
11
+ }) | undefined;
12
+ /** Check if config has a native auth provider */
13
+ export declare function hasNativeAuth(config: ResolvedAuthConfig): boolean;
14
+ /** Check if config has any OIDC provider */
15
+ export declare function hasOidcAuth(config: ResolvedAuthConfig): boolean;
16
+ /**
17
+ * Load auth config in dev mode (via Vite's ssrLoadModule).
18
+ */
19
+ export declare function loadAuthConfig(projectDir: string, ssrLoadModule?: (id: string) => Promise<any>): Promise<ResolvedAuthConfig | null>;
20
+ /**
21
+ * Load auth config in production from bundled server output.
22
+ */
23
+ export declare function loadAuthConfigProd(serverDir: string, configModule: string): Promise<ResolvedAuthConfig>;
@@ -0,0 +1,115 @@
1
+ import path from 'path';
2
+ const ROUTE_DEFAULTS = {
3
+ login: '/__nk_auth/login',
4
+ loginPage: '/auth/login',
5
+ callback: '/__nk_auth/callback',
6
+ logout: '/__nk_auth/logout',
7
+ signup: '/__nk_auth/signup',
8
+ postLogin: '/',
9
+ postLogout: '/',
10
+ };
11
+ const GUARD_DEFAULTS = {
12
+ defaultAuth: false,
13
+ };
14
+ const PERMISSIONS_DEFAULTS = {
15
+ enabled: false,
16
+ defaultOwnerGrants: ['read', 'write', 'delete', 'share'],
17
+ };
18
+ const TOKEN_DEFAULTS = {
19
+ enabled: true,
20
+ accessTokenTTL: 900,
21
+ refreshTokenTTL: 604800,
22
+ };
23
+ function validate(config) {
24
+ if (!config?.session?.secret)
25
+ throw new Error('[LumenJS Auth] session.secret is required');
26
+ // Normalize providers: support both legacy single-provider and multi-provider
27
+ let providers;
28
+ if (config.providers && Array.isArray(config.providers)) {
29
+ providers = config.providers;
30
+ }
31
+ else if (config.provider?.issuer) {
32
+ // Legacy single OIDC provider format
33
+ providers = [{
34
+ type: 'oidc',
35
+ name: 'default',
36
+ issuer: config.provider.issuer,
37
+ clientId: config.provider.clientId,
38
+ clientSecret: config.provider.clientSecret,
39
+ scopes: config.provider.scopes || ['openid', 'profile', 'email'],
40
+ }];
41
+ }
42
+ else {
43
+ throw new Error('[LumenJS Auth] Either providers[] or provider.issuer is required');
44
+ }
45
+ // Validate each provider
46
+ for (const p of providers) {
47
+ if (p.type === 'oidc') {
48
+ if (!p.issuer)
49
+ throw new Error(`[LumenJS Auth] Provider "${p.name}": issuer is required`);
50
+ if (!p.clientId)
51
+ throw new Error(`[LumenJS Auth] Provider "${p.name}": clientId is required`);
52
+ }
53
+ if (!p.name)
54
+ throw new Error('[LumenJS Auth] Each provider must have a name');
55
+ }
56
+ return {
57
+ providers,
58
+ session: {
59
+ secret: config.session.secret,
60
+ cookieName: config.session.cookieName || 'nk-session',
61
+ maxAge: config.session.maxAge || 60 * 60 * 24 * 7,
62
+ secure: config.session.secure ?? (process.env.NODE_ENV === 'production'),
63
+ },
64
+ routes: { ...ROUTE_DEFAULTS, ...config.routes },
65
+ guards: { ...GUARD_DEFAULTS, ...config.guards },
66
+ permissions: { ...PERMISSIONS_DEFAULTS, ...config.permissions },
67
+ token: { ...TOKEN_DEFAULTS, ...config.token },
68
+ ...(config.onEvent ? { onEvent: config.onEvent } : {}),
69
+ };
70
+ }
71
+ /** Get a provider by name */
72
+ export function getProvider(config, name) {
73
+ return config.providers.find(p => p.name === name);
74
+ }
75
+ /** Get the first OIDC provider */
76
+ export function getOidcProvider(config) {
77
+ return config.providers.find(p => p.type === 'oidc');
78
+ }
79
+ /** Get the native provider */
80
+ export function getNativeProvider(config) {
81
+ return config.providers.find(p => p.type === 'native');
82
+ }
83
+ /** Check if config has a native auth provider */
84
+ export function hasNativeAuth(config) {
85
+ return config.providers.some(p => p.type === 'native');
86
+ }
87
+ /** Check if config has any OIDC provider */
88
+ export function hasOidcAuth(config) {
89
+ return config.providers.some(p => p.type === 'oidc');
90
+ }
91
+ /**
92
+ * Load auth config in dev mode (via Vite's ssrLoadModule).
93
+ */
94
+ export async function loadAuthConfig(projectDir, ssrLoadModule) {
95
+ try {
96
+ if (ssrLoadModule) {
97
+ const mod = await ssrLoadModule(path.join(projectDir, 'lumenjs.auth.ts'));
98
+ return validate(mod.default || mod);
99
+ }
100
+ const mod = await import(path.join(projectDir, 'lumenjs.auth.ts'));
101
+ return validate(mod.default || mod);
102
+ }
103
+ catch (err) {
104
+ if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'ENOENT')
105
+ return null;
106
+ throw err;
107
+ }
108
+ }
109
+ /**
110
+ * Load auth config in production from bundled server output.
111
+ */
112
+ export async function loadAuthConfigProd(serverDir, configModule) {
113
+ const mod = await import(path.join(serverDir, configModule));
114
+ return validate(mod.default || mod);
115
+ }
@@ -0,0 +1,12 @@
1
+ import type { NkAuth } from './types.js';
2
+ export type GuardResult = {
3
+ allowed: true;
4
+ } | {
5
+ redirect: string;
6
+ } | {
7
+ forbidden: true;
8
+ };
9
+ /**
10
+ * Enforce auth guard — pure function, caller handles the HTTP response.
11
+ */
12
+ export declare function enforceGuard(authExport: any, nkAuth: NkAuth | null | undefined, loginUrl: string, pathname: string): GuardResult;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Enforce auth guard — pure function, caller handles the HTTP response.
3
+ */
4
+ export function enforceGuard(authExport, nkAuth, loginUrl, pathname) {
5
+ if (!authExport)
6
+ return { allowed: true };
7
+ const user = nkAuth?.user;
8
+ // auth = true → require any authenticated user
9
+ if (authExport === true) {
10
+ if (!user) {
11
+ return { redirect: `${loginUrl}?returnTo=${encodeURIComponent(pathname)}` };
12
+ }
13
+ return { allowed: true };
14
+ }
15
+ // auth = { roles: [...] } → require specific roles
16
+ if (authExport.roles && Array.isArray(authExport.roles)) {
17
+ if (!user) {
18
+ return { redirect: `${loginUrl}?returnTo=${encodeURIComponent(pathname)}` };
19
+ }
20
+ const userRoles = user.roles || [];
21
+ const hasRole = authExport.roles.some((r) => userRoles.includes(r));
22
+ if (!hasRole) {
23
+ return { forbidden: true };
24
+ }
25
+ return { allowed: true };
26
+ }
27
+ return { allowed: true };
28
+ }
@@ -0,0 +1,3 @@
1
+ export { googleProvider } from './providers/google.js';
2
+ export type { GoogleProviderOptions } from './providers/google.js';
3
+ export type { AuthConfig, AuthUser, AuthProvider, AuthEvent, OIDCProvider, NativeProvider, ResolvedAuthConfig, SessionData, NkAuth, TokenResponse, } from './types.js';
@@ -0,0 +1 @@
1
+ export { googleProvider } from './providers/google.js';
@@ -0,0 +1,23 @@
1
+ import type { IncomingMessage, ServerResponse } from 'http';
2
+ import type { ResolvedAuthConfig, NkAuth } from './types.js';
3
+ type NextFn = (err?: any) => void;
4
+ /** Type augmentation — makes `req.nkAuth` available without casting */
5
+ declare module 'http' {
6
+ interface IncomingMessage {
7
+ nkAuth?: NkAuth | null;
8
+ }
9
+ }
10
+ export type ConnectMiddleware = (req: IncomingMessage, res: ServerResponse, next: NextFn) => Promise<void>;
11
+ /**
12
+ * Create Connect middleware that parses the session cookie and attaches req.nkAuth.
13
+ * Works with both OIDC and native auth sessions — the cookie format is identical.
14
+ *
15
+ * Behavior:
16
+ * 1. Skip non-page requests (/@, /node_modules, static files with `.`)
17
+ * 2. Check Bearer token (mobile/API clients)
18
+ * 3. Parse + decrypt session cookie → attach req.nkAuth
19
+ * 4. Refresh OIDC tokens if expiring within 5 minutes
20
+ * 5. Always call next() — never blocks the middleware chain
21
+ */
22
+ export declare function createAuthMiddleware(config: ResolvedAuthConfig, db?: any): ConnectMiddleware;
23
+ export {};