@nuraly/lumenjs 0.1.3 → 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 (333) 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 +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 +48 -120
  49. package/dist/build/scan.d.ts +17 -0
  50. package/dist/build/scan.js +76 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -4
  53. package/dist/build/serve-loaders.js +26 -18
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +218 -15
  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/index.d.ts +17 -13
  93. package/dist/db/index.js +205 -26
  94. package/dist/db/seed.d.ts +12 -0
  95. package/dist/db/seed.js +88 -0
  96. package/dist/db/table.d.ts +10 -0
  97. package/dist/db/table.js +12 -0
  98. package/dist/dev-server/config.d.ts +11 -0
  99. package/dist/dev-server/config.js +23 -20
  100. package/dist/dev-server/index-html.d.ts +3 -0
  101. package/dist/dev-server/index-html.js +18 -6
  102. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  103. package/dist/dev-server/nuralyui-aliases.js +115 -94
  104. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  105. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  106. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  107. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  108. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  109. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  110. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  111. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  113. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  114. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  115. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  116. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  117. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  118. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  119. package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
  120. package/dist/dev-server/plugins/vite-plugin-routes.js +15 -5
  121. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  122. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  123. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  124. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  125. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  126. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  127. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  128. package/dist/dev-server/server.js +127 -13
  129. package/dist/dev-server/ssr-render.d.ts +2 -1
  130. package/dist/dev-server/ssr-render.js +107 -48
  131. package/dist/editor/ai/backend.d.ts +20 -0
  132. package/dist/editor/ai/backend.js +104 -0
  133. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  134. package/dist/editor/ai/claude-code-client.js +145 -0
  135. package/dist/editor/ai/opencode-client.d.ts +14 -0
  136. package/dist/editor/ai/opencode-client.js +125 -0
  137. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  138. package/dist/editor/ai/snapshot-store.js +35 -0
  139. package/dist/editor/ai/types.d.ts +30 -0
  140. package/dist/editor/ai/types.js +136 -0
  141. package/dist/editor/ai-chat-panel.d.ts +13 -0
  142. package/dist/editor/ai-chat-panel.js +587 -0
  143. package/dist/editor/ai-markdown.d.ts +10 -0
  144. package/dist/editor/ai-markdown.js +70 -0
  145. package/dist/editor/ai-project-panel.d.ts +11 -0
  146. package/dist/editor/ai-project-panel.js +332 -0
  147. package/dist/editor/ast-modification.d.ts +11 -0
  148. package/dist/editor/ast-modification.js +1 -0
  149. package/dist/editor/ast-service.d.ts +30 -0
  150. package/dist/editor/ast-service.js +180 -0
  151. package/dist/editor/css-rules.d.ts +54 -0
  152. package/dist/editor/css-rules.js +423 -0
  153. package/dist/editor/editor-api-client.d.ts +51 -0
  154. package/dist/editor/editor-api-client.js +162 -0
  155. package/dist/editor/editor-bridge.d.ts +1 -0
  156. package/dist/editor/editor-bridge.js +17 -8
  157. package/dist/editor/editor-toolbar.d.ts +14 -0
  158. package/dist/editor/editor-toolbar.js +115 -0
  159. package/dist/editor/file-editor.d.ts +9 -0
  160. package/dist/editor/file-editor.js +236 -0
  161. package/dist/editor/file-service.d.ts +16 -0
  162. package/dist/editor/file-service.js +52 -0
  163. package/dist/editor/i18n-key-gen.d.ts +1 -0
  164. package/dist/editor/i18n-key-gen.js +7 -0
  165. package/dist/editor/inline-text-edit.d.ts +5 -0
  166. package/dist/editor/inline-text-edit.js +173 -92
  167. package/dist/editor/overlay-events.d.ts +5 -0
  168. package/dist/editor/overlay-events.js +364 -0
  169. package/dist/editor/overlay-hmr.d.ts +2 -0
  170. package/dist/editor/overlay-hmr.js +75 -0
  171. package/dist/editor/overlay-selection.d.ts +29 -0
  172. package/dist/editor/overlay-selection.js +148 -0
  173. package/dist/editor/overlay-utils.d.ts +12 -0
  174. package/dist/editor/overlay-utils.js +59 -0
  175. package/dist/editor/properties-panel-persist.d.ts +14 -0
  176. package/dist/editor/properties-panel-persist.js +70 -0
  177. package/dist/editor/properties-panel-rows.d.ts +10 -0
  178. package/dist/editor/properties-panel-rows.js +349 -0
  179. package/dist/editor/properties-panel-styles.d.ts +4 -0
  180. package/dist/editor/properties-panel-styles.js +174 -0
  181. package/dist/editor/properties-panel.d.ts +4 -0
  182. package/dist/editor/properties-panel.js +148 -0
  183. package/dist/editor/property-registry.d.ts +16 -0
  184. package/dist/editor/property-registry.js +303 -0
  185. package/dist/editor/standalone-file-panel.d.ts +0 -0
  186. package/dist/editor/standalone-file-panel.js +1 -0
  187. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  188. package/dist/editor/standalone-overlay-dom.js +1 -0
  189. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  190. package/dist/editor/standalone-overlay-styles.js +1 -0
  191. package/dist/editor/standalone-overlay.d.ts +1 -0
  192. package/dist/editor/standalone-overlay.js +76 -0
  193. package/dist/editor/syntax-highlighter.d.ts +4 -0
  194. package/dist/editor/syntax-highlighter.js +81 -0
  195. package/dist/editor/text-toolbar.d.ts +11 -0
  196. package/dist/editor/text-toolbar.js +327 -0
  197. package/dist/editor/toolbar-styles.d.ts +4 -0
  198. package/dist/editor/toolbar-styles.js +198 -0
  199. package/dist/email/index.d.ts +32 -0
  200. package/dist/email/index.js +154 -0
  201. package/dist/email/providers/resend.d.ts +2 -0
  202. package/dist/email/providers/resend.js +24 -0
  203. package/dist/email/providers/sendgrid.d.ts +2 -0
  204. package/dist/email/providers/sendgrid.js +31 -0
  205. package/dist/email/providers/smtp.d.ts +13 -0
  206. package/dist/email/providers/smtp.js +125 -0
  207. package/dist/email/template-engine.d.ts +18 -0
  208. package/dist/email/template-engine.js +116 -0
  209. package/dist/email/templates/base.d.ts +9 -0
  210. package/dist/email/templates/base.js +65 -0
  211. package/dist/email/templates/password-reset.d.ts +5 -0
  212. package/dist/email/templates/password-reset.js +15 -0
  213. package/dist/email/templates/verify-email.d.ts +5 -0
  214. package/dist/email/templates/verify-email.js +15 -0
  215. package/dist/email/templates/welcome.d.ts +5 -0
  216. package/dist/email/templates/welcome.js +13 -0
  217. package/dist/email/types.d.ts +49 -0
  218. package/dist/email/types.js +1 -0
  219. package/dist/llms/generate.d.ts +46 -0
  220. package/dist/llms/generate.js +185 -0
  221. package/dist/permissions/guard.d.ts +28 -0
  222. package/dist/permissions/guard.js +30 -0
  223. package/dist/permissions/index.d.ts +6 -0
  224. package/dist/permissions/index.js +3 -0
  225. package/dist/permissions/service.d.ts +80 -0
  226. package/dist/permissions/service.js +210 -0
  227. package/dist/permissions/tables.d.ts +5 -0
  228. package/dist/permissions/tables.js +68 -0
  229. package/dist/permissions/types.d.ts +33 -0
  230. package/dist/permissions/types.js +1 -0
  231. package/dist/runtime/app-shell.js +163 -0
  232. package/dist/runtime/auth.d.ts +10 -0
  233. package/dist/runtime/auth.js +30 -0
  234. package/dist/runtime/communication.d.ts +137 -0
  235. package/dist/runtime/communication.js +228 -0
  236. package/dist/runtime/error-boundary.d.ts +23 -0
  237. package/dist/runtime/error-boundary.js +120 -0
  238. package/dist/runtime/i18n.d.ts +6 -1
  239. package/dist/runtime/i18n.js +42 -21
  240. package/dist/runtime/router-data.d.ts +3 -0
  241. package/dist/runtime/router-data.js +102 -17
  242. package/dist/runtime/router-hydration.js +25 -0
  243. package/dist/runtime/router.d.ts +16 -1
  244. package/dist/runtime/router.js +188 -42
  245. package/dist/runtime/socket-client.d.ts +2 -0
  246. package/dist/runtime/socket-client.js +30 -0
  247. package/dist/runtime/webrtc.d.ts +47 -0
  248. package/dist/runtime/webrtc.js +178 -0
  249. package/dist/shared/graceful-shutdown.d.ts +8 -0
  250. package/dist/shared/graceful-shutdown.js +36 -0
  251. package/dist/shared/health.d.ts +8 -0
  252. package/dist/shared/health.js +25 -0
  253. package/dist/shared/llms-txt.d.ts +31 -0
  254. package/dist/shared/llms-txt.js +85 -0
  255. package/dist/shared/logger.d.ts +32 -0
  256. package/dist/shared/logger.js +93 -0
  257. package/dist/shared/meta.d.ts +27 -0
  258. package/dist/shared/meta.js +71 -0
  259. package/dist/shared/middleware-runner.d.ts +9 -0
  260. package/dist/shared/middleware-runner.js +29 -0
  261. package/dist/shared/rate-limit.d.ts +18 -0
  262. package/dist/shared/rate-limit.js +71 -0
  263. package/dist/shared/request-id.d.ts +5 -0
  264. package/dist/shared/request-id.js +18 -0
  265. package/dist/shared/route-matching.js +16 -1
  266. package/dist/shared/security-headers.d.ts +18 -0
  267. package/dist/shared/security-headers.js +38 -0
  268. package/dist/shared/socket-io-setup.d.ts +11 -0
  269. package/dist/shared/socket-io-setup.js +51 -0
  270. package/dist/shared/types.d.ts +14 -0
  271. package/dist/shared/utils.d.ts +33 -7
  272. package/dist/shared/utils.js +164 -27
  273. package/dist/storage/adapters/local.d.ts +44 -0
  274. package/dist/storage/adapters/local.js +85 -0
  275. package/dist/storage/adapters/s3.d.ts +32 -0
  276. package/dist/storage/adapters/s3.js +116 -0
  277. package/dist/storage/adapters/types.d.ts +53 -0
  278. package/dist/storage/adapters/types.js +1 -0
  279. package/dist/storage/index.d.ts +76 -0
  280. package/dist/storage/index.js +83 -0
  281. package/package.json +19 -7
  282. package/templates/blog/api/posts.ts +4 -18
  283. package/templates/blog/data/migrations/001_init.sql +6 -5
  284. package/templates/blog/lumenjs.config.ts +3 -0
  285. package/templates/blog/package.json +14 -0
  286. package/templates/blog/pages/_layout.ts +25 -0
  287. package/templates/blog/pages/index.ts +48 -22
  288. package/templates/blog/pages/posts/[slug].ts +45 -20
  289. package/templates/blog/pages/tag/[tag].ts +44 -0
  290. package/templates/dashboard/api/stats.ts +8 -5
  291. package/templates/dashboard/lumenjs.config.ts +3 -0
  292. package/templates/dashboard/package.json +14 -0
  293. package/templates/dashboard/pages/_layout.ts +25 -0
  294. package/templates/dashboard/pages/index.ts +54 -23
  295. package/templates/dashboard/pages/settings/index.ts +29 -0
  296. package/templates/default/lumenjs.config.ts +3 -0
  297. package/templates/default/package.json +14 -0
  298. package/templates/default/pages/index.ts +24 -0
  299. package/templates/social/api/posts/[id].ts +14 -0
  300. package/templates/social/api/posts.ts +11 -0
  301. package/templates/social/api/profile/[username].ts +10 -0
  302. package/templates/social/api/upload.ts +19 -0
  303. package/templates/social/data/migrations/001_init.sql +78 -0
  304. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  305. package/templates/social/data/migrations/003_auth.sql +7 -0
  306. package/templates/social/docs/architecture.md +76 -0
  307. package/templates/social/docs/components.md +100 -0
  308. package/templates/social/docs/data.md +89 -0
  309. package/templates/social/docs/pages.md +96 -0
  310. package/templates/social/docs/theming.md +52 -0
  311. package/templates/social/lib/media.ts +130 -0
  312. package/templates/social/lumenjs.auth.ts +21 -0
  313. package/templates/social/lumenjs.config.ts +3 -0
  314. package/templates/social/package.json +5 -0
  315. package/templates/social/pages/_layout.ts +239 -0
  316. package/templates/social/pages/apps/[id].ts +173 -0
  317. package/templates/social/pages/apps/index.ts +116 -0
  318. package/templates/social/pages/auth/login.ts +92 -0
  319. package/templates/social/pages/bookmarks.ts +57 -0
  320. package/templates/social/pages/explore.ts +73 -0
  321. package/templates/social/pages/index.ts +351 -0
  322. package/templates/social/pages/messages.ts +298 -0
  323. package/templates/social/pages/new.ts +77 -0
  324. package/templates/social/pages/notifications.ts +73 -0
  325. package/templates/social/pages/post/[id].ts +124 -0
  326. package/templates/social/pages/profile/[username].ts +100 -0
  327. package/templates/social/pages/settings/accessibility.ts +153 -0
  328. package/templates/social/pages/settings/account.ts +260 -0
  329. package/templates/social/pages/settings/help.ts +141 -0
  330. package/templates/social/pages/settings/language.ts +103 -0
  331. package/templates/social/pages/settings/privacy.ts +183 -0
  332. package/templates/social/pages/settings/security.ts +133 -0
  333. package/templates/social/pages/settings.ts +185 -0
