@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.
- 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 +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 +48 -120
- package/dist/build/scan.d.ts +17 -0
- package/dist/build/scan.js +76 -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 +218 -15
- 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 +23 -20
- 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.js +146 -13
- package/dist/dev-server/plugins/vite-plugin-routes.js +15 -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 +111 -2
- package/dist/dev-server/server.js +127 -13
- 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 +3 -0
- package/dist/runtime/router-data.js +102 -17
- package/dist/runtime/router-hydration.js +25 -0
- package/dist/runtime/router.d.ts +16 -1
- package/dist/runtime/router.js +188 -42
- 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 +14 -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 +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 +19 -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/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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { sendJson } from './routes/utils.js';
|
|
2
|
+
import { handleNativeLogin, handleOidcLogin } from './routes/login.js';
|
|
3
|
+
import { handleNativeSignup } from './routes/signup.js';
|
|
4
|
+
import { handleOidcCallback } from './routes/oidc-callback.js';
|
|
5
|
+
import { handleLogout, handleLogoutAll } from './routes/logout.js';
|
|
6
|
+
import { handleVerifyEmail } from './routes/verify.js';
|
|
7
|
+
import { handleForgotPassword, handleResetPassword, handleChangePassword } from './routes/password.js';
|
|
8
|
+
import { handleTokenRefresh, handleTokenRevoke } from './routes/token.js';
|
|
9
|
+
/**
|
|
10
|
+
* Validate Origin header on POST requests to prevent CSRF.
|
|
11
|
+
* Returns true if the request is safe to proceed.
|
|
12
|
+
*/
|
|
13
|
+
function checkOrigin(req, url) {
|
|
14
|
+
if (req.method !== 'POST')
|
|
15
|
+
return true;
|
|
16
|
+
const origin = req.headers.origin || req.headers.referer;
|
|
17
|
+
if (!origin)
|
|
18
|
+
return true; // Allow requests without Origin (non-browser clients)
|
|
19
|
+
try {
|
|
20
|
+
const originUrl = new URL(origin);
|
|
21
|
+
// Direct match
|
|
22
|
+
if (originUrl.origin === url.origin)
|
|
23
|
+
return true;
|
|
24
|
+
// Behind reverse proxy: check X-Forwarded-Host
|
|
25
|
+
const fwdHost = req.headers['x-forwarded-host']?.split(',')[0]?.trim();
|
|
26
|
+
if (fwdHost && originUrl.host === fwdHost)
|
|
27
|
+
return true;
|
|
28
|
+
// Match hostname only (ignore port differences from proxy)
|
|
29
|
+
if (originUrl.hostname === url.hostname)
|
|
30
|
+
return true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle auth routes (login, callback, logout, signup, me).
|
|
39
|
+
* Supports both OIDC and native auth.
|
|
40
|
+
* Returns true if the request was handled.
|
|
41
|
+
*/
|
|
42
|
+
export async function handleAuthRoutes(config, req, res, db) {
|
|
43
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
44
|
+
const pathname = url.pathname;
|
|
45
|
+
const routes = config.routes;
|
|
46
|
+
// CSRF check: verify Origin header on POST requests
|
|
47
|
+
if (req.method === 'POST' && !checkOrigin(req, url)) {
|
|
48
|
+
sendJson(res, 403, { error: 'Origin mismatch — possible CSRF' });
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
// ── Login (GET) — redirect to OIDC or show available methods ──
|
|
52
|
+
// /__nk_auth/login/<provider> — specific provider
|
|
53
|
+
// /__nk_auth/login — default provider or first OIDC
|
|
54
|
+
if (pathname.startsWith(routes.login)) {
|
|
55
|
+
const providerName = pathname.slice(routes.login.length + 1) || undefined; // e.g. "keycloak"
|
|
56
|
+
// Native login via POST
|
|
57
|
+
if (req.method === 'POST') {
|
|
58
|
+
return handleNativeLogin(config, req, res, url, db);
|
|
59
|
+
}
|
|
60
|
+
// OIDC login
|
|
61
|
+
return handleOidcLogin(config, res, url, providerName);
|
|
62
|
+
}
|
|
63
|
+
// ── Signup (POST) — native registration ───────────────────────
|
|
64
|
+
if (pathname === routes.signup && req.method === 'POST') {
|
|
65
|
+
return handleNativeSignup(config, req, res, db);
|
|
66
|
+
}
|
|
67
|
+
// ── Callback — OIDC code exchange ─────────────────────────────
|
|
68
|
+
if (pathname === routes.callback) {
|
|
69
|
+
return handleOidcCallback(config, req, res, url, db);
|
|
70
|
+
}
|
|
71
|
+
// ── Logout ────────────────────────────────────────────────────
|
|
72
|
+
if (pathname === routes.logout) {
|
|
73
|
+
return handleLogout(config, req, res, url, db);
|
|
74
|
+
}
|
|
75
|
+
// ── Logout All — invalidate all sessions across devices ──────
|
|
76
|
+
if (pathname === '/__nk_auth/logout-all' && req.method === 'POST') {
|
|
77
|
+
return handleLogoutAll(config, req, res, db);
|
|
78
|
+
}
|
|
79
|
+
// ── Me — return current user ──────────────────────────────────
|
|
80
|
+
if (pathname === '/__nk_auth/me') {
|
|
81
|
+
const user = req.nkAuth?.user ?? null;
|
|
82
|
+
sendJson(res, 200, user);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
// ── Verify email ───────────────────────────────────────────────
|
|
86
|
+
if (pathname === '/__nk_auth/verify-email' && req.method === 'GET') {
|
|
87
|
+
return handleVerifyEmail(config, url, res, db);
|
|
88
|
+
}
|
|
89
|
+
// ── Forgot password (request reset) ───────────────────────────
|
|
90
|
+
if (pathname === '/__nk_auth/forgot-password' && req.method === 'POST') {
|
|
91
|
+
return handleForgotPassword(config, req, res, db);
|
|
92
|
+
}
|
|
93
|
+
// ── Reset password (with token) ───────────────────────────────
|
|
94
|
+
if (pathname === '/__nk_auth/reset-password' && req.method === 'POST') {
|
|
95
|
+
return handleResetPassword(config, req, res, db);
|
|
96
|
+
}
|
|
97
|
+
// ── Change password (authenticated) ──────────────────────────
|
|
98
|
+
if (pathname === '/__nk_auth/change-password' && req.method === 'POST') {
|
|
99
|
+
return handleChangePassword(config, req, res, db);
|
|
100
|
+
}
|
|
101
|
+
// ── Refresh — exchange refresh token for new access token ─────
|
|
102
|
+
if (pathname === '/__nk_auth/refresh' && req.method === 'POST') {
|
|
103
|
+
return handleTokenRefresh(config, req, res, db);
|
|
104
|
+
}
|
|
105
|
+
// ── Revoke — invalidate refresh token (mobile logout) ─────────
|
|
106
|
+
if (pathname === '/__nk_auth/revoke' && req.method === 'POST') {
|
|
107
|
+
return handleTokenRevoke(req, res, db);
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SessionData } from './types.js';
|
|
2
|
+
export declare function deriveKey(secret: string): Buffer;
|
|
3
|
+
export declare function encryptSession(data: SessionData, secret: string): Promise<string>;
|
|
4
|
+
export declare function decryptSession(cookie: string, secret: string): Promise<SessionData | null>;
|
|
5
|
+
export declare function createSessionCookie(name: string, value: string, maxAge: number, secure: boolean): string;
|
|
6
|
+
export declare function clearSessionCookie(name: string): string;
|
|
7
|
+
export declare function parseSessionCookie(cookieHeader: string, name: string): string | undefined;
|
|
8
|
+
export declare function shouldRefreshSession(session: SessionData): boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
const keyCache = new Map();
|
|
3
|
+
export function deriveKey(secret) {
|
|
4
|
+
const cached = keyCache.get(secret);
|
|
5
|
+
if (cached)
|
|
6
|
+
return cached;
|
|
7
|
+
const key = Buffer.from(crypto.hkdfSync('sha256', secret, '', 'lumenjs-session', 32));
|
|
8
|
+
keyCache.set(secret, key);
|
|
9
|
+
return key;
|
|
10
|
+
}
|
|
11
|
+
export async function encryptSession(data, secret) {
|
|
12
|
+
const key = deriveKey(secret);
|
|
13
|
+
const iv = crypto.randomBytes(12);
|
|
14
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
15
|
+
const plaintext = JSON.stringify(data);
|
|
16
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
17
|
+
const tag = cipher.getAuthTag();
|
|
18
|
+
return `${iv.toString('base64url')}.${ciphertext.toString('base64url')}.${tag.toString('base64url')}`;
|
|
19
|
+
}
|
|
20
|
+
export async function decryptSession(cookie, secret) {
|
|
21
|
+
try {
|
|
22
|
+
const parts = cookie.split('.');
|
|
23
|
+
if (parts.length !== 3)
|
|
24
|
+
return null;
|
|
25
|
+
const iv = Buffer.from(parts[0], 'base64url');
|
|
26
|
+
const ciphertext = Buffer.from(parts[1], 'base64url');
|
|
27
|
+
const tag = Buffer.from(parts[2], 'base64url');
|
|
28
|
+
const key = deriveKey(secret);
|
|
29
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
30
|
+
decipher.setAuthTag(tag);
|
|
31
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
32
|
+
return JSON.parse(plaintext.toString('utf8'));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function createSessionCookie(name, value, maxAge, secure) {
|
|
39
|
+
let cookie = `${name}=${value}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${maxAge}`;
|
|
40
|
+
if (secure)
|
|
41
|
+
cookie += '; Secure';
|
|
42
|
+
return cookie;
|
|
43
|
+
}
|
|
44
|
+
export function clearSessionCookie(name) {
|
|
45
|
+
return `${name}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0`;
|
|
46
|
+
}
|
|
47
|
+
export function parseSessionCookie(cookieHeader, name) {
|
|
48
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
49
|
+
const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${escapedName}=([^;]*)`));
|
|
50
|
+
return match ? match[1] : undefined;
|
|
51
|
+
}
|
|
52
|
+
export function shouldRefreshSession(session) {
|
|
53
|
+
return session.expiresAt - Date.now() / 1000 < 300;
|
|
54
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AuthUser } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Issue a short-lived access token (HMAC-SHA256 signed, stateless).
|
|
4
|
+
* Format: base64url(payload).base64url(signature)
|
|
5
|
+
*/
|
|
6
|
+
export declare function issueAccessToken(user: AuthUser, secret: string, ttlSeconds: number): string;
|
|
7
|
+
/**
|
|
8
|
+
* Verify and decode an access token. Returns the user or null if invalid/expired.
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyAccessToken(token: string, secret: string): AuthUser | null;
|
|
11
|
+
/**
|
|
12
|
+
* Generate an opaque refresh token (random bytes, stored hashed in DB).
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateRefreshToken(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Hash a refresh token for DB storage (SHA-256).
|
|
17
|
+
*/
|
|
18
|
+
export declare function hashRefreshToken(token: string): string;
|
|
19
|
+
interface Db {
|
|
20
|
+
all<T = any>(sql: string, ...params: any[]): Promise<T[]>;
|
|
21
|
+
get<T = any>(sql: string, ...params: any[]): Promise<T | undefined>;
|
|
22
|
+
run(sql: string, ...params: any[]): Promise<{
|
|
23
|
+
changes: number;
|
|
24
|
+
lastInsertRowid: number | bigint;
|
|
25
|
+
}>;
|
|
26
|
+
exec(sql: string): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare function ensureRefreshTokenTable(db: Db): Promise<void>;
|
|
29
|
+
export declare function storeRefreshToken(db: Db, token: string, userId: string, ttlSeconds: number): Promise<void>;
|
|
30
|
+
export declare function validateRefreshToken(db: Db, token: string): Promise<string | null>;
|
|
31
|
+
export declare function deleteRefreshToken(db: Db, token: string): Promise<void>;
|
|
32
|
+
export declare function deleteAllRefreshTokens(db: Db, userId: string): Promise<void>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Issue a short-lived access token (HMAC-SHA256 signed, stateless).
|
|
4
|
+
* Format: base64url(payload).base64url(signature)
|
|
5
|
+
*/
|
|
6
|
+
export function issueAccessToken(user, secret, ttlSeconds) {
|
|
7
|
+
const payload = {
|
|
8
|
+
sub: user.sub,
|
|
9
|
+
email: user.email,
|
|
10
|
+
name: user.name,
|
|
11
|
+
roles: user.roles || [],
|
|
12
|
+
provider: user.provider,
|
|
13
|
+
iat: Math.floor(Date.now() / 1000),
|
|
14
|
+
exp: Math.floor(Date.now() / 1000) + ttlSeconds,
|
|
15
|
+
};
|
|
16
|
+
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
17
|
+
const signature = crypto.createHmac('sha256', secret).update(payloadB64).digest('base64url');
|
|
18
|
+
return `${payloadB64}.${signature}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Verify and decode an access token. Returns the user or null if invalid/expired.
|
|
22
|
+
*/
|
|
23
|
+
export function verifyAccessToken(token, secret) {
|
|
24
|
+
try {
|
|
25
|
+
const parts = token.split('.');
|
|
26
|
+
if (parts.length !== 2)
|
|
27
|
+
return null;
|
|
28
|
+
const [payloadB64, signature] = parts;
|
|
29
|
+
const expectedSig = crypto.createHmac('sha256', secret).update(payloadB64).digest('base64url');
|
|
30
|
+
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSig)))
|
|
31
|
+
return null;
|
|
32
|
+
const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));
|
|
33
|
+
if (payload.exp < Math.floor(Date.now() / 1000))
|
|
34
|
+
return null;
|
|
35
|
+
return {
|
|
36
|
+
sub: payload.sub,
|
|
37
|
+
email: payload.email,
|
|
38
|
+
name: payload.name,
|
|
39
|
+
roles: payload.roles || [],
|
|
40
|
+
provider: payload.provider,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate an opaque refresh token (random bytes, stored hashed in DB).
|
|
49
|
+
*/
|
|
50
|
+
export function generateRefreshToken() {
|
|
51
|
+
return crypto.randomBytes(32).toString('base64url');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Hash a refresh token for DB storage (SHA-256).
|
|
55
|
+
*/
|
|
56
|
+
export function hashRefreshToken(token) {
|
|
57
|
+
return crypto.createHash('sha256').update(token).digest('hex');
|
|
58
|
+
}
|
|
59
|
+
export async function ensureRefreshTokenTable(db) {
|
|
60
|
+
await db.exec(`CREATE TABLE IF NOT EXISTS _nk_auth_refresh_tokens (
|
|
61
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
62
|
+
token_hash TEXT NOT NULL UNIQUE,
|
|
63
|
+
user_id TEXT NOT NULL,
|
|
64
|
+
expires_at TEXT NOT NULL,
|
|
65
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
66
|
+
)`);
|
|
67
|
+
}
|
|
68
|
+
export async function storeRefreshToken(db, token, userId, ttlSeconds) {
|
|
69
|
+
const tokenHash = hashRefreshToken(token);
|
|
70
|
+
const expiresAt = new Date(Date.now() + ttlSeconds * 1000).toISOString();
|
|
71
|
+
await db.run('INSERT INTO _nk_auth_refresh_tokens (token_hash, user_id, expires_at) VALUES (?, ?, ?)', tokenHash, userId, expiresAt);
|
|
72
|
+
}
|
|
73
|
+
export async function validateRefreshToken(db, token) {
|
|
74
|
+
const tokenHash = hashRefreshToken(token);
|
|
75
|
+
const row = await db.get('SELECT user_id, expires_at FROM _nk_auth_refresh_tokens WHERE token_hash = ?', tokenHash);
|
|
76
|
+
if (!row)
|
|
77
|
+
return null;
|
|
78
|
+
if (new Date(row.expires_at) < new Date()) {
|
|
79
|
+
await db.run('DELETE FROM _nk_auth_refresh_tokens WHERE token_hash = ?', tokenHash);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return row.user_id;
|
|
83
|
+
}
|
|
84
|
+
export async function deleteRefreshToken(db, token) {
|
|
85
|
+
const tokenHash = hashRefreshToken(token);
|
|
86
|
+
await db.run('DELETE FROM _nk_auth_refresh_tokens WHERE token_hash = ?', tokenHash);
|
|
87
|
+
}
|
|
88
|
+
export async function deleteAllRefreshTokens(db, userId) {
|
|
89
|
+
await db.run('DELETE FROM _nk_auth_refresh_tokens WHERE user_id = ?', userId);
|
|
90
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
export interface OIDCProvider {
|
|
2
|
+
type: 'oidc';
|
|
3
|
+
name: string;
|
|
4
|
+
issuer: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
scopes?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface NativeProvider {
|
|
10
|
+
type: 'native';
|
|
11
|
+
name: string;
|
|
12
|
+
/** Minimum password length. Default: 8 */
|
|
13
|
+
minPasswordLength?: number;
|
|
14
|
+
/** Allow user registration. Default: true */
|
|
15
|
+
allowRegistration?: boolean;
|
|
16
|
+
/** Require email verification before login. Default: false */
|
|
17
|
+
requireEmailVerification?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Auth event types for hooks (email sending, logging, etc.) */
|
|
20
|
+
export type AuthEvent = {
|
|
21
|
+
type: 'verification-email';
|
|
22
|
+
email: string;
|
|
23
|
+
token: string;
|
|
24
|
+
url: string;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'password-reset';
|
|
27
|
+
email: string;
|
|
28
|
+
token: string;
|
|
29
|
+
url: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'password-changed';
|
|
32
|
+
email: string;
|
|
33
|
+
userId: string;
|
|
34
|
+
};
|
|
35
|
+
export type AuthProvider = OIDCProvider | NativeProvider;
|
|
36
|
+
export interface AuthConfig {
|
|
37
|
+
/** Single provider (legacy) or array of providers */
|
|
38
|
+
provider?: {
|
|
39
|
+
issuer: string;
|
|
40
|
+
clientId: string;
|
|
41
|
+
clientSecret?: string;
|
|
42
|
+
scopes?: string[];
|
|
43
|
+
};
|
|
44
|
+
/** Multi-provider config (preferred) */
|
|
45
|
+
providers?: AuthProvider[];
|
|
46
|
+
session: {
|
|
47
|
+
secret: string;
|
|
48
|
+
cookieName?: string;
|
|
49
|
+
maxAge?: number;
|
|
50
|
+
secure?: boolean;
|
|
51
|
+
};
|
|
52
|
+
routes?: {
|
|
53
|
+
login?: string;
|
|
54
|
+
loginPage?: string;
|
|
55
|
+
callback?: string;
|
|
56
|
+
logout?: string;
|
|
57
|
+
signup?: string;
|
|
58
|
+
postLogin?: string;
|
|
59
|
+
postLogout?: string;
|
|
60
|
+
me?: string;
|
|
61
|
+
};
|
|
62
|
+
guards?: {
|
|
63
|
+
defaultAuth?: boolean;
|
|
64
|
+
};
|
|
65
|
+
permissions?: {
|
|
66
|
+
enabled?: boolean;
|
|
67
|
+
defaultOwnerGrants?: string[];
|
|
68
|
+
};
|
|
69
|
+
token?: {
|
|
70
|
+
enabled?: boolean;
|
|
71
|
+
/** Access token TTL in seconds. Default: 900 (15 min) */
|
|
72
|
+
accessTokenTTL?: number;
|
|
73
|
+
/** Refresh token TTL in seconds. Default: 604800 (7 days) */
|
|
74
|
+
refreshTokenTTL?: number;
|
|
75
|
+
};
|
|
76
|
+
/** Hook called for auth events (send verification emails, password reset emails, etc.) */
|
|
77
|
+
onEvent?: (event: AuthEvent) => void | Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
export interface ResolvedAuthConfig {
|
|
80
|
+
providers: AuthProvider[];
|
|
81
|
+
session: {
|
|
82
|
+
secret: string;
|
|
83
|
+
cookieName: string;
|
|
84
|
+
maxAge: number;
|
|
85
|
+
secure: boolean;
|
|
86
|
+
};
|
|
87
|
+
routes: {
|
|
88
|
+
login: string;
|
|
89
|
+
loginPage: string;
|
|
90
|
+
callback: string;
|
|
91
|
+
logout: string;
|
|
92
|
+
signup: string;
|
|
93
|
+
postLogin: string;
|
|
94
|
+
postLogout: string;
|
|
95
|
+
};
|
|
96
|
+
guards: {
|
|
97
|
+
defaultAuth: boolean;
|
|
98
|
+
};
|
|
99
|
+
permissions: {
|
|
100
|
+
enabled: boolean;
|
|
101
|
+
defaultOwnerGrants: string[];
|
|
102
|
+
};
|
|
103
|
+
token: {
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
accessTokenTTL: number;
|
|
106
|
+
refreshTokenTTL: number;
|
|
107
|
+
};
|
|
108
|
+
onEvent?: (event: AuthEvent) => void | Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
export interface TokenResponse {
|
|
111
|
+
accessToken: string;
|
|
112
|
+
refreshToken: string;
|
|
113
|
+
expiresIn: number;
|
|
114
|
+
tokenType: 'Bearer';
|
|
115
|
+
user: AuthUser;
|
|
116
|
+
}
|
|
117
|
+
export interface AuthUser {
|
|
118
|
+
sub: string;
|
|
119
|
+
email?: string;
|
|
120
|
+
name?: string;
|
|
121
|
+
preferred_username?: string;
|
|
122
|
+
roles: string[];
|
|
123
|
+
/** Which provider authenticated this user */
|
|
124
|
+
provider?: string;
|
|
125
|
+
[key: string]: unknown;
|
|
126
|
+
}
|
|
127
|
+
export interface SessionData {
|
|
128
|
+
accessToken: string;
|
|
129
|
+
refreshToken?: string;
|
|
130
|
+
idToken?: string;
|
|
131
|
+
expiresAt: number;
|
|
132
|
+
user: AuthUser;
|
|
133
|
+
/** Which provider created this session */
|
|
134
|
+
provider?: string;
|
|
135
|
+
/** Epoch seconds when session was created — used for logout-all invalidation */
|
|
136
|
+
createdAt?: number;
|
|
137
|
+
}
|
|
138
|
+
export interface NkAuth {
|
|
139
|
+
user: AuthUser;
|
|
140
|
+
session: SessionData;
|
|
141
|
+
}
|
|
142
|
+
export interface OIDCMetadata {
|
|
143
|
+
authorization_endpoint: string;
|
|
144
|
+
token_endpoint: string;
|
|
145
|
+
userinfo_endpoint: string;
|
|
146
|
+
end_session_endpoint?: string;
|
|
147
|
+
jwks_uri: string;
|
|
148
|
+
issuer: string;
|
|
149
|
+
}
|
|
150
|
+
export interface TokenSet {
|
|
151
|
+
access_token: string;
|
|
152
|
+
refresh_token?: string;
|
|
153
|
+
id_token?: string;
|
|
154
|
+
expires_in: number;
|
|
155
|
+
token_type: string;
|
|
156
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type UserConfig, type Plugin } from 'vite';
|
|
2
|
+
export interface BuildClientOptions {
|
|
3
|
+
projectDir: string;
|
|
4
|
+
clientDir: string;
|
|
5
|
+
title: string;
|
|
6
|
+
integrations: string[];
|
|
7
|
+
prefetchStrategy: 'hover' | 'viewport' | 'none';
|
|
8
|
+
publicDir: string;
|
|
9
|
+
shared: {
|
|
10
|
+
resolve: UserConfig['resolve'];
|
|
11
|
+
esbuild: UserConfig['esbuild'];
|
|
12
|
+
plugins: Plugin[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function buildClient(opts: BuildClientOptions): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { build as viteBuild } from 'vite';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { generateIndexHtml } from '../dev-server/index-html.js';
|
|
5
|
+
export async function buildClient(opts) {
|
|
6
|
+
const { projectDir, clientDir, title, integrations, prefetchStrategy, publicDir, shared } = opts;
|
|
7
|
+
console.log('[LumenJS] Building client bundle...');
|
|
8
|
+
// Read optional head.html for blocking scripts (e.g. theme initialization)
|
|
9
|
+
const headHtmlPath = path.join(projectDir, 'head.html');
|
|
10
|
+
const headContent = fs.existsSync(headHtmlPath) ? fs.readFileSync(headHtmlPath, 'utf-8') : undefined;
|
|
11
|
+
// Generate index.html as build entry
|
|
12
|
+
const indexHtml = generateIndexHtml({ title, editorMode: false, integrations, prefetch: prefetchStrategy, headContent });
|
|
13
|
+
const tempIndexPath = path.join(projectDir, '__nk_build_index.html');
|
|
14
|
+
fs.writeFileSync(tempIndexPath, indexHtml);
|
|
15
|
+
try {
|
|
16
|
+
await viteBuild({
|
|
17
|
+
root: projectDir,
|
|
18
|
+
publicDir: fs.existsSync(publicDir) ? publicDir : undefined,
|
|
19
|
+
resolve: shared.resolve,
|
|
20
|
+
plugins: shared.plugins,
|
|
21
|
+
esbuild: shared.esbuild,
|
|
22
|
+
build: {
|
|
23
|
+
outDir: clientDir,
|
|
24
|
+
emptyOutDir: true,
|
|
25
|
+
rollupOptions: {
|
|
26
|
+
input: tempIndexPath,
|
|
27
|
+
external: ['mermaid', 'monaco-editor', 'monacopilot', '@lumenjs/db', '@lumenjs/permissions', '@lumenjs/storage'],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
logLevel: 'warn',
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
// Clean up temp file
|
|
35
|
+
if (fs.existsSync(tempIndexPath)) {
|
|
36
|
+
fs.unlinkSync(tempIndexPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Rename the built HTML file from __nk_build_index.html to index.html
|
|
40
|
+
const builtHtmlPath = path.join(clientDir, '__nk_build_index.html');
|
|
41
|
+
const finalHtmlPath = path.join(clientDir, 'index.html');
|
|
42
|
+
if (fs.existsSync(builtHtmlPath)) {
|
|
43
|
+
fs.renameSync(builtHtmlPath, finalHtmlPath);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BuildManifest } from '../shared/types.js';
|
|
2
|
+
import type { PageEntry, LayoutEntry } from './scan.js';
|
|
3
|
+
export interface PrerenderOptions {
|
|
4
|
+
serverDir: string;
|
|
5
|
+
clientDir: string;
|
|
6
|
+
pagesDir: string;
|
|
7
|
+
pageEntries: PageEntry[];
|
|
8
|
+
layoutEntries: LayoutEntry[];
|
|
9
|
+
manifest: BuildManifest;
|
|
10
|
+
}
|
|
11
|
+
export declare function prerenderPages(opts: PrerenderOptions): Promise<void>;
|