@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
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { LocalStorageAdapter } from '../../storage/adapters/local.js';
|
|
4
|
+
import { setStorage } from '../../storage/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* LumenJS storage plugin (dev mode).
|
|
7
|
+
*
|
|
8
|
+
* - Creates a LocalStorageAdapter pointing to `{projectDir}/uploads`
|
|
9
|
+
* - Registers it as the global storage singleton (`useStorage()`)
|
|
10
|
+
* - Serves uploaded files at `/uploads/*`
|
|
11
|
+
* - Handles presigned PUT requests at `/__nk_storage/upload/:token`
|
|
12
|
+
*/
|
|
13
|
+
export function lumenStoragePlugin(projectDir) {
|
|
14
|
+
const uploadDir = path.join(projectDir, 'uploads');
|
|
15
|
+
const adapter = new LocalStorageAdapter({ uploadDir, publicPath: '/uploads' });
|
|
16
|
+
// Register global singleton so API routes and communication handlers can use it
|
|
17
|
+
setStorage(adapter);
|
|
18
|
+
return {
|
|
19
|
+
name: 'lumenjs-storage',
|
|
20
|
+
configureServer(server) {
|
|
21
|
+
// ── Presigned upload endpoint ──────────────────────────────
|
|
22
|
+
// Client sends a PUT to /__nk_storage/upload/:token with the (possibly
|
|
23
|
+
// encrypted) file body. The token was issued via adapter.presignPut().
|
|
24
|
+
server.middlewares.use('/__nk_storage/upload', async (req, res, next) => {
|
|
25
|
+
if (req.method !== 'PUT')
|
|
26
|
+
return next();
|
|
27
|
+
const token = req.url?.replace(/^\//, '').split('?')[0];
|
|
28
|
+
if (!token) {
|
|
29
|
+
res.statusCode = 400;
|
|
30
|
+
res.end(JSON.stringify({ error: 'missing token' }));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const pending = adapter.consumeUpload(token);
|
|
34
|
+
if (!pending) {
|
|
35
|
+
res.statusCode = 410; // Gone — expired or unknown token
|
|
36
|
+
res.setHeader('Content-Type', 'application/json');
|
|
37
|
+
res.end(JSON.stringify({ error: 'upload token expired or invalid' }));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Read raw body with streaming size enforcement
|
|
41
|
+
const MAX_UPLOAD = pending.maxSize || 50 * 1024 * 1024; // 50MB default cap
|
|
42
|
+
const chunks = [];
|
|
43
|
+
let uploadSize = 0;
|
|
44
|
+
let aborted = false;
|
|
45
|
+
req.on('data', (c) => {
|
|
46
|
+
uploadSize += c.length;
|
|
47
|
+
if (uploadSize > MAX_UPLOAD) {
|
|
48
|
+
aborted = true;
|
|
49
|
+
req.destroy();
|
|
50
|
+
res.statusCode = 413;
|
|
51
|
+
res.setHeader('Content-Type', 'application/json');
|
|
52
|
+
res.end(JSON.stringify({ error: 'file_too_large', maxSize: MAX_UPLOAD, received: uploadSize }));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
chunks.push(c);
|
|
56
|
+
});
|
|
57
|
+
await new Promise((resolve, reject) => {
|
|
58
|
+
req.on('end', resolve);
|
|
59
|
+
req.on('error', reject);
|
|
60
|
+
});
|
|
61
|
+
if (aborted)
|
|
62
|
+
return;
|
|
63
|
+
const body = Buffer.concat(chunks);
|
|
64
|
+
// Enforce maxSize if specified (redundant safety check)
|
|
65
|
+
if (pending.maxSize && body.length > pending.maxSize) {
|
|
66
|
+
res.statusCode = 413;
|
|
67
|
+
res.setHeader('Content-Type', 'application/json');
|
|
68
|
+
res.end(JSON.stringify({
|
|
69
|
+
error: `file_too_large`,
|
|
70
|
+
maxSize: pending.maxSize,
|
|
71
|
+
received: body.length,
|
|
72
|
+
}));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Write to disk (validate path stays within uploadDir)
|
|
76
|
+
const filePath = path.resolve(uploadDir, pending.key);
|
|
77
|
+
if (!filePath.startsWith(uploadDir + path.sep) && filePath !== uploadDir) {
|
|
78
|
+
res.statusCode = 400;
|
|
79
|
+
res.setHeader('Content-Type', 'application/json');
|
|
80
|
+
res.end(JSON.stringify({ error: 'invalid storage key' }));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
84
|
+
fs.writeFileSync(filePath, body);
|
|
85
|
+
res.statusCode = 200;
|
|
86
|
+
res.setHeader('Content-Type', 'application/json');
|
|
87
|
+
res.end(JSON.stringify({
|
|
88
|
+
key: pending.key,
|
|
89
|
+
url: adapter.publicUrl(pending.key),
|
|
90
|
+
size: body.length,
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
// ── Static file serving ────────────────────────────────────
|
|
94
|
+
// Serve files from uploadDir at /uploads/*
|
|
95
|
+
server.middlewares.use('/uploads', (req, res, next) => {
|
|
96
|
+
if (req.method !== 'GET' && req.method !== 'HEAD')
|
|
97
|
+
return next();
|
|
98
|
+
const filePath = path.resolve(uploadDir, (req.url?.split('?')[0] ?? '/').replace(/^\/+/, ''));
|
|
99
|
+
if (!filePath.startsWith(uploadDir + path.sep) && filePath !== uploadDir) {
|
|
100
|
+
return next();
|
|
101
|
+
}
|
|
102
|
+
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
103
|
+
return next();
|
|
104
|
+
}
|
|
105
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
106
|
+
const mimeTypes = {
|
|
107
|
+
'.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png',
|
|
108
|
+
'.gif': 'image/gif', '.webp': 'image/webp', '.svg': 'image/svg+xml',
|
|
109
|
+
'.mp4': 'video/mp4', '.webm': 'video/webm', '.mp3': 'audio/mpeg',
|
|
110
|
+
'.pdf': 'application/pdf', '.json': 'application/json',
|
|
111
|
+
'.txt': 'text/plain', '.bin': 'application/octet-stream',
|
|
112
|
+
};
|
|
113
|
+
const contentType = mimeTypes[ext] ?? 'application/octet-stream';
|
|
114
|
+
const stat = fs.statSync(filePath);
|
|
115
|
+
res.setHeader('Content-Type', contentType);
|
|
116
|
+
res.setHeader('Content-Length', stat.size);
|
|
117
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
118
|
+
if (req.method === 'HEAD') {
|
|
119
|
+
res.end();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
fs.createReadStream(filePath).pipe(res);
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -15,16 +15,38 @@ export function virtualModulesPlugin(runtimeDir, editorDir) {
|
|
|
15
15
|
'router-data': 'router-data.js',
|
|
16
16
|
'router-hydration': 'router-hydration.js',
|
|
17
17
|
'i18n': 'i18n.js',
|
|
18
|
+
'auth': 'auth.js',
|
|
19
|
+
'communication': 'communication.js',
|
|
20
|
+
'webrtc': 'webrtc.js',
|
|
21
|
+
'error-boundary': 'error-boundary.js',
|
|
22
|
+
'hydrate-support': '__virtual__',
|
|
18
23
|
};
|
|
19
24
|
// Modules resolved via resolve.alias instead of virtual module.
|
|
20
25
|
// They still appear in the map so relative import rewrites work.
|
|
21
|
-
const aliasedModules = new Set(['i18n']);
|
|
26
|
+
const aliasedModules = new Set(['i18n', 'auth', 'communication', 'webrtc']);
|
|
22
27
|
const editorModules = {
|
|
23
28
|
'editor-bridge': 'editor-bridge.js',
|
|
24
29
|
'element-annotator': 'element-annotator.js',
|
|
25
30
|
'click-select': 'click-select.js',
|
|
26
31
|
'hover-detect': 'hover-detect.js',
|
|
27
32
|
'inline-text-edit': 'inline-text-edit.js',
|
|
33
|
+
'editor-api-client': 'editor-api-client.js',
|
|
34
|
+
'standalone-overlay': 'standalone-overlay.js',
|
|
35
|
+
'standalone-overlay-dom': 'standalone-overlay-dom.js',
|
|
36
|
+
'standalone-overlay-styles': 'standalone-overlay-styles.js',
|
|
37
|
+
'standalone-file-panel': 'standalone-file-panel.js',
|
|
38
|
+
'overlay-utils': 'overlay-utils.js',
|
|
39
|
+
'text-toolbar': 'text-toolbar.js',
|
|
40
|
+
'editor-toolbar': 'editor-toolbar.js',
|
|
41
|
+
'css-rules': 'css-rules.js',
|
|
42
|
+
'ast-modification': 'ast-modification.js',
|
|
43
|
+
'ast-service': 'ast-service.js',
|
|
44
|
+
'file-service': 'file-service.js',
|
|
45
|
+
'property-registry': 'property-registry.js',
|
|
46
|
+
'properties-panel': 'properties-panel.js',
|
|
47
|
+
'i18n-key-gen': 'i18n-key-gen.js',
|
|
48
|
+
'ai-chat-panel': 'ai-chat-panel.js',
|
|
49
|
+
'ai-project-panel': 'ai-project-panel.js',
|
|
28
50
|
};
|
|
29
51
|
function rewriteRelativeImports(code, modules) {
|
|
30
52
|
for (const name of Object.keys(modules)) {
|
|
@@ -55,8 +77,95 @@ export function virtualModulesPlugin(runtimeDir, editorDir) {
|
|
|
55
77
|
if (!id.startsWith('\0lumenjs:'))
|
|
56
78
|
return;
|
|
57
79
|
const name = id.slice('\0lumenjs:'.length);
|
|
80
|
+
if (name === 'hydrate-support') {
|
|
81
|
+
// Custom hydrate support that catches digest mismatch errors and falls
|
|
82
|
+
// back to CSR instead of leaving double-rendered content.
|
|
83
|
+
// The stock @lit-labs/ssr-client/lit-element-hydrate-support.js throws
|
|
84
|
+
// on digest mismatch, sets _$AG=false before throwing, so the next
|
|
85
|
+
// update() appends fresh render alongside stale SSR content.
|
|
86
|
+
return `
|
|
87
|
+
import { render } from 'lit-html';
|
|
88
|
+
import { hydrate } from '@lit-labs/ssr-client';
|
|
89
|
+
|
|
90
|
+
globalThis.litElementHydrateSupport = ({LitElement}) => {
|
|
91
|
+
const observedGet = Object.getOwnPropertyDescriptor(
|
|
92
|
+
Object.getPrototypeOf(LitElement), 'observedAttributes'
|
|
93
|
+
).get;
|
|
94
|
+
Object.defineProperty(LitElement, 'observedAttributes', {
|
|
95
|
+
get() { return [...observedGet.call(this), 'defer-hydration']; }
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const origAttrChanged = LitElement.prototype.attributeChangedCallback;
|
|
99
|
+
LitElement.prototype.attributeChangedCallback = function(name, old, value) {
|
|
100
|
+
if (name === 'defer-hydration' && value === null) {
|
|
101
|
+
origConnected.call(this);
|
|
102
|
+
}
|
|
103
|
+
origAttrChanged.call(this, name, old, value);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const origConnected = LitElement.prototype.connectedCallback;
|
|
107
|
+
LitElement.prototype.connectedCallback = function() {
|
|
108
|
+
if (!this.hasAttribute('defer-hydration')) origConnected.call(this);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
function adoptElementStyles(el) {
|
|
112
|
+
const styles = el.constructor.elementStyles;
|
|
113
|
+
if (styles?.length && el.renderRoot instanceof ShadowRoot) {
|
|
114
|
+
el.renderRoot.adoptedStyleSheets = styles.map(
|
|
115
|
+
s => s instanceof CSSStyleSheet ? s : s.styleSheet
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const origCreateRoot = LitElement.prototype.createRenderRoot;
|
|
121
|
+
LitElement.prototype.createRenderRoot = function() {
|
|
122
|
+
if (this.shadowRoot) {
|
|
123
|
+
this._$AG = true;
|
|
124
|
+
// Adopt styles that SSR declarative shadow roots don't include
|
|
125
|
+
adoptElementStyles(this);
|
|
126
|
+
return this.shadowRoot;
|
|
127
|
+
}
|
|
128
|
+
return origCreateRoot.call(this);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const superUpdate = Object.getPrototypeOf(LitElement.prototype).update;
|
|
132
|
+
LitElement.prototype.update = function(changedProps) {
|
|
133
|
+
const value = this.render();
|
|
134
|
+
superUpdate.call(this, changedProps);
|
|
135
|
+
if (this._$AG) {
|
|
136
|
+
this._$AG = false;
|
|
137
|
+
for (const attr of this.getAttributeNames()) {
|
|
138
|
+
if (attr.startsWith('hydrate-internals-')) {
|
|
139
|
+
this.removeAttribute(attr.slice(18));
|
|
140
|
+
this.removeAttribute(attr);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
hydrate(value, this.renderRoot, this.renderOptions);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
// Digest mismatch — clear SSR content and render fresh (CSR fallback)
|
|
147
|
+
console.warn('[LumenJS] Hydration failed for <' + this.localName + '>, falling back to CSR:', err.message);
|
|
148
|
+
const root = this.renderRoot;
|
|
149
|
+
while (root.firstChild) root.removeChild(root.firstChild);
|
|
150
|
+
delete root._$litPart$;
|
|
151
|
+
// Re-adopt styles since clearing removed SSR <style> tags
|
|
152
|
+
adoptElementStyles(this);
|
|
153
|
+
render(value, root, this.renderOptions);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
render(value, this.renderRoot, this.renderOptions);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
58
162
|
if (runtimeModules[name]) {
|
|
59
|
-
|
|
163
|
+
let code = fs.readFileSync(path.join(runtimeDir, runtimeModules[name]), 'utf-8');
|
|
164
|
+
// Prepend hydrate support to app-shell so all Lit imports share one module graph.
|
|
165
|
+
// Uses our custom hydrate-support virtual module (with CSR fallback) instead of stock.
|
|
166
|
+
if (name === 'app-shell') {
|
|
167
|
+
code = `import '/@lumenjs/hydrate-support';\n` + code;
|
|
168
|
+
}
|
|
60
169
|
return rewriteRelativeImports(code, runtimeModules);
|
|
61
170
|
}
|
|
62
171
|
if (editorModules[name]) {
|
|
@@ -11,12 +11,21 @@ import { ssrRenderPage } from './ssr-render.js';
|
|
|
11
11
|
import { readProjectConfig, getLumenJSNodeModules, getLumenJSDirs } from './config.js';
|
|
12
12
|
import { getNuralyUIAliases, resolveNuralyUIPaths } from './nuralyui-aliases.js';
|
|
13
13
|
import { litDedupPlugin } from './plugins/vite-plugin-lit-dedup.js';
|
|
14
|
+
import { autoDefinePlugin } from './plugins/vite-plugin-auto-define.js';
|
|
14
15
|
import { autoImportPlugin } from './plugins/vite-plugin-auto-import.js';
|
|
15
16
|
import { litHmrPlugin } from './plugins/vite-plugin-lit-hmr.js';
|
|
16
17
|
import { sourceAnnotatorPlugin } from './plugins/vite-plugin-source-annotator.js';
|
|
18
|
+
import { editorApiPlugin } from './plugins/vite-plugin-editor-api.js';
|
|
17
19
|
import { virtualModulesPlugin } from './plugins/vite-plugin-virtual-modules.js';
|
|
18
20
|
import { i18nPlugin, loadTranslationsFromDisk } from './plugins/vite-plugin-i18n.js';
|
|
21
|
+
import { authPlugin } from './plugins/vite-plugin-auth.js';
|
|
22
|
+
import { communicationPlugin } from './plugins/vite-plugin-communication.js';
|
|
23
|
+
import { lumenStoragePlugin } from './plugins/vite-plugin-storage.js';
|
|
24
|
+
import { lumenSocketIOPlugin } from './plugins/vite-plugin-socketio.js';
|
|
19
25
|
import { resolveLocale } from './middleware/locale.js';
|
|
26
|
+
import { setProjectDir } from '../db/context.js';
|
|
27
|
+
import { scanMiddleware, getMiddlewareDirsForPathname } from '../build/scan.js';
|
|
28
|
+
import { runMiddlewareChain, extractMiddleware } from '../shared/middleware-runner.js';
|
|
20
29
|
// Re-export for backwards compatibility
|
|
21
30
|
export { readProjectConfig, readProjectTitle, getLumenJSNodeModules, getLumenJSDirs } from './config.js';
|
|
22
31
|
export { getNuralyUIAliases, resolveNuralyUIPaths } from './nuralyui-aliases.js';
|
|
@@ -29,24 +38,37 @@ export function getSharedViteConfig(projectDir, options) {
|
|
|
29
38
|
const isDev = mode === 'development';
|
|
30
39
|
const pagesDir = path.join(projectDir, 'pages');
|
|
31
40
|
const lumenNodeModules = getLumenJSNodeModules();
|
|
32
|
-
const { runtimeDir, editorDir } = getLumenJSDirs();
|
|
41
|
+
const { distDir, runtimeDir, editorDir } = getLumenJSDirs();
|
|
33
42
|
// Resolve NuralyUI paths for aliases (only when nuralyui integration is enabled)
|
|
34
43
|
const aliases = {};
|
|
35
44
|
if (options?.integrations?.includes('nuralyui')) {
|
|
36
45
|
const nuralyUIPaths = resolveNuralyUIPaths(projectDir);
|
|
37
46
|
if (nuralyUIPaths) {
|
|
38
47
|
Object.assign(aliases, getNuralyUIAliases(nuralyUIPaths.componentsPath, nuralyUIPaths.commonPath));
|
|
48
|
+
// Add root aliases for theme CSS imports
|
|
49
|
+
const nuralyUIRoot = path.resolve(nuralyUIPaths.componentsPath, '..');
|
|
50
|
+
aliases['@nuralyui-theme'] = path.join(nuralyUIRoot, 'shared/themes');
|
|
51
|
+
aliases['@nuralyui-common'] = nuralyUIPaths.commonPath;
|
|
39
52
|
}
|
|
40
53
|
}
|
|
41
54
|
const resolve = {
|
|
42
55
|
alias: {
|
|
43
56
|
...aliases,
|
|
44
|
-
// Map @lumenjs/i18n to the physical dist file so Vite resolves it
|
|
45
|
-
// without going through node_modules (it's not an npm package).
|
|
46
57
|
'@lumenjs/i18n': path.join(runtimeDir, 'i18n.js'),
|
|
58
|
+
'@lumenjs/auth': path.join(runtimeDir, 'auth.js'),
|
|
59
|
+
'@nuraly/lumenjs-auth': path.join(runtimeDir, 'auth.js'),
|
|
60
|
+
'@lumenjs/communication': path.join(runtimeDir, 'communication.js'),
|
|
61
|
+
'@lumenjs/webrtc': path.join(runtimeDir, 'webrtc.js'),
|
|
62
|
+
'@lumenjs/db': path.join(distDir, 'db', 'client.js'),
|
|
63
|
+
'@lumenjs/permissions': path.join(distDir, 'permissions', 'index.js'),
|
|
64
|
+
'@lumenjs/storage': path.join(distDir, 'storage', 'index.js'),
|
|
65
|
+
'@nuraly/lumenjs': path.resolve(distDir, '..'),
|
|
47
66
|
},
|
|
48
67
|
conditions: isDev ? ['development', 'browser'] : ['browser'],
|
|
49
|
-
|
|
68
|
+
// Note: resolve.dedupe is NOT used — it resolves via Node's algorithm
|
|
69
|
+
// which ignores Vite's resolve.conditions, picking the `default` export
|
|
70
|
+
// (prod proxy) instead of `development`. The litDedupPlugin handles
|
|
71
|
+
// single-copy resolution with correct conditions instead.
|
|
50
72
|
};
|
|
51
73
|
const esbuild = {
|
|
52
74
|
tsconfigRaw: {
|
|
@@ -59,6 +81,7 @@ export function getSharedViteConfig(projectDir, options) {
|
|
|
59
81
|
const plugins = [
|
|
60
82
|
lumenRoutesPlugin(pagesDir),
|
|
61
83
|
lumenLoadersPlugin(pagesDir),
|
|
84
|
+
autoDefinePlugin(pagesDir),
|
|
62
85
|
litDedupPlugin(lumenNodeModules, isDev),
|
|
63
86
|
virtualModulesPlugin(runtimeDir, editorDir),
|
|
64
87
|
];
|
|
@@ -86,7 +109,13 @@ export async function createDevServer(options) {
|
|
|
86
109
|
const apiDir = path.join(projectDir, 'api');
|
|
87
110
|
const publicDir = path.join(projectDir, 'public');
|
|
88
111
|
const config = readProjectConfig(projectDir);
|
|
89
|
-
const { title, integrations, i18n: i18nConfig } = config;
|
|
112
|
+
const { title, integrations, i18n: i18nConfig, prefetch: prefetchStrategy } = config;
|
|
113
|
+
// Read optional head.html for blocking scripts (e.g. theme initialization)
|
|
114
|
+
const headHtmlPath = path.join(projectDir, 'head.html');
|
|
115
|
+
const headContent = fs.existsSync(headHtmlPath) ? fs.readFileSync(headHtmlPath, 'utf-8') : undefined;
|
|
116
|
+
// Set project dir for DB context (used by loaders, API routes, plugins)
|
|
117
|
+
setProjectDir(projectDir);
|
|
118
|
+
process.env.LUMENJS_PROJECT_DIR = projectDir;
|
|
90
119
|
const shared = getSharedViteConfig(projectDir, { integrations });
|
|
91
120
|
const server = await createViteServer({
|
|
92
121
|
root: projectDir,
|
|
@@ -97,15 +126,90 @@ export async function createDevServer(options) {
|
|
|
97
126
|
strictPort: false,
|
|
98
127
|
allowedHosts: true,
|
|
99
128
|
cors: true,
|
|
100
|
-
hmr: true,
|
|
129
|
+
hmr: process.env.HMR_CLIENT_PORT ? { clientPort: parseInt(process.env.HMR_CLIENT_PORT), protocol: process.env.HMR_PROTOCOL || 'wss', host: process.env.HMR_HOST || undefined } : true,
|
|
130
|
+
fs: {
|
|
131
|
+
allow: [projectDir, getLumenJSNodeModules(), path.resolve(getLumenJSNodeModules(), '..')],
|
|
132
|
+
},
|
|
101
133
|
},
|
|
102
134
|
resolve: shared.resolve,
|
|
103
135
|
plugins: [
|
|
136
|
+
...(integrations.includes('auth') ? [authPlugin(projectDir)] : []),
|
|
104
137
|
...shared.plugins,
|
|
138
|
+
...(integrations.includes('communication') ? [communicationPlugin(projectDir)] : []),
|
|
139
|
+
lumenStoragePlugin(projectDir),
|
|
105
140
|
lumenApiRoutesPlugin(apiDir, projectDir),
|
|
106
141
|
litHmrPlugin(projectDir),
|
|
107
142
|
...(i18nConfig ? [i18nPlugin(projectDir, i18nConfig)] : []),
|
|
108
|
-
...(editorMode ? [sourceAnnotatorPlugin(projectDir)] : []),
|
|
143
|
+
...(editorMode ? [sourceAnnotatorPlugin(projectDir), editorApiPlugin(projectDir)] : []),
|
|
144
|
+
lumenSocketIOPlugin(pagesDir),
|
|
145
|
+
{
|
|
146
|
+
// Clear SSR module cache on file changes so the next SSR request uses fresh code.
|
|
147
|
+
// Without this, HMR updates the client but SSR keeps serving stale modules.
|
|
148
|
+
name: 'lumenjs-ssr-invalidate-on-change',
|
|
149
|
+
handleHotUpdate({ file, server }) {
|
|
150
|
+
const mods = server.moduleGraph.getModulesByFile(file);
|
|
151
|
+
if (mods) {
|
|
152
|
+
for (const m of mods) {
|
|
153
|
+
m.ssrModule = null;
|
|
154
|
+
m.ssrTransformResult = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'lumenjs-user-middleware',
|
|
161
|
+
config(config) {
|
|
162
|
+
const entries = scanMiddleware(pagesDir);
|
|
163
|
+
if (entries.length === 0)
|
|
164
|
+
return;
|
|
165
|
+
const npmDeps = new Set();
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
try {
|
|
168
|
+
const content = fs.readFileSync(entry.filePath, 'utf-8');
|
|
169
|
+
const importMatches = content.matchAll(/(?:import|require)\s*(?:\(?\s*['"]([^./][^'"]*)['"]\s*\)?|.*from\s*['"]([^./][^'"]*)['"]\s*)/g);
|
|
170
|
+
for (const m of importMatches) {
|
|
171
|
+
const pkg = m[1] || m[2];
|
|
172
|
+
if (pkg) {
|
|
173
|
+
const pkgName = pkg.startsWith('@') ? pkg.split('/').slice(0, 2).join('/') : pkg.split('/')[0];
|
|
174
|
+
npmDeps.add(pkgName);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch { }
|
|
179
|
+
}
|
|
180
|
+
if (npmDeps.size > 0) {
|
|
181
|
+
const existing = config.ssr?.external || [];
|
|
182
|
+
return { ssr: { external: [...existing, ...npmDeps] } };
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
configureServer(server) {
|
|
186
|
+
server.middlewares.use(async (req, res, next) => {
|
|
187
|
+
const pathname = (req.url || '/').split('?')[0];
|
|
188
|
+
if (pathname.startsWith('/@') || pathname.startsWith('/node_modules') || pathname.includes('.')) {
|
|
189
|
+
return next();
|
|
190
|
+
}
|
|
191
|
+
const middlewareEntries = scanMiddleware(pagesDir);
|
|
192
|
+
if (middlewareEntries.length === 0)
|
|
193
|
+
return next();
|
|
194
|
+
const matchingDirs = getMiddlewareDirsForPathname(pathname, middlewareEntries);
|
|
195
|
+
if (matchingDirs.length === 0)
|
|
196
|
+
return next();
|
|
197
|
+
const allMw = [];
|
|
198
|
+
for (const entry of matchingDirs) {
|
|
199
|
+
try {
|
|
200
|
+
const mod = await server.ssrLoadModule(entry.filePath);
|
|
201
|
+
allMw.push(...extractMiddleware(mod));
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
console.error(`[LumenJS] Failed to load _middleware.ts (${entry.dir || 'root'}):`, err);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (allMw.length === 0)
|
|
208
|
+
return next();
|
|
209
|
+
runMiddlewareChain(allMw, req, res, next);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
},
|
|
109
213
|
{
|
|
110
214
|
name: 'lumenjs-index-html',
|
|
111
215
|
configureServer(server) {
|
|
@@ -136,7 +240,7 @@ export async function createDevServer(options) {
|
|
|
136
240
|
translations = loadTranslationsFromDisk(projectDir, locale);
|
|
137
241
|
}
|
|
138
242
|
const SSR_PLACEHOLDER = '<!--__NK_SSR_CONTENT__-->';
|
|
139
|
-
ssrRenderPage(server, pagesDir, pathname, req.headers, locale).then(async (ssrResult) => {
|
|
243
|
+
ssrRenderPage(server, pagesDir, pathname, req.headers, locale, req.nkAuth?.user ?? undefined).then(async (ssrResult) => {
|
|
140
244
|
if (ssrResult?.redirect) {
|
|
141
245
|
res.writeHead(ssrResult.redirect.status, { Location: ssrResult.redirect.location });
|
|
142
246
|
res.end();
|
|
@@ -152,6 +256,9 @@ export async function createDevServer(options) {
|
|
|
152
256
|
locale,
|
|
153
257
|
i18nConfig: i18nConfig || undefined,
|
|
154
258
|
translations,
|
|
259
|
+
prefetch: prefetchStrategy,
|
|
260
|
+
authUser: ssrResult?.authUser ?? req.nkAuth?.user ?? undefined,
|
|
261
|
+
headContent,
|
|
155
262
|
});
|
|
156
263
|
const transformed = await server.transformIndexHtml(req.url, shellHtml);
|
|
157
264
|
const finalHtml = ssrResult
|
|
@@ -162,7 +269,7 @@ export async function createDevServer(options) {
|
|
|
162
269
|
res.end(finalHtml);
|
|
163
270
|
}).catch(err => {
|
|
164
271
|
console.error('[LumenJS] SSR/HTML generation error:', err);
|
|
165
|
-
const html = generateIndexHtml({ title, editorMode, integrations, locale, i18nConfig: i18nConfig || undefined, translations });
|
|
272
|
+
const html = generateIndexHtml({ title, editorMode, integrations, locale, i18nConfig: i18nConfig || undefined, translations, prefetch: prefetchStrategy, headContent });
|
|
166
273
|
server.transformIndexHtml(req.url, html).then(transformed => {
|
|
167
274
|
res.setHeader('Content-Type', 'text/html');
|
|
168
275
|
res.setHeader('Cache-Control', 'no-store');
|
|
@@ -178,12 +285,21 @@ export async function createDevServer(options) {
|
|
|
178
285
|
],
|
|
179
286
|
esbuild: shared.esbuild,
|
|
180
287
|
optimizeDeps: {
|
|
181
|
-
|
|
182
|
-
|
|
288
|
+
exclude: [
|
|
289
|
+
'@lumenjs/i18n',
|
|
290
|
+
'@nuraly/lumenjs-auth',
|
|
291
|
+
// Lit packages must NOT be pre-bundled — pre-bundling creates separate
|
|
292
|
+
// module entries (/.vite/deps/) alongside raw /@fs/ files, causing
|
|
293
|
+
// multiple lit-html instances. Instead, resolve.dedupe forces all lit
|
|
294
|
+
// imports to a single copy. The project's lit version MUST match
|
|
295
|
+
// lumenjs's lit version for dedupe to work.
|
|
296
|
+
'lit', 'lit-html', 'lit-element', '@lit/reactive-element',
|
|
297
|
+
'@lit-labs/ssr-client',
|
|
298
|
+
],
|
|
183
299
|
},
|
|
184
300
|
ssr: {
|
|
185
301
|
noExternal: true,
|
|
186
|
-
external: ['node-domexception'],
|
|
302
|
+
external: ['node-domexception', 'socket.io-client', 'xmlhttprequest-ssl', 'engine.io-client', 'better-sqlite3', '@lumenjs/db', '@lumenjs/permissions'],
|
|
187
303
|
resolve: {
|
|
188
304
|
conditions: ['node', 'import'],
|
|
189
305
|
},
|
|
@@ -9,7 +9,7 @@ export interface LayoutSSRData {
|
|
|
9
9
|
*
|
|
10
10
|
* Returns pre-rendered HTML and loader data, or null on failure (falls back to CSR).
|
|
11
11
|
*/
|
|
12
|
-
export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, pathname: string, headers?: Record<string, string | string[] | undefined>, locale?: string): Promise<{
|
|
12
|
+
export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, pathname: string, headers?: Record<string, string | string[] | undefined>, locale?: string, user?: any): Promise<{
|
|
13
13
|
html: string;
|
|
14
14
|
loaderData: any;
|
|
15
15
|
layoutsData?: LayoutSSRData[];
|
|
@@ -17,4 +17,5 @@ export declare function ssrRenderPage(server: ViteDevServer, pagesDir: string, p
|
|
|
17
17
|
location: string;
|
|
18
18
|
status: number;
|
|
19
19
|
};
|
|
20
|
+
authUser?: any;
|
|
20
21
|
} | null>;
|