package/README.md CHANGED
@@ -1,50 +1,48 @@
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, real-time subscriptions (SSE), 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
@@ -59,27 +57,20 @@ export class PageIndex extends LitElement {
59
57
  }
60
58
  ```
61
59
 
62
- The custom element tag name is derived automatically from the file path — no `@customElement` decorator needed.
63
-
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 };
@@ -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,82 +96,34 @@ 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
111
-
112
- ```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 };
117
- }
118
- ```
119
-
120
99
  ## Live Data (subscribe)
121
100
 
122
- Export a `subscribe()` function from any page or layout to push real-time data to the client over Server-Sent Events (SSE).
101
+ Export a `subscribe()` to push real-time data over Server-Sent Events.
123
102
 
124
103
  ```typescript
125
104
  // pages/dashboard.ts
126
- export async function loader() {
127
- return { orders: await db.orders.findAll() };
128
- }
129
-
130
105
  export function subscribe({ push }) {
131
- const stream = db.orders.watch();
132
- stream.on('change', (change) => push({ type: 'order-update', data: change }));
133
- return () => stream.close();
106
+ const interval = setInterval(() => {
107
+ push({ time: new Date().toISOString(), count: ++n });
108
+ }, 1000);
109
+ return () => clearInterval(interval);
134
110
  }
