@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { dirToLayoutTagName, fileHasLoader, fileHasSubscribe, filePathToRoute, filePathToTagName } from '../../shared/utils.js';
|
|
3
|
+
import { dirToLayoutTagName, fileHasLoader, fileHasSubscribe, fileHasAuth, fileHasMeta, fileHasStandalone, filePathToRoute, filePathToTagName } from '../../shared/utils.js';
|
|
4
4
|
const VIRTUAL_MODULE_ID = 'virtual:lumenjs-routes';
|
|
5
5
|
const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;
|
|
6
6
|
/**
|
|
@@ -28,7 +28,7 @@ export function lumenRoutesPlugin(pagesDir) {
|
|
|
28
28
|
const tagName = dirToLayoutTagName(relativePath);
|
|
29
29
|
layouts.push({ dir: relativePath.replace(/\\/g, '/'), filePath, tagName });
|
|
30
30
|
}
|
|
31
|
-
if (entry.isDirectory()) {
|
|
31
|
+
if (entry.isDirectory() && !entry.name.startsWith('_')) {
|
|
32
32
|
walkForLayouts(baseDir, path.join(relativePath, entry.name), layouts);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -55,12 +55,18 @@ export function lumenRoutesPlugin(pagesDir) {
|
|
|
55
55
|
function walkDir(baseDir, relativePath, routes) {
|
|
56
56
|
const fullDir = path.join(baseDir, relativePath);
|
|
57
57
|
const entries = fs.readdirSync(fullDir, { withFileTypes: true });
|
|
58
|
+
// Check if this subdirectory contains an index file (folder route)
|
|
59
|
+
// Only applies to subdirectories, not the root pages directory
|
|
60
|
+
const hasIndex = relativePath !== '' && entries.some(e => e.isFile() && /^index\.(ts|js)$/.test(e.name));
|
|
58
61
|
for (const entry of entries) {
|
|
59
62
|
const entryRelative = path.join(relativePath, entry.name);
|
|
60
|
-
if (entry.isDirectory()) {
|
|
63
|
+
if (entry.isDirectory() && !entry.name.startsWith('_')) {
|
|
61
64
|
walkDir(baseDir, entryRelative, routes);
|
|
62
65
|
}
|
|
63
66
|
else if (entry.isFile() && /\.(ts|js)$/.test(entry.name) && !entry.name.startsWith('_')) {
|
|
67
|
+
// In a folder route (has index file), only register the index file and dynamic param files
|
|
68
|
+
if (hasIndex && !/^index\.(ts|js)$/.test(entry.name) && !entry.name.startsWith('['))
|
|
69
|
+
continue;
|
|
64
70
|
const routePath = filePathToRoute(entryRelative);
|
|
65
71
|
const componentPath = path.join(pagesDir, entryRelative);
|
|
66
72
|
const tagName = filePathToTagName(entryRelative);
|
|
@@ -99,8 +105,12 @@ export function lumenRoutesPlugin(pagesDir) {
|
|
|
99
105
|
.map(r => {
|
|
100
106
|
const hasLoader = fileHasLoader(r.componentPath);
|
|
101
107
|
const hasSubscribe = fileHasSubscribe(r.componentPath);
|
|
108
|
+
const hasAuth = fileHasAuth(r.componentPath);
|
|
109
|
+
const hasMeta = fileHasMeta(r.componentPath);
|
|
110
|
+
const isStandalone = fileHasStandalone(r.componentPath);
|
|
102
111
|
const componentPath = r.componentPath.replace(/\\/g, '/');
|
|
103
|
-
|
|
112
|
+
// Standalone pages skip all layouts
|
|
113
|
+
const chain = isStandalone ? [] : getLayoutChain(r.componentPath, layouts);
|
|
104
114
|
let layoutsStr = '';
|
|
105
115
|
if (chain.length > 0) {
|
|
106
116
|
const items = chain.map(l => {
|
|
@@ -111,7 +121,7 @@ export function lumenRoutesPlugin(pagesDir) {
|
|
|
111
121
|
});
|
|
112
122
|
layoutsStr = `, layouts: [${items.join(', ')}]`;
|
|
113
123
|
}
|
|
114
|
-
return ` { path: ${JSON.stringify(r.path)}, tagName: ${JSON.stringify(r.tagName)}${hasLoader ? ', hasLoader: true' : ''}${hasSubscribe ? ', hasSubscribe: true' : ''}, load: () => import('${componentPath}')${layoutsStr} }`;
|
|
124
|
+
return ` { path: ${JSON.stringify(r.path)}, tagName: ${JSON.stringify(r.tagName)}${hasLoader ? ', hasLoader: true' : ''}${hasSubscribe ? ', hasSubscribe: true' : ''}${hasMeta ? ', hasMeta: true' : ''}${hasAuth ? ', __nk_has_auth: true' : ''}, load: () => import('${componentPath}')${layoutsStr} }`;
|
|
115
125
|
})
|
|
116
126
|
.join(',\n');
|
|
117
127
|
return `export const routes = [\n${routeArray}\n];\n`;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileHasSocket, filePathToRoute } from '../../shared/utils.js';
|
|
4
|
+
export function lumenSocketIOPlugin(pagesDir) {
|
|
5
|
+
return {
|
|
6
|
+
name: 'lumenjs-socketio',
|
|
7
|
+
configureServer(server) {
|
|
8
|
+
if (!server.httpServer)
|
|
9
|
+
return;
|
|
10
|
+
import('../../shared/socket-io-setup.js').then(({ setupSocketIO }) => {
|
|
11
|
+
const routes = scanSocketRoutes(pagesDir);
|
|
12
|
+
setupSocketIO({
|
|
13
|
+
httpServer: server.httpServer,
|
|
14
|
+
loadModule: (fp) => server.ssrLoadModule(fp),
|
|
15
|
+
routes,
|
|
16
|
+
projectDir: path.dirname(pagesDir),
|
|
17
|
+
}).catch((err) => {
|
|
18
|
+
console.warn('[LumenJS] Socket.IO setup failed:', err.message);
|
|
19
|
+
console.warn('[LumenJS] Make sure socket.io is installed: lumenjs add socketio');
|
|
20
|
+
});
|
|
21
|
+
}).catch((err) => {
|
|
22
|
+
console.warn('[LumenJS] Socket.IO plugin load failed:', err.message);
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function scanSocketRoutes(pagesDir) {
|
|
28
|
+
const routes = [];
|
|
29
|
+
if (!fs.existsSync(pagesDir))
|
|
30
|
+
return routes;
|
|
31
|
+
walkDir(pagesDir, '', routes, pagesDir);
|
|
32
|
+
return routes;
|
|
33
|
+
}
|
|
34
|
+
function walkDir(baseDir, relativePath, routes, pagesDir) {
|
|
35
|
+
const fullDir = path.join(baseDir, relativePath);
|
|
36
|
+
const entries = fs.readdirSync(fullDir, { withFileTypes: true });
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const entryRelative = path.join(relativePath, entry.name);
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
walkDir(baseDir, entryRelative, routes, pagesDir);
|
|
41
|
+
}
|
|
42
|
+
else if (entry.isFile() && /\.(ts|js)$/.test(entry.name) && !entry.name.startsWith('_')) {
|
|
43
|
+
const filePath = path.join(pagesDir, entryRelative);
|
|
44
|
+
const hasSocket = fileHasSocket(filePath);
|
|
45
|
+
if (hasSocket) {
|
|
46
|
+
const routePath = filePathToRoute(entryRelative);
|
|
47
|
+
routes.push({ path: routePath, hasSocket: true, filePath });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
/**
|
|
3
3
|
* In editor mode, inject data-nk-source attributes into html`` template literals.
|
|
4
|
+
* Reads the original source file from disk to compute correct line numbers,
|
|
5
|
+
* since Vite's transform hook receives esbuild-compiled code with shifted lines.
|
|
4
6
|
*/
|
|
5
7
|
export declare function sourceAnnotatorPlugin(projectDir: string): Plugin;
|
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
2
3
|
/**
|
|
3
4
|
* In editor mode, inject data-nk-source attributes into html`` template literals.
|
|
5
|
+
* Reads the original source file from disk to compute correct line numbers,
|
|
6
|
+
* since Vite's transform hook receives esbuild-compiled code with shifted lines.
|
|
4
7
|
*/
|
|
5
8
|
export function sourceAnnotatorPlugin(projectDir) {
|
|
6
9
|
return {
|
|
7
10
|
name: 'lumenjs-source-annotator',
|
|
11
|
+
enforce: 'pre',
|
|
8
12
|
transform(code, id) {
|
|
9
13
|
if (!id.startsWith(projectDir) || !id.endsWith('.ts'))
|
|
10
14
|
return;
|
|
11
15
|
if (!code.includes('html`'))
|
|
12
16
|
return;
|
|
17
|
+
// Read the original source to get correct line numbers
|
|
18
|
+
let originalSource;
|
|
19
|
+
try {
|
|
20
|
+
originalSource = fs.readFileSync(id, 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
originalSource = code;
|
|
24
|
+
}
|
|
13
25
|
const relativePath = path.relative(projectDir, id);
|
|
26
|
+
// Build ordered list of html` base lines from original source
|
|
27
|
+
const originalBaseLines = [];
|
|
28
|
+
const origRegex = /html`/g;
|
|
29
|
+
let origMatch;
|
|
30
|
+
while ((origMatch = origRegex.exec(originalSource)) !== null) {
|
|
31
|
+
const before = originalSource.substring(0, origMatch.index + 5); // include 'html`'
|
|
32
|
+
originalBaseLines.push(before.split('\n').length);
|
|
33
|
+
}
|
|
34
|
+
let templateIndex = 0;
|
|
14
35
|
const transformed = code.replace(/html`([\s\S]*?)`/g, (match, templateContent) => {
|
|
15
36
|
let offset = 0;
|
|
16
|
-
|
|
17
|
-
const baseLine =
|
|
18
|
-
|
|
37
|
+
// Use original source line for this Nth html` template
|
|
38
|
+
const baseLine = originalBaseLines[templateIndex] ?? code.substring(0, code.indexOf(match)).split('\n').length;
|
|
39
|
+
templateIndex++;
|
|
40
|
+
// Annotate both custom elements (tags with hyphens) and standard HTML elements
|
|
41
|
+
const annotated = templateContent.replace(/<((?:[a-z][a-z0-9]*-[a-z0-9-]*)|(?:div|section|article|aside|main|nav|header|footer|h[1-6]|p|span|a|ul|ol|li|button|form|input|textarea|select|label|img|table|tr|td|th|thead|tbody))([\s>])/gi, (tagMatch, tagName, after) => {
|
|
19
42
|
const beforeTag = templateContent.substring(0, templateContent.indexOf(tagMatch, offset));
|
|
20
43
|
const lineInTemplate = beforeTag.split('\n').length - 1;
|
|
21
44
|
offset = templateContent.indexOf(tagMatch, offset) + tagMatch.length;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* LumenJS storage plugin (dev mode).
|
|
4
|
+
*
|
|
5
|
+
* - Creates a LocalStorageAdapter pointing to `{projectDir}/uploads`
|
|
6
|
+
* - Registers it as the global storage singleton (`useStorage()`)
|
|
7
|
+
* - Serves uploaded files at `/uploads/*`
|
|
8
|
+
* - Handles presigned PUT requests at `/__nk_storage/upload/:token`
|
|
9
|
+
*/
|
|
10
|
+
export declare function lumenStoragePlugin(projectDir: string): Plugin;
|
|
@@ -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]) {
|