@nuraly/lumenjs 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -235
- package/dist/auth/config.d.ts +23 -0
- package/dist/auth/config.js +115 -0
- package/dist/auth/guard.d.ts +12 -0
- package/dist/auth/guard.js +28 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/middleware.d.ts +23 -0
- package/dist/auth/middleware.js +89 -0
- package/dist/auth/native-auth.d.ts +73 -0
- package/dist/auth/native-auth.js +293 -0
- package/dist/auth/oidc-client.d.ts +17 -0
- package/dist/auth/oidc-client.js +123 -0
- package/dist/auth/providers/google.d.ts +23 -0
- package/dist/auth/providers/google.js +25 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +1 -0
- package/dist/auth/routes/login.d.ts +8 -0
- package/dist/auth/routes/login.js +98 -0
- package/dist/auth/routes/logout.d.ts +4 -0
- package/dist/auth/routes/logout.js +79 -0
- package/dist/auth/routes/oidc-callback.d.ts +3 -0
- package/dist/auth/routes/oidc-callback.js +70 -0
- package/dist/auth/routes/password.d.ts +5 -0
- package/dist/auth/routes/password.js +149 -0
- package/dist/auth/routes/signup.d.ts +3 -0
- package/dist/auth/routes/signup.js +81 -0
- package/dist/auth/routes/token.d.ts +4 -0
- package/dist/auth/routes/token.js +70 -0
- package/dist/auth/routes/utils.d.ts +7 -0
- package/dist/auth/routes/utils.js +35 -0
- package/dist/auth/routes/verify.d.ts +3 -0
- package/dist/auth/routes/verify.js +26 -0
- package/dist/auth/routes.d.ts +8 -0
- package/dist/auth/routes.js +110 -0
- package/dist/auth/session.d.ts +8 -0
- package/dist/auth/session.js +54 -0
- package/dist/auth/token.d.ts +33 -0
- package/dist/auth/token.js +90 -0
- package/dist/auth/types.d.ts +156 -0
- package/dist/auth/types.js +2 -0
- package/dist/build/build-client.d.ts +15 -0
- package/dist/build/build-client.js +45 -0
- package/dist/build/build-prerender.d.ts +11 -0
- package/dist/build/build-prerender.js +159 -0
- package/dist/build/build-server.d.ts +17 -0
- package/dist/build/build-server.js +98 -0
- package/dist/build/build.js +52 -120
- package/dist/build/scan.d.ts +19 -0
- package/dist/build/scan.js +77 -6
- package/dist/build/serve-api.js +8 -2
- package/dist/build/serve-loaders.d.ts +4 -2
- package/dist/build/serve-loaders.js +128 -10
- package/dist/build/serve-ssr.js +38 -11
- package/dist/build/serve-static.js +3 -3
- package/dist/build/serve.js +229 -14
- package/dist/cli.js +37 -6
- package/dist/communication/encryption.d.ts +35 -0
- package/dist/communication/encryption.js +90 -0
- package/dist/communication/handlers/context.d.ts +27 -0
- package/dist/communication/handlers/context.js +1 -0
- package/dist/communication/handlers/conversation.d.ts +24 -0
- package/dist/communication/handlers/conversation.js +113 -0
- package/dist/communication/handlers/file-upload.d.ts +17 -0
- package/dist/communication/handlers/file-upload.js +62 -0
- package/dist/communication/handlers/messaging.d.ts +30 -0
- package/dist/communication/handlers/messaging.js +237 -0
- package/dist/communication/handlers/presence.d.ts +15 -0
- package/dist/communication/handlers/presence.js +76 -0
- package/dist/communication/handlers.d.ts +5 -0
- package/dist/communication/handlers.js +5 -0
- package/dist/communication/index.d.ts +9 -0
- package/dist/communication/index.js +7 -0
- package/dist/communication/link-preview.d.ts +18 -0
- package/dist/communication/link-preview.js +115 -0
- package/dist/communication/schema.d.ts +10 -0
- package/dist/communication/schema.js +101 -0
- package/dist/communication/server.d.ts +86 -0
- package/dist/communication/server.js +212 -0
- package/dist/communication/signaling.d.ts +43 -0
- package/dist/communication/signaling.js +271 -0
- package/dist/communication/store.d.ts +71 -0
- package/dist/communication/store.js +289 -0
- package/dist/communication/types.d.ts +454 -0
- package/dist/communication/types.js +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +55 -0
- package/dist/db/auto-migrate.d.ts +3 -0
- package/dist/db/auto-migrate.js +100 -0
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.js +18 -0
- package/dist/db/context.d.ts +2 -0
- package/dist/db/context.js +9 -0
- package/dist/db/index.d.ts +23 -0
- package/dist/db/index.js +258 -0
- package/dist/db/seed.d.ts +12 -0
- package/dist/db/seed.js +88 -0
- package/dist/db/table.d.ts +10 -0
- package/dist/db/table.js +12 -0
- package/dist/dev-server/config.d.ts +14 -0
- package/dist/dev-server/config.js +26 -9
- package/dist/dev-server/index-html.d.ts +3 -0
- package/dist/dev-server/index-html.js +18 -6
- package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
- package/dist/dev-server/nuralyui-aliases.js +115 -94
- package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
- package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
- package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
- package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
- package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
- package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
- package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
- package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
- package/dist/dev-server/plugins/vite-plugin-loaders.d.ts +0 -1
- package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
- package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
- package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
- package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
- package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
- package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
- package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
- package/dist/dev-server/server.js +128 -12
- package/dist/dev-server/ssr-render.d.ts +2 -1
- package/dist/dev-server/ssr-render.js +107 -48
- package/dist/editor/ai/backend.d.ts +20 -0
- package/dist/editor/ai/backend.js +104 -0
- package/dist/editor/ai/claude-code-client.d.ts +20 -0
- package/dist/editor/ai/claude-code-client.js +145 -0
- package/dist/editor/ai/opencode-client.d.ts +14 -0
- package/dist/editor/ai/opencode-client.js +125 -0
- package/dist/editor/ai/snapshot-store.d.ts +22 -0
- package/dist/editor/ai/snapshot-store.js +35 -0
- package/dist/editor/ai/types.d.ts +30 -0
- package/dist/editor/ai/types.js +136 -0
- package/dist/editor/ai-chat-panel.d.ts +13 -0
- package/dist/editor/ai-chat-panel.js +587 -0
- package/dist/editor/ai-markdown.d.ts +10 -0
- package/dist/editor/ai-markdown.js +70 -0
- package/dist/editor/ai-project-panel.d.ts +11 -0
- package/dist/editor/ai-project-panel.js +332 -0
- package/dist/editor/ast-modification.d.ts +11 -0
- package/dist/editor/ast-modification.js +1 -0
- package/dist/editor/ast-service.d.ts +30 -0
- package/dist/editor/ast-service.js +180 -0
- package/dist/editor/css-rules.d.ts +54 -0
- package/dist/editor/css-rules.js +423 -0
- package/dist/editor/editor-api-client.d.ts +51 -0
- package/dist/editor/editor-api-client.js +162 -0
- package/dist/editor/editor-bridge.d.ts +1 -0
- package/dist/editor/editor-bridge.js +17 -8
- package/dist/editor/editor-toolbar.d.ts +14 -0
- package/dist/editor/editor-toolbar.js +115 -0
- package/dist/editor/file-editor.d.ts +9 -0
- package/dist/editor/file-editor.js +236 -0
- package/dist/editor/file-service.d.ts +16 -0
- package/dist/editor/file-service.js +52 -0
- package/dist/editor/i18n-key-gen.d.ts +1 -0
- package/dist/editor/i18n-key-gen.js +7 -0
- package/dist/editor/inline-text-edit.d.ts +5 -0
- package/dist/editor/inline-text-edit.js +173 -92
- package/dist/editor/overlay-events.d.ts +5 -0
- package/dist/editor/overlay-events.js +364 -0
- package/dist/editor/overlay-hmr.d.ts +2 -0
- package/dist/editor/overlay-hmr.js +75 -0
- package/dist/editor/overlay-selection.d.ts +29 -0
- package/dist/editor/overlay-selection.js +148 -0
- package/dist/editor/overlay-utils.d.ts +12 -0
- package/dist/editor/overlay-utils.js +59 -0
- package/dist/editor/properties-panel-persist.d.ts +14 -0
- package/dist/editor/properties-panel-persist.js +70 -0
- package/dist/editor/properties-panel-rows.d.ts +10 -0
- package/dist/editor/properties-panel-rows.js +349 -0
- package/dist/editor/properties-panel-styles.d.ts +4 -0
- package/dist/editor/properties-panel-styles.js +174 -0
- package/dist/editor/properties-panel.d.ts +4 -0
- package/dist/editor/properties-panel.js +148 -0
- package/dist/editor/property-registry.d.ts +16 -0
- package/dist/editor/property-registry.js +303 -0
- package/dist/editor/standalone-file-panel.d.ts +0 -0
- package/dist/editor/standalone-file-panel.js +1 -0
- package/dist/editor/standalone-overlay-dom.d.ts +0 -0
- package/dist/editor/standalone-overlay-dom.js +1 -0
- package/dist/editor/standalone-overlay-styles.d.ts +0 -0
- package/dist/editor/standalone-overlay-styles.js +1 -0
- package/dist/editor/standalone-overlay.d.ts +1 -0
- package/dist/editor/standalone-overlay.js +76 -0
- package/dist/editor/syntax-highlighter.d.ts +4 -0
- package/dist/editor/syntax-highlighter.js +81 -0
- package/dist/editor/text-toolbar.d.ts +11 -0
- package/dist/editor/text-toolbar.js +327 -0
- package/dist/editor/toolbar-styles.d.ts +4 -0
- package/dist/editor/toolbar-styles.js +198 -0
- package/dist/email/index.d.ts +32 -0
- package/dist/email/index.js +154 -0
- package/dist/email/providers/resend.d.ts +2 -0
- package/dist/email/providers/resend.js +24 -0
- package/dist/email/providers/sendgrid.d.ts +2 -0
- package/dist/email/providers/sendgrid.js +31 -0
- package/dist/email/providers/smtp.d.ts +13 -0
- package/dist/email/providers/smtp.js +125 -0
- package/dist/email/template-engine.d.ts +18 -0
- package/dist/email/template-engine.js +116 -0
- package/dist/email/templates/base.d.ts +9 -0
- package/dist/email/templates/base.js +65 -0
- package/dist/email/templates/password-reset.d.ts +5 -0
- package/dist/email/templates/password-reset.js +15 -0
- package/dist/email/templates/verify-email.d.ts +5 -0
- package/dist/email/templates/verify-email.js +15 -0
- package/dist/email/templates/welcome.d.ts +5 -0
- package/dist/email/templates/welcome.js +13 -0
- package/dist/email/types.d.ts +49 -0
- package/dist/email/types.js +1 -0
- package/dist/llms/generate.d.ts +46 -0
- package/dist/llms/generate.js +185 -0
- package/dist/permissions/guard.d.ts +28 -0
- package/dist/permissions/guard.js +30 -0
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/service.d.ts +80 -0
- package/dist/permissions/service.js +210 -0
- package/dist/permissions/tables.d.ts +5 -0
- package/dist/permissions/tables.js +68 -0
- package/dist/permissions/types.d.ts +33 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/app-shell.js +163 -0
- package/dist/runtime/auth.d.ts +10 -0
- package/dist/runtime/auth.js +30 -0
- package/dist/runtime/communication.d.ts +137 -0
- package/dist/runtime/communication.js +228 -0
- package/dist/runtime/error-boundary.d.ts +23 -0
- package/dist/runtime/error-boundary.js +120 -0
- package/dist/runtime/i18n.d.ts +6 -1
- package/dist/runtime/i18n.js +42 -21
- package/dist/runtime/router-data.d.ts +5 -0
- package/dist/runtime/router-data.js +121 -16
- package/dist/runtime/router-hydration.js +25 -0
- package/dist/runtime/router.d.ts +21 -1
- package/dist/runtime/router.js +221 -39
- package/dist/runtime/socket-client.d.ts +2 -0
- package/dist/runtime/socket-client.js +30 -0
- package/dist/runtime/webrtc.d.ts +47 -0
- package/dist/runtime/webrtc.js +178 -0
- package/dist/shared/graceful-shutdown.d.ts +8 -0
- package/dist/shared/graceful-shutdown.js +36 -0
- package/dist/shared/health.d.ts +8 -0
- package/dist/shared/health.js +25 -0
- package/dist/shared/llms-txt.d.ts +31 -0
- package/dist/shared/llms-txt.js +85 -0
- package/dist/shared/logger.d.ts +32 -0
- package/dist/shared/logger.js +93 -0
- package/dist/shared/meta.d.ts +27 -0
- package/dist/shared/meta.js +71 -0
- package/dist/shared/middleware-runner.d.ts +9 -0
- package/dist/shared/middleware-runner.js +29 -0
- package/dist/shared/rate-limit.d.ts +18 -0
- package/dist/shared/rate-limit.js +71 -0
- package/dist/shared/request-id.d.ts +5 -0
- package/dist/shared/request-id.js +18 -0
- package/dist/shared/route-matching.js +16 -1
- package/dist/shared/security-headers.d.ts +18 -0
- package/dist/shared/security-headers.js +38 -0
- package/dist/shared/socket-io-setup.d.ts +11 -0
- package/dist/shared/socket-io-setup.js +51 -0
- package/dist/shared/types.d.ts +16 -0
- package/dist/shared/utils.d.ts +37 -7
- package/dist/shared/utils.js +175 -26
- package/dist/storage/adapters/local.d.ts +44 -0
- package/dist/storage/adapters/local.js +85 -0
- package/dist/storage/adapters/s3.d.ts +32 -0
- package/dist/storage/adapters/s3.js +116 -0
- package/dist/storage/adapters/types.d.ts +53 -0
- package/dist/storage/adapters/types.js +1 -0
- package/dist/storage/index.d.ts +76 -0
- package/dist/storage/index.js +83 -0
- package/package.json +20 -1
- package/templates/blog/api/posts.ts +6 -0
- package/templates/blog/data/migrations/001_init.sql +13 -0
- package/templates/blog/lumenjs.config.ts +3 -0
- package/templates/blog/package.json +14 -0
- package/templates/blog/pages/_layout.ts +25 -0
- package/templates/blog/pages/index.ts +65 -0
- package/templates/blog/pages/posts/[slug].ts +60 -0
- package/templates/blog/pages/tag/[tag].ts +44 -0
- package/templates/dashboard/api/stats.ts +10 -0
- package/templates/dashboard/data/migrations/001_init.sql +13 -0
- package/templates/dashboard/lumenjs.config.ts +3 -0
- package/templates/dashboard/package.json +14 -0
- package/templates/dashboard/pages/_layout.ts +25 -0
- package/templates/dashboard/pages/index.ts +72 -0
- package/templates/dashboard/pages/settings/index.ts +29 -0
- package/templates/default/lumenjs.config.ts +3 -0
- package/templates/default/package.json +14 -0
- package/templates/default/pages/index.ts +24 -0
- package/templates/social/api/posts/[id].ts +14 -0
- package/templates/social/api/posts.ts +11 -0
- package/templates/social/api/profile/[username].ts +10 -0
- package/templates/social/api/upload.ts +19 -0
- package/templates/social/data/migrations/001_init.sql +78 -0
- package/templates/social/data/migrations/002_add_image_url.sql +1 -0
- package/templates/social/data/migrations/003_auth.sql +7 -0
- package/templates/social/docs/architecture.md +76 -0
- package/templates/social/docs/components.md +100 -0
- package/templates/social/docs/data.md +89 -0
- package/templates/social/docs/pages.md +96 -0
- package/templates/social/docs/theming.md +52 -0
- package/templates/social/lib/media.ts +130 -0
- package/templates/social/lumenjs.auth.ts +21 -0
- package/templates/social/lumenjs.config.ts +3 -0
- package/templates/social/package.json +5 -0
- package/templates/social/pages/_layout.ts +239 -0
- package/templates/social/pages/apps/[id].ts +173 -0
- package/templates/social/pages/apps/index.ts +116 -0
- package/templates/social/pages/auth/login.ts +92 -0
- package/templates/social/pages/bookmarks.ts +57 -0
- package/templates/social/pages/explore.ts +73 -0
- package/templates/social/pages/index.ts +351 -0
- package/templates/social/pages/messages.ts +298 -0
- package/templates/social/pages/new.ts +77 -0
- package/templates/social/pages/notifications.ts +73 -0
- package/templates/social/pages/post/[id].ts +124 -0
- package/templates/social/pages/profile/[username].ts +100 -0
- package/templates/social/pages/settings/accessibility.ts +153 -0
- package/templates/social/pages/settings/account.ts +260 -0
- package/templates/social/pages/settings/help.ts +141 -0
- package/templates/social/pages/settings/language.ts +103 -0
- package/templates/social/pages/settings/privacy.ts +183 -0
- package/templates/social/pages/settings/security.ts +133 -0
- package/templates/social/pages/settings.ts +185 -0
package/dist/db/index.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
5
|
+
import Database from 'better-sqlite3';
|
|
6
|
+
const _require = createRequire(import.meta.url);
|
|
7
|
+
import { getProjectDir } from './context.js';
|
|
8
|
+
import { autoMigrate } from './auto-migrate.js';
|
|
9
|
+
import { getRegisteredTables } from './table.js';
|
|
10
|
+
import { autoSeed } from './seed.js';
|
|
11
|
+
export { defineTable, getRegisteredTables } from './table.js';
|
|
12
|
+
export { waitForSeed } from './seed.js';
|
|
13
|
+
// ── Abstract async interface ───────────────────────────────────────────────
|
|
14
|
+
export class LumenDb {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.isPg = false;
|
|
17
|
+
}
|
|
18
|
+
/** Raw SQLite Database — only available in SQLite mode */
|
|
19
|
+
get raw() {
|
|
20
|
+
throw new Error('raw is only available in SQLite mode');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// ── SQLite implementation ─────────────────────────────────────────────────
|
|
24
|
+
class LumenDbSqlite extends LumenDb {
|
|
25
|
+
constructor(db) {
|
|
26
|
+
super();
|
|
27
|
+
this.db = db;
|
|
28
|
+
this.isPg = false;
|
|
29
|
+
}
|
|
30
|
+
async all(sql, ...params) {
|
|
31
|
+
return this.db.prepare(sql).all(...params);
|
|
32
|
+
}
|
|
33
|
+
async get(sql, ...params) {
|
|
34
|
+
return this.db.prepare(sql).get(...params);
|
|
35
|
+
}
|
|
36
|
+
async run(sql, ...params) {
|
|
37
|
+
const stmt = this.db.prepare(sql);
|
|
38
|
+
// RETURNING clause → use .get() to capture the returned row's id
|
|
39
|
+
if (/\bRETURNING\b/i.test(sql)) {
|
|
40
|
+
const row = stmt.get(...params);
|
|
41
|
+
return { changes: 1, lastInsertRowid: row?.id ?? 0 };
|
|
42
|
+
}
|
|
43
|
+
const result = stmt.run(...params);
|
|
44
|
+
return { changes: result.changes, lastInsertRowid: result.lastInsertRowid };
|
|
45
|
+
}
|
|
46
|
+
async exec(sql) {
|
|
47
|
+
this.db.exec(sql);
|
|
48
|
+
}
|
|
49
|
+
async withTransaction(fn) {
|
|
50
|
+
this.db.exec('BEGIN');
|
|
51
|
+
try {
|
|
52
|
+
const result = await fn();
|
|
53
|
+
this.db.exec('COMMIT');
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
try {
|
|
58
|
+
this.db.exec('ROLLBACK');
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
get raw() {
|
|
65
|
+
return this.db;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ── PostgreSQL implementation ─────────────────────────────────────────────
|
|
69
|
+
// AsyncLocalStorage stores the current transactional pg client so queries
|
|
70
|
+
// within withTransaction() use the same connection.
|
|
71
|
+
const pgTxClient = new AsyncLocalStorage();
|
|
72
|
+
class LumenDbPg extends LumenDb {
|
|
73
|
+
constructor(connectionString) {
|
|
74
|
+
super();
|
|
75
|
+
this.isPg = true;
|
|
76
|
+
// Use createRequire for CJS compatibility in ESM context
|
|
77
|
+
const { Pool } = _require('pg');
|
|
78
|
+
this.pool = new Pool({ connectionString });
|
|
79
|
+
this.pool.on('error', (err) => {
|
|
80
|
+
console.error('[LumenJS PG] Pool error:', err.message);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/** Convert SQLite-flavoured SQL to PostgreSQL */
|
|
84
|
+
convertSql(sql) {
|
|
85
|
+
// INSERT OR IGNORE → INSERT ... ON CONFLICT DO NOTHING
|
|
86
|
+
const isInsertOrIgnore = /^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/i.test(sql);
|
|
87
|
+
let result = isInsertOrIgnore
|
|
88
|
+
? sql.replace(/INSERT\s+OR\s+IGNORE\s+INTO\b/i, 'INSERT INTO')
|
|
89
|
+
: sql;
|
|
90
|
+
// Replace ? with $1, $2, ... positional parameters
|
|
91
|
+
let i = 0;
|
|
92
|
+
result = result.replace(/\?/g, () => `$${++i}`);
|
|
93
|
+
// datetime('now', '+N unit') / datetime('now', '-N unit')
|
|
94
|
+
result = result.replace(/datetime\s*\(\s*'now'\s*,\s*'([+-]\d+)\s+(\w+)'\s*\)/gi, (_m, offset, unit) => {
|
|
95
|
+
const op = offset.startsWith('-') ? '-' : '+';
|
|
96
|
+
const amount = offset.replace(/^[+-]/, '');
|
|
97
|
+
return `NOW() ${op} INTERVAL '${amount} ${unit}'`;
|
|
98
|
+
});
|
|
99
|
+
// datetime('now')
|
|
100
|
+
result = result.replace(/datetime\s*\(\s*'now'\s*\)/gi, 'NOW()');
|
|
101
|
+
// json_each(expr) alias → jsonb_array_elements_text(expr::jsonb) AS alias
|
|
102
|
+
result = result.replace(/\bjson_each\s*\(([^)]+)\)\s+(\w+)/gi, (_m, expr, alias) => `jsonb_array_elements_text(${expr.trim()}::jsonb) AS ${alias}`);
|
|
103
|
+
// alias.value (from json_each) → alias (jsonb_array_elements_text column is the alias itself)
|
|
104
|
+
result = result.replace(/\b(\w+)\.value\b/g, '$1');
|
|
105
|
+
if (isInsertOrIgnore) {
|
|
106
|
+
result = result.trimEnd() + ' ON CONFLICT DO NOTHING';
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
getClient() {
|
|
111
|
+
// Return transactional client if inside withTransaction, otherwise use pool
|
|
112
|
+
return pgTxClient.getStore() ?? this.pool;
|
|
113
|
+
}
|
|
114
|
+
async all(sql, ...params) {
|
|
115
|
+
const pgSql = this.convertSql(sql);
|
|
116
|
+
const res = await this.getClient().query(pgSql, params);
|
|
117
|
+
return res.rows;
|
|
118
|
+
}
|
|
119
|
+
async get(sql, ...params) {
|
|
120
|
+
const pgSql = this.convertSql(sql);
|
|
121
|
+
const res = await this.getClient().query(pgSql, params);
|
|
122
|
+
return res.rows[0];
|
|
123
|
+
}
|
|
124
|
+
async run(sql, ...params) {
|
|
125
|
+
const pgSql = this.convertSql(sql);
|
|
126
|
+
const res = await this.getClient().query(pgSql, params);
|
|
127
|
+
const lastInsertRowid = res.rows?.[0]?.id ?? 0;
|
|
128
|
+
return { changes: res.rowCount ?? 0, lastInsertRowid };
|
|
129
|
+
}
|
|
130
|
+
async exec(sql) {
|
|
131
|
+
// exec is used for DDL / multi-statement — skip placeholder conversion
|
|
132
|
+
// (DDL has no ? params), just normalize datetime() calls
|
|
133
|
+
const pgSql = this.convertSql(sql);
|
|
134
|
+
await this.getClient().query(pgSql);
|
|
135
|
+
}
|
|
136
|
+
async withTransaction(fn) {
|
|
137
|
+
const client = await this.pool.connect();
|
|
138
|
+
try {
|
|
139
|
+
await client.query('BEGIN');
|
|
140
|
+
// All db calls inside fn() will use this client via AsyncLocalStorage
|
|
141
|
+
const result = await pgTxClient.run(client, fn);
|
|
142
|
+
await client.query('COMMIT');
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
try {
|
|
147
|
+
await client.query('ROLLBACK');
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
client.release();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ── Singleton management ──────────────────────────────────────────────────
|
|
158
|
+
let _instance = null;
|
|
159
|
+
let _migrationPromise = null;
|
|
160
|
+
export function useDb() {
|
|
161
|
+
if (_instance)
|
|
162
|
+
return _instance;
|
|
163
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
164
|
+
if (databaseUrl && (databaseUrl.startsWith('postgres') || databaseUrl.startsWith('postgresql'))) {
|
|
165
|
+
_instance = new LumenDbPg(databaseUrl);
|
|
166
|
+
const projectDir = (() => {
|
|
167
|
+
try {
|
|
168
|
+
return getProjectDir();
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return process.env.LUMENJS_PROJECT_DIR || process.cwd();
|
|
172
|
+
}
|
|
173
|
+
})();
|
|
174
|
+
_migrationPromise = runPgMigrations(_instance, projectDir);
|
|
175
|
+
_migrationPromise.catch(err => console.error('[LumenJS] PG migration error:', err.message));
|
|
176
|
+
return _instance;
|
|
177
|
+
}
|
|
178
|
+
// SQLite mode
|
|
179
|
+
const projectDir = getProjectDir();
|
|
180
|
+
const dbRelPath = (() => {
|
|
181
|
+
try {
|
|
182
|
+
const c = fs.readFileSync(path.join(projectDir, 'lumenjs.config.ts'), 'utf-8');
|
|
183
|
+
const m = c.match(/db\s*:\s*\{[^}]*path\s*:\s*['"]([^'"]+)['"]/);
|
|
184
|
+
return m ? m[1] : 'data/db.sqlite';
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return 'data/db.sqlite';
|
|
188
|
+
}
|
|
189
|
+
})();
|
|
190
|
+
const dbPath = path.resolve(projectDir, dbRelPath);
|
|
191
|
+
const dbDir = path.dirname(dbPath);
|
|
192
|
+
if (!fs.existsSync(dbDir))
|
|
193
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
194
|
+
const rawDb = new Database(dbPath);
|
|
195
|
+
rawDb.pragma('journal_mode = WAL');
|
|
196
|
+
rawDb.pragma('foreign_keys = ON');
|
|
197
|
+
_instance = new LumenDbSqlite(rawDb);
|
|
198
|
+
autoMigrate(rawDb, projectDir, getRegisteredTables());
|
|
199
|
+
runSqliteMigrations(rawDb, projectDir);
|
|
200
|
+
autoSeed(rawDb, projectDir);
|
|
201
|
+
return _instance;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns a promise that resolves when the initial DB migrations have completed.
|
|
205
|
+
* Useful for waiting before serving the first request in PG mode.
|
|
206
|
+
*/
|
|
207
|
+
export function waitForMigrations() {
|
|
208
|
+
return _migrationPromise ?? Promise.resolve();
|
|
209
|
+
}
|
|
210
|
+
// ── SQLite migration runner ───────────────────────────────────────────────
|
|
211
|
+
function runSqliteMigrations(db, projectDir) {
|
|
212
|
+
const migrationsDir = path.join(projectDir, 'data', 'migrations');
|
|
213
|
+
if (!fs.existsSync(migrationsDir))
|
|
214
|
+
return;
|
|
215
|
+
db.exec(`CREATE TABLE IF NOT EXISTS _lumen_migrations (
|
|
216
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
217
|
+
name TEXT NOT NULL UNIQUE,
|
|
218
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
219
|
+
)`);
|
|
220
|
+
const applied = new Set(db.prepare('SELECT name FROM _lumen_migrations').all().map((r) => r.name));
|
|
221
|
+
const files = fs.readdirSync(migrationsDir)
|
|
222
|
+
.filter(f => f.endsWith('.sql'))
|
|
223
|
+
.sort();
|
|
224
|
+
for (const file of files) {
|
|
225
|
+
if (applied.has(file))
|
|
226
|
+
continue;
|
|
227
|
+
const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf-8');
|
|
228
|
+
const migrate = db.transaction(() => {
|
|
229
|
+
db.exec(sql);
|
|
230
|
+
db.prepare('INSERT INTO _lumen_migrations (name) VALUES (?)').run(file);
|
|
231
|
+
});
|
|
232
|
+
migrate();
|
|
233
|
+
console.log(`[LumenJS] Applied migration: ${file}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// ── PostgreSQL migration runner ───────────────────────────────────────────
|
|
237
|
+
async function runPgMigrations(db, projectDir) {
|
|
238
|
+
const migrationsDir = path.join(projectDir, 'data', 'migrations', 'postgres');
|
|
239
|
+
if (!fs.existsSync(migrationsDir))
|
|
240
|
+
return;
|
|
241
|
+
await db.exec(`CREATE TABLE IF NOT EXISTS _lumen_migrations (
|
|
242
|
+
id BIGSERIAL PRIMARY KEY,
|
|
243
|
+
name TEXT NOT NULL UNIQUE,
|
|
244
|
+
applied_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
245
|
+
)`);
|
|
246
|
+
const applied = new Set((await db.all('SELECT name FROM _lumen_migrations')).map(r => r.name));
|
|
247
|
+
const files = fs.readdirSync(migrationsDir)
|
|
248
|
+
.filter(f => f.endsWith('.sql'))
|
|
249
|
+
.sort();
|
|
250
|
+
for (const file of files) {
|
|
251
|
+
if (applied.has(file))
|
|
252
|
+
continue;
|
|
253
|
+
const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf-8');
|
|
254
|
+
await db.exec(sql);
|
|
255
|
+
await db.run('INSERT INTO _lumen_migrations (name) VALUES (?)', file);
|
|
256
|
+
console.log(`[LumenJS] Applied PG migration: ${file}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-seed on first DB creation. Called from useDb() after migrations.
|
|
4
|
+
* Only runs in SQLite mode (PG seeds are handled separately).
|
|
5
|
+
*/
|
|
6
|
+
export declare function autoSeed(db: Database.Database, projectDir: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Returns a promise that resolves when any in-progress seed completes.
|
|
9
|
+
*/
|
|
10
|
+
export declare function waitForSeed(): Promise<void>;
|
|
11
|
+
/** Run seed via CLI. If force=true, re-run even if already applied. */
|
|
12
|
+
export declare function runSeed(projectDir: string, force?: boolean): Promise<void>;
|
package/dist/db/seed.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
const SEED_TABLE = '_lumen_seed_applied';
|
|
4
|
+
const SEED_NAME = 'data/seed.ts';
|
|
5
|
+
function ensureSeedTableSqlite(db) {
|
|
6
|
+
db.exec(`CREATE TABLE IF NOT EXISTS ${SEED_TABLE} (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
name TEXT NOT NULL UNIQUE,
|
|
9
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
10
|
+
)`);
|
|
11
|
+
}
|
|
12
|
+
function isSeedAppliedSqlite(db) {
|
|
13
|
+
ensureSeedTableSqlite(db);
|
|
14
|
+
const row = db.prepare(`SELECT 1 FROM ${SEED_TABLE} WHERE name = ?`).get(SEED_NAME);
|
|
15
|
+
return !!row;
|
|
16
|
+
}
|
|
17
|
+
function markSeedAppliedSqlite(db) {
|
|
18
|
+
db.prepare(`INSERT OR IGNORE INTO ${SEED_TABLE} (name) VALUES (?)`).run(SEED_NAME);
|
|
19
|
+
}
|
|
20
|
+
async function loadAndRunSeed(projectDir) {
|
|
21
|
+
const seedPath = path.join(projectDir, 'data', 'seed.ts');
|
|
22
|
+
const mod = await import(/* @vite-ignore */ seedPath);
|
|
23
|
+
const seedFn = mod.default || mod;
|
|
24
|
+
if (typeof seedFn === 'function') {
|
|
25
|
+
await seedFn();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let _seedPromise = null;
|
|
29
|
+
/**
|
|
30
|
+
* Auto-seed on first DB creation. Called from useDb() after migrations.
|
|
31
|
+
* Only runs in SQLite mode (PG seeds are handled separately).
|
|
32
|
+
*/
|
|
33
|
+
export function autoSeed(db, projectDir) {
|
|
34
|
+
if (isSeedAppliedSqlite(db))
|
|
35
|
+
return;
|
|
36
|
+
const seedPath = path.join(projectDir, 'data', 'seed.ts');
|
|
37
|
+
if (!fs.existsSync(seedPath))
|
|
38
|
+
return;
|
|
39
|
+
console.log('[LumenJS] Running seed file...');
|
|
40
|
+
markSeedAppliedSqlite(db);
|
|
41
|
+
_seedPromise = loadAndRunSeed(projectDir)
|
|
42
|
+
.then(() => {
|
|
43
|
+
console.log('[LumenJS] Seed applied.');
|
|
44
|
+
})
|
|
45
|
+
.catch(err => {
|
|
46
|
+
console.error('[LumenJS] Failed to run seed:', err);
|
|
47
|
+
db.prepare(`DELETE FROM ${SEED_TABLE} WHERE name = ?`).run(SEED_NAME);
|
|
48
|
+
})
|
|
49
|
+
.finally(() => {
|
|
50
|
+
_seedPromise = null;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns a promise that resolves when any in-progress seed completes.
|
|
55
|
+
*/
|
|
56
|
+
export function waitForSeed() {
|
|
57
|
+
return _seedPromise ?? Promise.resolve();
|
|
58
|
+
}
|
|
59
|
+
/** Run seed via CLI. If force=true, re-run even if already applied. */
|
|
60
|
+
export async function runSeed(projectDir, force = false) {
|
|
61
|
+
const seedPath = path.join(projectDir, 'data', 'seed.ts');
|
|
62
|
+
if (!fs.existsSync(seedPath)) {
|
|
63
|
+
console.error(`[LumenJS] Seed file not found: ${seedPath}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const { useDb } = await import('./index.js');
|
|
67
|
+
const lumenDb = useDb();
|
|
68
|
+
// PG mode: seeds are not tracked via SQLite mechanism
|
|
69
|
+
if (lumenDb.isPg) {
|
|
70
|
+
if (!force) {
|
|
71
|
+
console.log('[LumenJS] PG mode: skipping seed tracking check. Use --force to run anyway.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
await loadAndRunSeed(projectDir);
|
|
75
|
+
console.log('[LumenJS] Seed applied.');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const db = lumenDb.raw;
|
|
79
|
+
ensureSeedTableSqlite(db);
|
|
80
|
+
if (!force && isSeedAppliedSqlite(db)) {
|
|
81
|
+
console.log('[LumenJS] Seed already applied. Use --force to re-run.');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log('[LumenJS] Running seed file...');
|
|
85
|
+
await loadAndRunSeed(projectDir);
|
|
86
|
+
markSeedAppliedSqlite(db);
|
|
87
|
+
console.log('[LumenJS] Seed applied.');
|
|
88
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface TableColumn {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TableDefinition {
|
|
6
|
+
name: string;
|
|
7
|
+
columns: TableColumn[];
|
|
8
|
+
}
|
|
9
|
+
export declare function defineTable<T extends Record<string, string>>(name: string, columns: T): T;
|
|
10
|
+
export declare function getRegisteredTables(): Map<string, TableDefinition>;
|
package/dist/db/table.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const _registry = new Map();
|
|
2
|
+
export function defineTable(name, columns) {
|
|
3
|
+
const parsed = Object.entries(columns).map(([colName, colType]) => ({
|
|
4
|
+
name: colName,
|
|
5
|
+
type: colType,
|
|
6
|
+
}));
|
|
7
|
+
_registry.set(name, { name, columns: parsed });
|
|
8
|
+
return columns;
|
|
9
|
+
}
|
|
10
|
+
export function getRegisteredTables() {
|
|
11
|
+
return _registry;
|
|
12
|
+
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
import type { SecurityHeadersConfig } from '../shared/security-headers.js';
|
|
2
|
+
import type { RateLimitConfig } from '../shared/rate-limit.js';
|
|
1
3
|
export interface I18nConfig {
|
|
2
4
|
locales: string[];
|
|
3
5
|
defaultLocale: string;
|
|
4
6
|
prefixDefault: boolean;
|
|
5
7
|
}
|
|
8
|
+
export type PrefetchStrategy = 'hover' | 'viewport' | 'none';
|
|
6
9
|
export interface ProjectConfig {
|
|
7
10
|
title: string;
|
|
8
11
|
integrations: string[];
|
|
9
12
|
i18n?: I18nConfig;
|
|
13
|
+
db?: {
|
|
14
|
+
path?: string;
|
|
15
|
+
};
|
|
16
|
+
prefetch: PrefetchStrategy;
|
|
17
|
+
prerender?: boolean;
|
|
18
|
+
/** App version for health check. Default: reads from package.json. */
|
|
19
|
+
version?: string;
|
|
20
|
+
/** Security headers config. Applied in production. */
|
|
21
|
+
securityHeaders?: SecurityHeadersConfig;
|
|
22
|
+
/** Rate limiting config. Applied in production. */
|
|
23
|
+
rateLimit?: RateLimitConfig;
|
|
10
24
|
}
|
|
11
25
|
/**
|
|
12
26
|
* Reads the project config from lumenjs.config.ts.
|
|
@@ -9,9 +9,13 @@ const __dirname = path.dirname(__filename);
|
|
|
9
9
|
export function readProjectConfig(projectDir) {
|
|
10
10
|
let title = 'LumenJS App';
|
|
11
11
|
let integrations = [];
|
|
12
|
+
let prefetch = 'viewport';
|
|
13
|
+
let prerender;
|
|
14
|
+
let i18n;
|
|
12
15
|
const configPath = path.join(projectDir, 'lumenjs.config.ts');
|
|
13
16
|
if (fs.existsSync(configPath)) {
|
|
14
17
|
try {
|
|
18
|
+
// Read the config file once and parse all fields from the same content
|
|
15
19
|
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
16
20
|
const titleMatch = configContent.match(/title\s*:\s*['"]([^'"]+)['"]/);
|
|
17
21
|
if (titleMatch)
|
|
@@ -23,14 +27,17 @@ export function readProjectConfig(projectDir) {
|
|
|
23
27
|
.map(s => s.trim().replace(/^['"]|['"]$/g, ''))
|
|
24
28
|
.filter(Boolean);
|
|
25
29
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
30
|
+
const prefetchMatch = configContent.match(/prefetch\s*:\s*['"]([^'"]+)['"]/);
|
|
31
|
+
if (prefetchMatch) {
|
|
32
|
+
const val = prefetchMatch[1];
|
|
33
|
+
if (val === 'hover' || val === 'viewport' || val === 'none') {
|
|
34
|
+
prefetch = val;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const prerenderMatch = configContent.match(/prerender\s*:\s*(true|false)/);
|
|
38
|
+
if (prerenderMatch) {
|
|
39
|
+
prerender = prerenderMatch[1] === 'true';
|
|
40
|
+
}
|
|
34
41
|
const i18nMatch = configContent.match(/i18n\s*:\s*\{([\s\S]*?)\}/);
|
|
35
42
|
if (i18nMatch) {
|
|
36
43
|
const block = i18nMatch[1];
|
|
@@ -50,9 +57,19 @@ export function readProjectConfig(projectDir) {
|
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
}
|
|
60
|
+
catch { /* use defaults */ }
|
|
61
|
+
}
|
|
62
|
+
// Read version from project's package.json
|
|
63
|
+
let version;
|
|
64
|
+
const pkgPath = path.join(projectDir, 'package.json');
|
|
65
|
+
if (fs.existsSync(pkgPath)) {
|
|
66
|
+
try {
|
|
67
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
68
|
+
version = pkg.version;
|
|
69
|
+
}
|
|
53
70
|
catch { /* ignore */ }
|
|
54
71
|
}
|
|
55
|
-
return { title, integrations, ...(i18n ? { i18n } : {}) };
|
|
72
|
+
return { title, integrations, prefetch, version, ...(i18n ? { i18n } : {}), ...(prerender ? { prerender } : {}) };
|
|
56
73
|
}
|
|
57
74
|
/**
|
|
58
75
|
* Reads the project title from lumenjs.config.ts (or returns default).
|
|
@@ -29,18 +29,29 @@ export function generateIndexHtml(options) {
|
|
|
29
29
|
};
|
|
30
30
|
i18nScript = `<script type="application/json" id="__nk_i18n__">${JSON.stringify(i18nData).replace(/</g, '\\u003c')}</script>`;
|
|
31
31
|
}
|
|
32
|
+
// Auth: inline user data for client hydration
|
|
33
|
+
let authScript = '';
|
|
34
|
+
if (options.authUser) {
|
|
35
|
+
authScript = `<script type="application/json" id="__nk_auth__">${JSON.stringify(options.authUser).replace(/</g, '\\u003c')}</script>`;
|
|
36
|
+
}
|
|
37
|
+
// Prefetch strategy inline
|
|
38
|
+
let prefetchScript = '';
|
|
39
|
+
if (options.prefetch && options.prefetch !== 'hover') {
|
|
40
|
+
prefetchScript = `<script type="application/json" id="__nk_prefetch__">${options.prefetch}</script>`;
|
|
41
|
+
}
|
|
32
42
|
// i18n module is loaded via imports from router-hydration, no separate script needed
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: '';
|
|
43
|
+
// Hydrate support is always loaded via the app-shell virtual module (first import)
|
|
44
|
+
// to avoid Lit module duplication from separate script tags.
|
|
36
45
|
const htmlLang = options.locale || 'en';
|
|
37
46
|
return `<!DOCTYPE html>
|
|
38
47
|
<html lang="${htmlLang}">
|
|
39
48
|
<head>
|
|
40
49
|
<meta charset="UTF-8" />
|
|
41
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
50
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
|
|
42
51
|
<title>${escapeHtml(options.title)}</title>
|
|
43
|
-
|
|
52
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
53
|
+
${options.integrations?.includes('nuralyui') ? '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@nuraly/lumenui@latest/packages/themes/dist/default.css">' : ''}${options.integrations?.includes('tailwind') ? '\n <script type="module">import "/styles/tailwind.css";</script>' : ''}
|
|
54
|
+
${options.headContent || ''}
|
|
44
55
|
<style>
|
|
45
56
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
46
57
|
body { font-family: system-ui, -apple-system, sans-serif; min-height: 100vh; }
|
|
@@ -48,10 +59,11 @@ export function generateIndexHtml(options) {
|
|
|
48
59
|
</style>
|
|
49
60
|
</head>
|
|
50
61
|
<body>
|
|
62
|
+
${prefetchScript}
|
|
51
63
|
${i18nScript}
|
|
64
|
+
${authScript}
|
|
52
65
|
${loaderDataScript}
|
|
53
66
|
${appTag}
|
|
54
|
-
${hydrateScript}
|
|
55
67
|
<script type="module" src="/@lumenjs/app-shell"></script>
|
|
56
68
|
${editorScript}
|
|
57
69
|
</body>
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export declare const tagToPackage: Record<string, string>;
|
|
2
2
|
export declare const implicitDeps: Record<string, string[]>;
|
|
3
|
-
/**
|
|
4
|
-
* NuralyUI component alias map — mirrors the studio astro.config.mjs aliases.
|
|
5
|
-
* Points to the component source directories within the studio service.
|
|
6
|
-
*/
|
|
7
3
|
export declare function getNuralyUIAliases(nuralyUIPath: string, nuralyCommonPath: string): Record<string, string>;
|
|
8
4
|
/**
|
|
9
5
|
* Resolves the NuralyUI source path dynamically.
|