135
111
 
136
112
  export class PageDashboard extends LitElement {
137
- static properties = { loaderData: { type: Object }, liveData: { type: Object } };
138
- loaderData: any = {};
113
+ static properties = { liveData: { type: Object } };
139
114
  liveData: any = null;
140
115
 
141
116
  render() {
142
- return html`
143
- <h1>Orders (${this.loaderData.orders?.length})</h1>
144
- ${this.liveData ? html`<p>Update: ${this.liveData.type}</p>` : ''}
145
- `;
117
+ return html`<p>Server time: ${this.liveData?.time}</p>`;
146
118
  }
147
119
  }
148
120
  ```
149
121
 
150
- The `subscribe()` function is a persistent server-side process tied to the page lifecycle:
151
-
152
- 1. User opens page → framework opens SSE connection to `/__nk_subscribe/<path>`
153
- 2. Server calls `subscribe()` — function keeps running (DB watchers, intervals, etc.)
154
- 3. Call `push(data)` whenever you want → delivered to client → updates `liveData` property
155
- 4. User navigates away → connection closes → cleanup function runs
122
+ Return a cleanup function it runs when the client disconnects.
156
123
 
157
- Like `loader()`, `subscribe()` is stripped from client bundles automatically.
124
+ ## Layouts
158
125
 
159
- ### Subscribe Context
160
-
161
- | Property | Type | Description |
162
- |---|---|---|
163
- | `params` | `Record<string, string>` | Dynamic route parameters |
164
- | `headers` | `Record<string, any>` | Request headers |
165
- | `locale` | `string` | Current locale (when i18n is configured) |
166
- | `push` | `(data: any) => void` | Send SSE event to client (JSON-serialized) |
167
-
168
- Return a cleanup function that is called when the client disconnects.
169
-
170
- ### Layout Subscribe
171
-
172
- Layouts can also export `subscribe()` for global live data (notifications, presence, etc.):
173
-
174
- ```typescript
175
- // pages/_layout.ts
176
- export function subscribe({ push }) {
177
- const ws = new WebSocket('wss://notifications.example.com');
178
- ws.on('message', (msg) => push(JSON.parse(msg)));
179
- return () => ws.close();
180
- }
181
- ```
182
-
183
- ## Nested Layouts
184
-
185
- Create `_layout.ts` in any directory to wrap all pages in that directory and its subdirectories.
126
+ Create `_layout.ts` in any directory. It wraps all pages below it and persists across navigation.
186
127
 
187
128
  ```typescript
