@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.
- package/README.md +76 -235
- 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 +73 -0
- package/dist/auth/native-auth.js +293 -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 +98 -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/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 +110 -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 +17 -0
- package/dist/build/build-server.js +98 -0
- package/dist/build/build.js +52 -120
- package/dist/build/scan.d.ts +19 -0
- package/dist/build/scan.js +77 -6
- package/dist/build/serve-api.js +8 -2
- package/dist/build/serve-loaders.d.ts +4 -2
- package/dist/build/serve-loaders.js +128 -10
- package/dist/build/serve-ssr.js +38 -11
- package/dist/build/serve-static.js +3 -3
- package/dist/build/serve.js +229 -14
- 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/context.d.ts +2 -0
- package/dist/db/context.js +9 -0
- package/dist/db/index.d.ts +23 -0
- package/dist/db/index.js +258 -0
- 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 +14 -0
- package/dist/dev-server/config.js +26 -9
- package/dist/dev-server/index-html.d.ts +3 -0
- package/dist/dev-server/index-html.js +18 -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.d.ts +0 -1
- package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
- package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
- 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 +111 -2
- package/dist/dev-server/server.js +128 -12
- package/dist/dev-server/ssr-render.d.ts +2 -1
- package/dist/dev-server/ssr-render.js +107 -48
- package/dist/editor/ai/backend.d.ts +20 -0
- package/dist/editor/ai/backend.js +104 -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/opencode-client.d.ts +14 -0
- package/dist/editor/ai/opencode-client.js +125 -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 +587 -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 +17 -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 +75 -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.js +163 -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/router-data.d.ts +5 -0
- package/dist/runtime/router-data.js +121 -16
- package/dist/runtime/router-hydration.js +25 -0
- package/dist/runtime/router.d.ts +21 -1
- package/dist/runtime/router.js +221 -39
- package/dist/runtime/socket-client.d.ts +2 -0
- package/dist/runtime/socket-client.js +30 -0
- package/dist/runtime/webrtc.d.ts +47 -0
- package/dist/runtime/webrtc.js +178 -0
- 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 +16 -0
- package/dist/shared/utils.d.ts +37 -7
- package/dist/shared/utils.js +175 -26
- 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 +116 -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 +20 -1
- package/templates/blog/api/posts.ts +6 -0
- package/templates/blog/data/migrations/001_init.sql +13 -0
- 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 +65 -0
- package/templates/blog/pages/posts/[slug].ts +60 -0
- package/templates/blog/pages/tag/[tag].ts +44 -0
- package/templates/dashboard/api/stats.ts +10 -0
- package/templates/dashboard/data/migrations/001_init.sql +13 -0
- 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 +72 -0
- 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/templates/social/api/posts/[id].ts +14 -0
- package/templates/social/api/posts.ts +11 -0
- package/templates/social/api/profile/[username].ts +10 -0
- package/templates/social/api/upload.ts +19 -0
- package/templates/social/data/migrations/001_init.sql +78 -0
- package/templates/social/data/migrations/002_add_image_url.sql +1 -0
- package/templates/social/data/migrations/003_auth.sql +7 -0
- package/templates/social/docs/architecture.md +76 -0
- package/templates/social/docs/components.md +100 -0
- package/templates/social/docs/data.md +89 -0
- package/templates/social/docs/pages.md +96 -0
- package/templates/social/docs/theming.md +52 -0
- package/templates/social/lib/media.ts +130 -0
- package/templates/social/lumenjs.auth.ts +21 -0
- package/templates/social/lumenjs.config.ts +3 -0
- package/templates/social/package.json +5 -0
- package/templates/social/pages/_layout.ts +239 -0
- package/templates/social/pages/apps/[id].ts +173 -0
- package/templates/social/pages/apps/index.ts +116 -0
- package/templates/social/pages/auth/login.ts +92 -0
- package/templates/social/pages/bookmarks.ts +57 -0
- package/templates/social/pages/explore.ts +73 -0
- package/templates/social/pages/index.ts +351 -0
- package/templates/social/pages/messages.ts +298 -0
- package/templates/social/pages/new.ts +77 -0
- package/templates/social/pages/notifications.ts +73 -0
- package/templates/social/pages/post/[id].ts +124 -0
- package/templates/social/pages/profile/[username].ts +100 -0
- package/templates/social/pages/settings/accessibility.ts +153 -0
- package/templates/social/pages/settings/account.ts +260 -0
- package/templates/social/pages/settings/help.ts +141 -0
- package/templates/social/pages/settings/language.ts +103 -0
- package/templates/social/pages/settings/privacy.ts +183 -0
- package/templates/social/pages/settings/security.ts +133 -0
- 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
|
|
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
|
|
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()`
|
|
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 };
|
|
86
77
|
}
|
|
87
78
|
|
|
88
|
-
@customElement('page-blog-slug')
|
|
89
79
|
export class BlogPost extends LitElement {
|
|
90
|
-
|
|
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
|
-
|
|
99
|
+
## Live Data (subscribe)
|
|
100
|
+
|
|
101
|
+
Export a `subscribe()` to push real-time data over Server-Sent Events.
|
|
111
102
|
|
|
112
103
|
```typescript
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
+
Return a cleanup function — it runs when the client disconnects.
|
|
139
123
|
|
|
140
|
-
Layouts
|
|
124
|
+
## Layouts
|
|
141
125
|
|
|
142
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
170
|
+
import { t, setLocale } from '@lumenjs/i18n';
|
|
261
171
|
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 {};
|