@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.
- package/README.md +62 -282
- package/dist/auth/config.d.ts +23 -0
- package/dist/auth/config.js +115 -0
- package/dist/auth/guard.d.ts +12 -0
- package/dist/auth/guard.js +28 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/middleware.d.ts +23 -0
- package/dist/auth/middleware.js +89 -0
- package/dist/auth/native-auth.d.ts +82 -0
- package/dist/auth/native-auth.js +340 -0
- package/dist/auth/oidc-client.d.ts +17 -0
- package/dist/auth/oidc-client.js +123 -0
- package/dist/auth/providers/google.d.ts +23 -0
- package/dist/auth/providers/google.js +25 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +1 -0
- package/dist/auth/routes/login.d.ts +8 -0
- package/dist/auth/routes/login.js +121 -0
- package/dist/auth/routes/logout.d.ts +4 -0
- package/dist/auth/routes/logout.js +79 -0
- package/dist/auth/routes/oidc-callback.d.ts +3 -0
- package/dist/auth/routes/oidc-callback.js +70 -0
- package/dist/auth/routes/password.d.ts +5 -0
- package/dist/auth/routes/password.js +149 -0
- package/dist/auth/routes/signup.d.ts +3 -0
- package/dist/auth/routes/signup.js +81 -0
- package/dist/auth/routes/token.d.ts +4 -0
- package/dist/auth/routes/token.js +70 -0
- package/dist/auth/routes/totp.d.ts +22 -0
- package/dist/auth/routes/totp.js +232 -0
- package/dist/auth/routes/utils.d.ts +7 -0
- package/dist/auth/routes/utils.js +35 -0
- package/dist/auth/routes/verify.d.ts +3 -0
- package/dist/auth/routes/verify.js +26 -0
- package/dist/auth/routes.d.ts +8 -0
- package/dist/auth/routes.js +124 -0
- package/dist/auth/session.d.ts +8 -0
- package/dist/auth/session.js +54 -0
- package/dist/auth/token.d.ts +33 -0
- package/dist/auth/token.js +90 -0
- package/dist/auth/types.d.ts +156 -0
- package/dist/auth/types.js +2 -0
- package/dist/build/build-client.d.ts +15 -0
- package/dist/build/build-client.js +45 -0
- package/dist/build/build-prerender.d.ts +11 -0
- package/dist/build/build-prerender.js +159 -0
- package/dist/build/build-server.d.ts +18 -0
- package/dist/build/build-server.js +107 -0
- package/dist/build/build.js +60 -123
- package/dist/build/scan.d.ts +18 -0
- package/dist/build/scan.js +77 -6
- package/dist/build/serve-api.js +8 -2
- package/dist/build/serve-loaders.d.ts +4 -4
- package/dist/build/serve-loaders.js +26 -18
- package/dist/build/serve-ssr.js +38 -11
- package/dist/build/serve-static.js +3 -3
- package/dist/build/serve.js +341 -18
- package/dist/cli.js +37 -6
- package/dist/communication/encryption.d.ts +35 -0
- package/dist/communication/encryption.js +90 -0
- package/dist/communication/handlers/context.d.ts +27 -0
- package/dist/communication/handlers/context.js +1 -0
- package/dist/communication/handlers/conversation.d.ts +24 -0
- package/dist/communication/handlers/conversation.js +113 -0
- package/dist/communication/handlers/file-upload.d.ts +17 -0
- package/dist/communication/handlers/file-upload.js +62 -0
- package/dist/communication/handlers/messaging.d.ts +30 -0
- package/dist/communication/handlers/messaging.js +237 -0
- package/dist/communication/handlers/presence.d.ts +15 -0
- package/dist/communication/handlers/presence.js +76 -0
- package/dist/communication/handlers.d.ts +5 -0
- package/dist/communication/handlers.js +5 -0
- package/dist/communication/index.d.ts +9 -0
- package/dist/communication/index.js +7 -0
- package/dist/communication/link-preview.d.ts +18 -0
- package/dist/communication/link-preview.js +115 -0
- package/dist/communication/schema.d.ts +10 -0
- package/dist/communication/schema.js +101 -0
- package/dist/communication/server.d.ts +86 -0
- package/dist/communication/server.js +212 -0
- package/dist/communication/signaling.d.ts +43 -0
- package/dist/communication/signaling.js +271 -0
- package/dist/communication/store.d.ts +71 -0
- package/dist/communication/store.js +289 -0
- package/dist/communication/types.d.ts +454 -0
- package/dist/communication/types.js +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +55 -0
- package/dist/db/auto-migrate.d.ts +3 -0
- package/dist/db/auto-migrate.js +100 -0
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.js +18 -0
- package/dist/db/index.d.ts +17 -13
- package/dist/db/index.js +205 -26
- package/dist/db/seed.d.ts +12 -0
- package/dist/db/seed.js +88 -0
- package/dist/db/table.d.ts +10 -0
- package/dist/db/table.js +12 -0
- package/dist/dev-server/config.d.ts +11 -0
- package/dist/dev-server/config.js +40 -20
- package/dist/dev-server/index-html.d.ts +4 -0
- package/dist/dev-server/index-html.js +21 -6
- package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
- package/dist/dev-server/nuralyui-aliases.js +115 -94
- package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
- package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
- package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
- package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
- package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
- package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
- package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
- package/dist/dev-server/plugins/vite-plugin-routes.js +16 -5
- package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
- package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
- package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
- package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +140 -3
- package/dist/dev-server/server.js +242 -70
- package/dist/dev-server/ssr-render.d.ts +2 -1
- package/dist/dev-server/ssr-render.js +117 -50
- package/dist/editor/ai/backend.d.ts +20 -0
- package/dist/editor/ai/backend.js +113 -0
- package/dist/editor/ai/claude-code-client.d.ts +20 -0
- package/dist/editor/ai/claude-code-client.js +145 -0
- package/dist/editor/ai/deepseek-client.d.ts +7 -0
- package/dist/editor/ai/deepseek-client.js +113 -0
- package/dist/editor/ai/opencode-client.d.ts +14 -0
- package/dist/editor/ai/opencode-client.js +99 -0
- package/dist/editor/ai/snapshot-store.d.ts +22 -0
- package/dist/editor/ai/snapshot-store.js +35 -0
- package/dist/editor/ai/types.d.ts +30 -0
- package/dist/editor/ai/types.js +136 -0
- package/dist/editor/ai-chat-panel.d.ts +13 -0
- package/dist/editor/ai-chat-panel.js +613 -0
- package/dist/editor/ai-markdown.d.ts +10 -0
- package/dist/editor/ai-markdown.js +70 -0
- package/dist/editor/ai-project-panel.d.ts +11 -0
- package/dist/editor/ai-project-panel.js +332 -0
- package/dist/editor/ast-modification.d.ts +11 -0
- package/dist/editor/ast-modification.js +1 -0
- package/dist/editor/ast-service.d.ts +30 -0
- package/dist/editor/ast-service.js +180 -0
- package/dist/editor/css-rules.d.ts +54 -0
- package/dist/editor/css-rules.js +423 -0
- package/dist/editor/editor-api-client.d.ts +51 -0
- package/dist/editor/editor-api-client.js +162 -0
- package/dist/editor/editor-bridge.d.ts +1 -0
- package/dist/editor/editor-bridge.js +18 -8
- package/dist/editor/editor-toolbar.d.ts +14 -0
- package/dist/editor/editor-toolbar.js +115 -0
- package/dist/editor/file-editor.d.ts +9 -0
- package/dist/editor/file-editor.js +236 -0
- package/dist/editor/file-service.d.ts +16 -0
- package/dist/editor/file-service.js +52 -0
- package/dist/editor/i18n-key-gen.d.ts +1 -0
- package/dist/editor/i18n-key-gen.js +7 -0
- package/dist/editor/inline-text-edit.d.ts +5 -0
- package/dist/editor/inline-text-edit.js +173 -92
- package/dist/editor/overlay-events.d.ts +5 -0
- package/dist/editor/overlay-events.js +364 -0
- package/dist/editor/overlay-hmr.d.ts +2 -0
- package/dist/editor/overlay-hmr.js +76 -0
- package/dist/editor/overlay-selection.d.ts +29 -0
- package/dist/editor/overlay-selection.js +148 -0
- package/dist/editor/overlay-utils.d.ts +12 -0
- package/dist/editor/overlay-utils.js +59 -0
- package/dist/editor/properties-panel-persist.d.ts +14 -0
- package/dist/editor/properties-panel-persist.js +70 -0
- package/dist/editor/properties-panel-rows.d.ts +10 -0
- package/dist/editor/properties-panel-rows.js +349 -0
- package/dist/editor/properties-panel-styles.d.ts +4 -0
- package/dist/editor/properties-panel-styles.js +174 -0
- package/dist/editor/properties-panel.d.ts +4 -0
- package/dist/editor/properties-panel.js +148 -0
- package/dist/editor/property-registry.d.ts +16 -0
- package/dist/editor/property-registry.js +303 -0
- package/dist/editor/standalone-file-panel.d.ts +0 -0
- package/dist/editor/standalone-file-panel.js +1 -0
- package/dist/editor/standalone-overlay-dom.d.ts +0 -0
- package/dist/editor/standalone-overlay-dom.js +1 -0
- package/dist/editor/standalone-overlay-styles.d.ts +0 -0
- package/dist/editor/standalone-overlay-styles.js +1 -0
- package/dist/editor/standalone-overlay.d.ts +1 -0
- package/dist/editor/standalone-overlay.js +76 -0
- package/dist/editor/syntax-highlighter.d.ts +4 -0
- package/dist/editor/syntax-highlighter.js +81 -0
- package/dist/editor/text-toolbar.d.ts +11 -0
- package/dist/editor/text-toolbar.js +327 -0
- package/dist/editor/toolbar-styles.d.ts +4 -0
- package/dist/editor/toolbar-styles.js +198 -0
- package/dist/email/index.d.ts +32 -0
- package/dist/email/index.js +154 -0
- package/dist/email/providers/resend.d.ts +2 -0
- package/dist/email/providers/resend.js +24 -0
- package/dist/email/providers/sendgrid.d.ts +2 -0
- package/dist/email/providers/sendgrid.js +31 -0
- package/dist/email/providers/smtp.d.ts +13 -0
- package/dist/email/providers/smtp.js +125 -0
- package/dist/email/template-engine.d.ts +18 -0
- package/dist/email/template-engine.js +116 -0
- package/dist/email/templates/base.d.ts +9 -0
- package/dist/email/templates/base.js +65 -0
- package/dist/email/templates/password-reset.d.ts +5 -0
- package/dist/email/templates/password-reset.js +15 -0
- package/dist/email/templates/verify-email.d.ts +5 -0
- package/dist/email/templates/verify-email.js +15 -0
- package/dist/email/templates/welcome.d.ts +5 -0
- package/dist/email/templates/welcome.js +13 -0
- package/dist/email/types.d.ts +49 -0
- package/dist/email/types.js +1 -0
- package/dist/llms/generate.d.ts +46 -0
- package/dist/llms/generate.js +185 -0
- package/dist/permissions/guard.d.ts +28 -0
- package/dist/permissions/guard.js +30 -0
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/service.d.ts +80 -0
- package/dist/permissions/service.js +210 -0
- package/dist/permissions/tables.d.ts +5 -0
- package/dist/permissions/tables.js +68 -0
- package/dist/permissions/types.d.ts +33 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/app-shell.d.ts +1 -1
- package/dist/runtime/app-shell.js +164 -0
- package/dist/runtime/auth.d.ts +10 -0
- package/dist/runtime/auth.js +30 -0
- package/dist/runtime/communication.d.ts +137 -0
- package/dist/runtime/communication.js +228 -0
- package/dist/runtime/error-boundary.d.ts +23 -0
- package/dist/runtime/error-boundary.js +120 -0
- package/dist/runtime/i18n.d.ts +6 -1
- package/dist/runtime/i18n.js +42 -21
- package/dist/runtime/island.d.ts +16 -0
- package/dist/runtime/island.js +80 -0
- package/dist/runtime/router-data.d.ts +3 -0
- package/dist/runtime/router-data.js +102 -17
- package/dist/runtime/router-hydration.js +34 -2
- package/dist/runtime/router.d.ts +19 -2
- package/dist/runtime/router.js +237 -43
- package/dist/runtime/socket-client.d.ts +2 -0
- package/dist/runtime/socket-client.js +30 -0
- package/dist/runtime/webrtc.d.ts +91 -0
- package/dist/runtime/webrtc.js +428 -0
- package/dist/shared/dom-shims.js +4 -2
- package/dist/shared/graceful-shutdown.d.ts +8 -0
- package/dist/shared/graceful-shutdown.js +36 -0
- package/dist/shared/health.d.ts +8 -0
- package/dist/shared/health.js +25 -0
- package/dist/shared/llms-txt.d.ts +31 -0
- package/dist/shared/llms-txt.js +85 -0
- package/dist/shared/logger.d.ts +32 -0
- package/dist/shared/logger.js +93 -0
- package/dist/shared/meta.d.ts +27 -0
- package/dist/shared/meta.js +71 -0
- package/dist/shared/middleware-runner.d.ts +9 -0
- package/dist/shared/middleware-runner.js +29 -0
- package/dist/shared/rate-limit.d.ts +18 -0
- package/dist/shared/rate-limit.js +71 -0
- package/dist/shared/request-id.d.ts +5 -0
- package/dist/shared/request-id.js +18 -0
- package/dist/shared/route-matching.js +16 -1
- package/dist/shared/security-headers.d.ts +18 -0
- package/dist/shared/security-headers.js +38 -0
- package/dist/shared/socket-io-setup.d.ts +11 -0
- package/dist/shared/socket-io-setup.js +51 -0
- package/dist/shared/types.d.ts +15 -0
- package/dist/shared/utils.d.ts +33 -7
- package/dist/shared/utils.js +164 -27
- package/dist/storage/adapters/local.d.ts +44 -0
- package/dist/storage/adapters/local.js +85 -0
- package/dist/storage/adapters/s3.d.ts +32 -0
- package/dist/storage/adapters/s3.js +119 -0
- package/dist/storage/adapters/types.d.ts +53 -0
- package/dist/storage/adapters/types.js +1 -0
- package/dist/storage/index.d.ts +76 -0
- package/dist/storage/index.js +83 -0
- package/package.json +45 -7
- package/templates/blog/api/posts.ts +4 -18
- package/templates/blog/data/migrations/001_init.sql +6 -5
- package/templates/blog/lumenjs.config.ts +3 -0
- package/templates/blog/package.json +14 -0
- package/templates/blog/pages/_layout.ts +25 -0
- package/templates/blog/pages/index.ts +48 -22
- package/templates/blog/pages/posts/[slug].ts +45 -20
- package/templates/blog/pages/tag/[tag].ts +44 -0
- package/templates/dashboard/api/stats.ts +8 -5
- package/templates/dashboard/lumenjs.config.ts +3 -0
- package/templates/dashboard/package.json +14 -0
- package/templates/dashboard/pages/_layout.ts +25 -0
- package/templates/dashboard/pages/index.ts +54 -23
- package/templates/dashboard/pages/settings/index.ts +29 -0
- package/templates/default/lumenjs.config.ts +3 -0
- package/templates/default/package.json +14 -0
- package/templates/default/pages/index.ts +24 -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
|
|
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
|
-
##
|
|
12
|
+
## Getting Started
|
|
6
13
|
|
|
7
14
|
```bash
|
|
8
|
-
npx lumenjs
|
|
15
|
+
npx @nuraly/lumenjs create my-app
|
|
16
|
+
cd my-app
|
|
17
|
+
npm install
|
|
18
|
+
npx lumenjs dev
|
|
9
19
|
```
|
|
10
20
|
|
|
11
|
-
|
|
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
|
-
|
|
23
|
+
### Templates
|
|
31
24
|
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
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()`
|
|
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
|
|
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()`
|
|
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
|
|
132
|
-
|
|
133
|
-
|
|
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 = {
|
|
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
|
-
|
|
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
|
-
|
|
124
|
+
## Layouts
|
|
158
125
|
|
|
159
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
170
|
+
import { t, setLocale } from '@lumenjs/i18n';
|
|
323
171
|
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 {};
|