188
129
  // pages/_layout.ts
@@ -191,40 +132,16 @@ export class RootLayout extends LitElement {
191
132
  return html`
192
133
  <header>My App</header>
193
134
  <main><slot></slot></main>
194
- <footer>Footer</footer>
195
135
  `;
196
136
  }
197
137
  }
198
138
  ```
199
139
 
200
- Layouts persist across navigation when navigating between pages that share the same layout, only the page component is swapped.
201
-
202
- Layouts can have their own `loader()` function for shared data like auth or navigation:
203
-
204
- ```typescript
205
- // pages/dashboard/_layout.ts
206
- export async function loader({ headers }) {
207
- const user = await getUser(headers.authorization);
208
- if (!user) return { __nk_redirect: true, location: '/login', status: 302 };
209
- return { user };
210
- }
211
-
212
- export class DashboardLayout extends LitElement {
213
- static properties = { loaderData: { type: Object } };
214
- loaderData: any = {};
215
-
216
- render() {
217
- return html`
218
- <nav>Welcome, ${this.loaderData.user?.name}</nav>
219
- <slot></slot>
220
- `;
221
- }
222
- }
223
- ```
140
+ Layouts can have their own `loader()` and `subscribe()` for shared data (auth, notifications, etc.).
224
141
 
225
142
  ## API Routes
226
143
 
227
- 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.
228
145
 
229
146
  ```typescript
230
147
  // api/users/[id].ts
@@ -238,196 +155,59 @@ export async function POST(req) {
238
155
  }
239
156
  ```
240
157
 
241
- ### Request Object
242
-
243
- | Property | Type | Description |
244
- |---|---|---|
245
- | `method` | `string` | HTTP method |
246
- | `url` | `string` | Request pathname |
247
- | `query` | `Record<string, string>` | Query string parameters |
248
- | `params` | `Record<string, string>` | Dynamic route parameters |
249
- | `body` | `any` | Parsed JSON body (non-GET) |
250
- | `files` | `NkUploadedFile[]` | Uploaded files (multipart) |
251
- | `headers` | `Record<string, any>` | Request headers |
252
-
253
- ### Error Responses
254
-
255
- ```typescript
256
- export async function GET(req) {
257
- const item = await db.find(req.params.id);
258
- if (!item) throw { status: 404, message: 'Not found' };
259
- return item;
260
- }
261
- ```
262
-
263
- ### File Uploads
158
+ Supports JSON bodies, query params, dynamic routes, file uploads (`req.files`), and error handling via `throw { status, message }`.
264
159
 
265
- Multipart form data is parsed automatically:
266
-
267
- ```typescript
268
- export async function POST(req) {
269
- for (const file of req.files) {
270
- console.log(file.fileName, file.size, file.contentType);
271
- // file.data is a Buffer
272
- }
273
- return { uploaded: req.files.length };
274
- }
275
- ```
276
-
277
- ## SSR & Hydration
278
-
279
- Pages with loaders are automatically server-rendered using `@lit-labs/ssr`:
280
-
281
- 1. Loader runs on the server
282
- 2. Lit component renders to HTML
283
- 3. Loader data is embedded as JSON in the response
284
- 4. Browser receives pre-rendered HTML (fast first paint)
285
- 5. Client hydrates the existing DOM without re-rendering
286
-
287
- Pages without loaders render client-side only (SPA mode). If SSR fails, LumenJS falls back gracefully to client-side rendering.
288
-
289
- ## Internationalization (i18n)
290
-
291
- LumenJS has built-in i18n support with URL-prefix-based locale routing.
292
-
293
- ### Setup
294
-
295
- 1. Add i18n config to `lumenjs.config.ts`:
160
+ ## i18n
296
161
 
297
162
  ```typescript
163
+ // lumenjs.config.ts
298
164
  export default {
299
- title: 'My App',
300
- i18n: {
301
- locales: ['en', 'fr'],
302
- defaultLocale: 'en',
303
- prefixDefault: false, // / instead of /en/
304
- },
165
+ i18n: { locales: ['en', 'fr'], defaultLocale: 'en' },
305
166
  };
306
167
  ```
307
168
 
308
- 2. Create translation files in `locales/`:
309
-
310
- ```
311
- my-app/
312
- ├── locales/
313
- │ ├── en.json # { "home.title": "Welcome", "nav.docs": "Docs" }
314
- │ └── fr.json # { "home.title": "Bienvenue", "nav.docs": "Documentation" }
315
- ├── pages/
316
- └── lumenjs.config.ts
317
- ```
318
-
319
- ### Usage
320
-
321
169
  ```typescript
322
- import { t, getLocale, setLocale } from '@lumenjs/i18n';
170
+ import { t, setLocale } from '@lumenjs/i18n';
323
171
 
324
- export class PageIndex extends LitElement {
325
- render() {
326
- return html`<h1>${t('home.title')}</h1>`;
327
- }
328
- }
172
+ html`<h1>${t('home.title')}</h1>
173
+ <button @click=${() => setLocale('fr')}>FR</button>`;
329
174
  ```
330
175
 
331
- ### API
332
-
333
- | Function | Description |
334
- |---|---|
335
- | `t(key)` | Returns the translated string for the key, or the key itself if not found |
336
- | `getLocale()` | Returns the current locale string |
337
- | `setLocale(locale)` | Switches locale — sets cookie, navigates to the localized URL |
338
-
339
- ### Locale Resolution
340
-
341
- Locale is resolved in this order:
342
-
343
- 1. URL prefix: `/fr/about` → locale `fr`, pathname `/about`
344
- 2. Cookie `nk-locale` (set on explicit locale switch)
345
- 3. `Accept-Language` header (SSR)
346
- 4. Config `defaultLocale`
347
-
348
- ### URL Routing
349
-
350
- With `prefixDefault: false`, the default locale uses clean URLs:
351
-
352
- | URL | Locale | Page |
353
- |---|---|---|
354
- | `/about` | `en` (default) | `pages/about.ts` |
355
- | `/fr/about` | `fr` | `pages/about.ts` |
356
-
357
- 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.
358
-
359
- ### SSR
360
-
361
- 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.
362
177
 
363
178
  ## Integrations
364
179
 
365
- ### Tailwind CSS
366
-
367
180
  ```bash
368
- npx lumenjs add tailwind
181
+ npx lumenjs add tailwind # Tailwind CSS via @tailwindcss/vite
369
182
  ```
370
183
 
371
- This installs `tailwindcss` and `@tailwindcss/vite`, creates `styles/tailwind.css`, and updates your config. For pages using Tailwind classes in light DOM:
372
-
373
184
  ```typescript
374
- createRenderRoot() { return this; }
185
+ // lumenjs.config.ts NuralyUI auto-import
186
+ export default { integrations: ['nuralyui'] };
375
187
  ```
376
188
 
377
- ### NuralyUI
378
-
379
- Add `'nuralyui'` to integrations to enable auto-import of `<nr-*>` components:
380
-
381
- ```typescript
382
- // lumenjs.config.ts
383
- export default {
384
- title: 'My App',
385
- integrations: ['nuralyui'],
386
- };
387
- ```
388
-
389
- NuralyUI components are detected in `html\`\`` templates and imported automatically, including implicit dependencies (e.g., `nr-button` auto-imports `nr-icon`).
390
-
391
189
  ## CLI
392
190
 
393
191
  ```
394
- 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]
395
194
  lumenjs build [--project <dir>] [--out <dir>]
396
195
  lumenjs serve [--project <dir>] [--port <port>]
397
196
  lumenjs add <integration>
398
197
  ```
399
198
 
400
- | Command | Description |
401
- |---|---|
402
- | `dev` | Start Vite dev server with HMR, SSR, and API routes |
403
- | `build` | Bundle client assets and server modules for production |
404
- | `serve` | Serve the production build with SSR and gzip compression |
405
- | `add` | Add an integration (e.g., `tailwind`) |
406
-
407
- ### Default Ports
408
-
409
- | Mode | Default |
410
- |---|---|
411
- | `dev` | 3000 |
412
- | `serve` | 3000 |
413
-
414
- ## Production Build
199
+ ## Production
415
200
 
416
201
  ```bash
417
202
  npx lumenjs build --project ./my-app
418
203
  npx lumenjs serve --project ./my-app --port 8080
419
204
  ```
420
205
 
421
- 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.
422
207
 
423
- ```
424
- .lumenjs/
425
- ├── client/ # Static assets (HTML, JS, CSS)
426
- ├── server/ # Server modules (loaders, API routes, SSR runtime)
427
- └── manifest.json # Route manifest
428
- ```
208
+ ## Contributing
429
209
 
430
- 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.
431
211
 
432
212
  ## License
433
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 {};