@musnows/scriverse 0.2.0 → 0.3.0

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.
Files changed (70) hide show
  1. package/README.en.md +13 -4
  2. package/README.md +13 -4
  3. package/dist/ai.js +3374 -0
  4. package/dist/ai.js.map +1 -0
  5. package/dist/app.js +1046 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/cli-core.js +147 -20
  8. package/dist/cli-core.js.map +1 -1
  9. package/dist/credential-vault.js +40 -0
  10. package/dist/credential-vault.js.map +1 -0
  11. package/dist/database.js +1122 -0
  12. package/dist/database.js.map +1 -0
  13. package/dist/docx-security.js +184 -0
  14. package/dist/docx-security.js.map +1 -0
  15. package/dist/domain.js +21 -0
  16. package/dist/domain.js.map +1 -0
  17. package/dist/errors.js +16 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/image-captcha.js +173 -0
  20. package/dist/image-captcha.js.map +1 -0
  21. package/dist/image-metadata.js +128 -0
  22. package/dist/image-metadata.js.map +1 -0
  23. package/dist/import-security.js +46 -0
  24. package/dist/import-security.js.map +1 -0
  25. package/dist/parser.js +223 -0
  26. package/dist/parser.js.map +1 -0
  27. package/dist/public/ai-context-meter.js +10 -0
  28. package/dist/public/ai-conversation.js +3 -0
  29. package/dist/public/ai-mentions.js +55 -0
  30. package/dist/public/ai-message-actions.js +27 -0
  31. package/dist/public/ai-message-meta.js +15 -0
  32. package/dist/public/ai-message-time.js +23 -0
  33. package/dist/public/ai-prompt-keyboard.js +3 -0
  34. package/dist/public/app.js +4255 -0
  35. package/dist/public/character-profile.d.ts +9 -0
  36. package/dist/public/character-profile.js +65 -0
  37. package/dist/public/character-version.d.ts +2 -0
  38. package/dist/public/character-version.js +31 -0
  39. package/dist/public/entity-version.js +34 -0
  40. package/dist/public/icon.svg +10 -0
  41. package/dist/public/index.html +547 -0
  42. package/dist/public/line-number-layout.js +15 -0
  43. package/dist/public/markdown.js +199 -0
  44. package/dist/public/model-config.d.ts +17 -0
  45. package/dist/public/model-config.js +57 -0
  46. package/dist/public/page-route.d.ts +11 -0
  47. package/dist/public/page-route.js +81 -0
  48. package/dist/public/relationship-graph.js +2017 -0
  49. package/dist/public/site.webmanifest +17 -0
  50. package/dist/public/styles.css +1399 -0
  51. package/dist/public/text-formatting.d.ts +2 -0
  52. package/dist/public/text-formatting.js +20 -0
  53. package/dist/public/theme-init.js +8 -0
  54. package/dist/public/theme.js +13 -0
  55. package/dist/public/whitespace-visualization.js +20 -0
  56. package/dist/request-context.js +9 -0
  57. package/dist/request-context.js.map +1 -0
  58. package/dist/security.js +235 -0
  59. package/dist/security.js.map +1 -0
  60. package/dist/server-runtime.js +77 -0
  61. package/dist/server-runtime.js.map +1 -0
  62. package/dist/server.js +15 -0
  63. package/dist/server.js.map +1 -0
  64. package/dist/store.js +2492 -0
  65. package/dist/store.js.map +1 -0
  66. package/dist/user-auth.js +489 -0
  67. package/dist/user-auth.js.map +1 -0
  68. package/dist/utils.js +50 -0
  69. package/dist/utils.js.map +1 -0
  70. package/package.json +4 -9
@@ -0,0 +1,2 @@
1
+ export function collapseExcessBlankLines(value: unknown): string;
2
+ export function normalizeParagraphSpacing(value: unknown): string;
@@ -0,0 +1,20 @@
1
+ export function collapseExcessBlankLines(value) {
2
+ return String(value ?? "")
3
+ .replace(/\r\n?/gu, "\n")
4
+ .replace(/\n(?:[\t\p{Zs}\uFEFF]*\n){2,}/gu, "\n\n");
5
+ }
6
+
7
+ export function normalizeParagraphSpacing(value) {
8
+ return collapseExcessBlankLines(value)
9
+ .replace(/[\t\p{Zs}\uFEFF]+$/gmu, "")
10
+ .replace(/^\n+/u, "")
11
+ .replace(/\n+$/u, "")
12
+ .replace(/\n{3,}/gu, "\n\n");
13
+ }
14
+
15
+ export function formatDateTime(value) {
16
+ const date = new Date(value);
17
+ if (Number.isNaN(date.getTime())) return "";
18
+ const pad = (part) => String(part).padStart(2, "0");
19
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
20
+ }
@@ -0,0 +1,8 @@
1
+ (() => {
2
+ let storedTheme = null;
3
+ try { storedTheme = localStorage.getItem("scriverse-color-theme-v1"); } catch { /* 使用系统主题 */ }
4
+ const prefersDark = window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
5
+ const theme = storedTheme === "dark" || storedTheme === "light" ? storedTheme : prefersDark ? "dark" : "light";
6
+ document.documentElement.dataset.theme = theme;
7
+ document.documentElement.style.colorScheme = theme;
8
+ })();
@@ -0,0 +1,13 @@
1
+ export const THEME_STORAGE_KEY = "scriverse-color-theme-v1";
2
+
3
+ export function normalizeTheme(value, prefersDark = false) {
4
+ return value === "dark" || value === "light" ? value : prefersDark ? "dark" : "light";
5
+ }
6
+
7
+ export function nextTheme(theme) {
8
+ return normalizeTheme(theme) === "dark" ? "light" : "dark";
9
+ }
10
+
11
+ export function themeToggleLabel(theme) {
12
+ return normalizeTheme(theme) === "dark" ? "切换到白天模式" : "切换到黑夜模式";
13
+ }
@@ -0,0 +1,20 @@
1
+ export function tokenizeVisibleSpaces(value) {
2
+ const tokens = [];
3
+ let text = "";
4
+ const flushText = () => {
5
+ if (!text) return;
6
+ tokens.push({ type: "text", text });
7
+ text = "";
8
+ };
9
+ for (const character of String(value ?? "")) {
10
+ if (character === " " || character === "\u3000" || character === "\t") {
11
+ flushText();
12
+ const type = character === " " ? "space" : character === "\u3000" ? "ideographic-space" : "tab";
13
+ tokens.push({ type, text: character });
14
+ } else {
15
+ text += character;
16
+ }
17
+ }
18
+ flushText();
19
+ return tokens;
20
+ }
@@ -0,0 +1,9 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const actorStorage = new AsyncLocalStorage();
3
+ export function runWithRequestActor(actor, operation) {
4
+ return actorStorage.run(actor, operation);
5
+ }
6
+ export function currentRequestActor() {
7
+ return actorStorage.getStore() ?? null;
8
+ }
9
+ //# sourceMappingURL=request-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAUrD,MAAM,YAAY,GAAG,IAAI,iBAAiB,EAAuB,CAAC;AAElE,MAAM,UAAU,mBAAmB,CAAI,KAA0B,EAAE,SAAkB;IACnF,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,YAAY,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AACzC,CAAC"}
@@ -0,0 +1,235 @@
1
+ import { createHash, timingSafeEqual } from "node:crypto";
2
+ import { isIP } from "node:net";
3
+ import { lookup } from "node:dns/promises";
4
+ import { AppError } from "./errors.js";
5
+ const digest = (value) => createHash("sha256").update(value).digest();
6
+ const constantTimeEqual = (left, right) => timingSafeEqual(digest(left), digest(right));
7
+ function requestKey(request) {
8
+ return request.ip || request.socket.remoteAddress || "unknown";
9
+ }
10
+ function consumeRate(entries, key, limit, windowMs) {
11
+ const currentTime = Date.now();
12
+ const existing = entries.get(key);
13
+ const entry = !existing || existing.resetAt <= currentTime ? { count: 0, resetAt: currentTime + windowMs } : existing;
14
+ entry.count += 1;
15
+ entries.set(key, entry);
16
+ if (entries.size > 10_000) {
17
+ for (const [candidate, value] of entries)
18
+ if (value.resetAt <= currentTime)
19
+ entries.delete(candidate);
20
+ }
21
+ return { allowed: entry.count <= limit, retryAfter: Math.max(1, Math.ceil((entry.resetAt - currentTime) / 1000)) };
22
+ }
23
+ function unauthorized(response, realm) {
24
+ response.setHeader("WWW-Authenticate", `Basic realm="${realm.replace(/["\\]/gu, "")}", charset="UTF-8"`);
25
+ response.setHeader("Cache-Control", "no-store");
26
+ response.status(401).json({ error: { code: "AUTH_REQUIRED", message: "需要管理员身份验证" } });
27
+ }
28
+ function parseBasicCredentials(header) {
29
+ if (!header?.startsWith("Basic "))
30
+ return null;
31
+ try {
32
+ const decoded = Buffer.from(header.slice(6).trim(), "base64").toString("utf8");
33
+ const separator = decoded.indexOf(":");
34
+ if (separator < 0)
35
+ return null;
36
+ return { username: decoded.slice(0, separator), password: decoded.slice(separator + 1) };
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ export function createBasicAuthMiddleware(options) {
43
+ const realm = options.realm ?? "Scriverse";
44
+ const failureLimit = options.failureLimit ?? 10;
45
+ const failureWindowMs = options.failureWindowMs ?? 15 * 60_000;
46
+ const failures = new Map();
47
+ return (request, response, next) => {
48
+ if (request.path === "/api/health")
49
+ return next();
50
+ const key = requestKey(request);
51
+ const credentials = parseBasicCredentials(request.get("authorization"));
52
+ const valid = credentials
53
+ && constantTimeEqual(credentials.username, options.username)
54
+ && constantTimeEqual(credentials.password, options.password);
55
+ if (valid) {
56
+ failures.delete(key);
57
+ return next();
58
+ }
59
+ const rate = consumeRate(failures, key, failureLimit, failureWindowMs);
60
+ if (!rate.allowed) {
61
+ response.setHeader("Retry-After", String(rate.retryAfter));
62
+ response.status(429).json({ error: { code: "AUTH_RATE_LIMITED", message: "身份验证失败次数过多,请稍后重试" } });
63
+ return;
64
+ }
65
+ unauthorized(response, realm);
66
+ };
67
+ }
68
+ export function createSecurityHeadersMiddleware() {
69
+ return (request, response, next) => {
70
+ response.setHeader("Content-Security-Policy", "default-src 'self'; base-uri 'none'; connect-src 'self'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' data: blob: https:; manifest-src 'self'; media-src 'none'; object-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; worker-src 'none'");
71
+ response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
72
+ response.setHeader("Cross-Origin-Resource-Policy", "same-origin");
73
+ response.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(), usb=()");
74
+ response.setHeader("Referrer-Policy", "same-origin");
75
+ response.setHeader("X-Content-Type-Options", "nosniff");
76
+ response.setHeader("X-Frame-Options", "DENY");
77
+ response.setHeader("X-Permitted-Cross-Domain-Policies", "none");
78
+ response.setHeader("Cache-Control", request.path.startsWith("/api/") ? "no-store" : "private, no-cache");
79
+ response.vary("Authorization");
80
+ if (request.secure)
81
+ response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
82
+ next();
83
+ };
84
+ }
85
+ export function createSameOriginMiddleware() {
86
+ return (request, response, next) => {
87
+ if (["GET", "HEAD", "OPTIONS"].includes(request.method))
88
+ return next();
89
+ if (request.get("sec-fetch-site") === "cross-site") {
90
+ response.status(403).json({ error: { code: "CROSS_ORIGIN_WRITE_BLOCKED", message: "已拒绝跨站写请求" } });
91
+ return;
92
+ }
93
+ const origin = request.get("origin");
94
+ if (!origin)
95
+ return next();
96
+ const host = request.get("host");
97
+ let expectedOrigin = "";
98
+ try {
99
+ expectedOrigin = new URL(`${request.protocol}://${host}`).origin;
100
+ }
101
+ catch {
102
+ response.status(400).json({ error: { code: "INVALID_HOST", message: "请求主机信息无效" } });
103
+ return;
104
+ }
105
+ if (origin !== expectedOrigin) {
106
+ response.status(403).json({ error: { code: "CROSS_ORIGIN_WRITE_BLOCKED", message: "已拒绝跨站写请求" } });
107
+ return;
108
+ }
109
+ next();
110
+ };
111
+ }
112
+ export function createApiRateLimitMiddleware(limit = 600, windowMs = 60_000) {
113
+ const entries = new Map();
114
+ return (request, response, next) => {
115
+ if (!request.path.startsWith("/api/") || request.path === "/api/health")
116
+ return next();
117
+ const rate = consumeRate(entries, requestKey(request), limit, windowMs);
118
+ if (rate.allowed)
119
+ return next();
120
+ response.setHeader("Retry-After", String(rate.retryAfter));
121
+ response.status(429).json({ error: { code: "API_RATE_LIMITED", message: "请求过于频繁,请稍后重试" } });
122
+ };
123
+ }
124
+ export function createAuthenticationRateLimitMiddleware(limit = 20, windowMs = 15 * 60_000) {
125
+ const entries = new Map();
126
+ return (request, response, next) => {
127
+ const authenticationWrite = request.method === "POST" && ["/api/auth/login", "/api/auth/register"].includes(request.path);
128
+ if (!authenticationWrite)
129
+ return next();
130
+ const rate = consumeRate(entries, `${requestKey(request)}:${request.path}`, limit, windowMs);
131
+ if (rate.allowed)
132
+ return next();
133
+ response.setHeader("Retry-After", String(rate.retryAfter));
134
+ response.status(429).json({ error: { code: "AUTH_RATE_LIMITED", message: "登录或注册尝试过于频繁,请稍后重试" } });
135
+ };
136
+ }
137
+ function parseIpv4(address) {
138
+ if (isIP(address) !== 4)
139
+ return null;
140
+ return address.split(".").map(Number);
141
+ }
142
+ function unsafeIpKind(address) {
143
+ const ipv4 = parseIpv4(address);
144
+ if (ipv4) {
145
+ const a = ipv4[0] ?? -1;
146
+ const b = ipv4[1] ?? -1;
147
+ if (a === 127 || a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168))
148
+ return "private";
149
+ if (a === 0 || (a === 100 && b >= 64 && b <= 127) || (a === 169 && b === 254) || a >= 224)
150
+ return "blocked";
151
+ return null;
152
+ }
153
+ const normalized = address.toLocaleLowerCase();
154
+ if (normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd"))
155
+ return "private";
156
+ if (normalized === "::" || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb") || normalized.startsWith("ff"))
157
+ return "blocked";
158
+ if (normalized.startsWith("::ffff:"))
159
+ return unsafeIpKind(normalized.slice(7));
160
+ return null;
161
+ }
162
+ export async function assertSafeAiEndpoint(value, allowPrivateNetwork = false) {
163
+ const endpoint = new URL(value);
164
+ if (!['http:', 'https:'].includes(endpoint.protocol) || endpoint.username || endpoint.password) {
165
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商地址必须是无内嵌凭据的 HTTP 或 HTTPS 地址");
166
+ }
167
+ const addresses = isIP(endpoint.hostname)
168
+ ? [{ address: endpoint.hostname }]
169
+ : await lookup(endpoint.hostname, { all: true, verbatim: true }).catch(() => []);
170
+ if (!addresses.length)
171
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商域名无法解析");
172
+ for (const { address } of addresses) {
173
+ const kind = unsafeIpKind(address);
174
+ if (kind === "blocked" || (kind === "private" && !allowPrivateNetwork)) {
175
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商地址指向受保护的本机、内网或链路本地网络");
176
+ }
177
+ }
178
+ }
179
+ const redirectStatuses = new Set([301, 302, 303, 307, 308]);
180
+ /**
181
+ * 出站 AI 请求:禁止浏览器式自动跟随重定向。
182
+ * 每一跳都重新做 SSRF 校验;跨主机跳转时剥离 Authorization,避免密钥泄露到跳转目标。
183
+ */
184
+ export async function fetchSafeAiEndpoint(fetchImpl, url, init, validateOutboundUrl, maxRedirects = 5) {
185
+ let currentUrl = url;
186
+ const baseHeaders = new Headers(init.headers);
187
+ for (let hop = 0; hop <= maxRedirects; hop += 1) {
188
+ await validateOutboundUrl?.(currentUrl);
189
+ const response = await fetchImpl(currentUrl, { ...init, headers: baseHeaders, redirect: "manual" });
190
+ if (!redirectStatuses.has(response.status))
191
+ return response;
192
+ const location = response.headers.get("location");
193
+ if (!location) {
194
+ throw new AppError(502, "PROVIDER_REDIRECT_INVALID", "AI 供应商返回了无效的重定向响应");
195
+ }
196
+ let nextUrl;
197
+ try {
198
+ nextUrl = new URL(location, currentUrl);
199
+ }
200
+ catch {
201
+ throw new AppError(502, "PROVIDER_REDIRECT_INVALID", "AI 供应商返回了无效的重定向地址");
202
+ }
203
+ if (nextUrl.origin !== new URL(currentUrl).origin) {
204
+ baseHeaders.delete("authorization");
205
+ }
206
+ if (response.status === 303) {
207
+ init = { ...init, method: "GET", body: undefined };
208
+ }
209
+ currentUrl = nextUrl.toString();
210
+ }
211
+ throw new AppError(502, "PROVIDER_REDIRECT_LIMIT", "AI 供应商重定向次数过多");
212
+ }
213
+ export function resolveRuntimeSecurity(environment, requireAuthentication = false) {
214
+ const production = environment.NODE_ENV === "production";
215
+ const username = environment.APP_AUTH_USERNAME?.trim() ?? "";
216
+ const password = environment.APP_AUTH_PASSWORD ?? "";
217
+ if (Boolean(username) !== Boolean(password))
218
+ throw new Error("APP_AUTH_USERNAME 与 APP_AUTH_PASSWORD 必须同时配置");
219
+ if (requireAuthentication && (!username || !password))
220
+ throw new Error("当前部署策略要求配置 APP_AUTH_USERNAME 与 APP_AUTH_PASSWORD");
221
+ if (password && password.length < 12)
222
+ throw new Error("APP_AUTH_PASSWORD 至少需要 12 个字符");
223
+ const trustProxyValue = environment.APP_TRUST_PROXY?.trim() ?? "";
224
+ const trustProxy = trustProxyValue === "true" ? true : /^\d+$/u.test(trustProxyValue) ? Number(trustProxyValue) : false;
225
+ if (typeof trustProxy === "number" && (trustProxy < 0 || trustProxy > 10))
226
+ throw new Error("APP_TRUST_PROXY 只能是 true 或 0-10 的整数");
227
+ return {
228
+ ...(username ? { auth: { username, password } } : {}),
229
+ trustProxy,
230
+ enforceSameOrigin: true,
231
+ allowPrivateAiEndpoints: environment.APP_ALLOW_PRIVATE_AI_ENDPOINTS === "true" || !production,
232
+ allowRegistration: environment.APP_ALLOW_REGISTRATION !== "false"
233
+ };
234
+ }
235
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { join } from "node:path";
3
+ import { createRuntime } from "./app.js";
4
+ import { loadMasterSecret } from "./credential-vault.js";
5
+ import { resolveRuntimeSecurity } from "./security.js";
6
+ const publicPath = fileURLToPath(new URL("./public/", import.meta.url));
7
+ export async function startLocalServer(options) {
8
+ const security = resolveRuntimeSecurity(options.env);
9
+ const runtime = createRuntime({
10
+ databasePath: options.databasePath,
11
+ masterSecret: loadMasterSecret(join(options.dataDirectory, "master.key"), options.env.AI_NOVEL_MASTER_KEY),
12
+ publicPath,
13
+ security
14
+ });
15
+ return await new Promise((resolveStart, rejectStart) => {
16
+ const server = runtime.app.listen(options.port, options.host);
17
+ const handleStartupError = (error) => {
18
+ runtime.close();
19
+ rejectStart(error);
20
+ };
21
+ server.once("error", handleStartupError);
22
+ server.once("listening", () => {
23
+ server.off("error", handleStartupError);
24
+ const address = server.address();
25
+ if (!address || typeof address === "string") {
26
+ server.close();
27
+ runtime.close();
28
+ rejectStart(new Error("Scriverse server did not expose a TCP port"));
29
+ return;
30
+ }
31
+ const port = address.port;
32
+ const displayHost = options.host.includes(":") ? `[${options.host}]` : options.host;
33
+ let closed = false;
34
+ const close = async () => {
35
+ if (closed)
36
+ return;
37
+ closed = true;
38
+ server.closeAllConnections();
39
+ try {
40
+ await new Promise((resolveClose, rejectClose) => {
41
+ server.close((error) => error ? rejectClose(error) : resolveClose());
42
+ });
43
+ }
44
+ finally {
45
+ runtime.close();
46
+ }
47
+ };
48
+ resolveStart({
49
+ server,
50
+ runtime,
51
+ url: `http://${displayHost}:${port}`,
52
+ host: options.host,
53
+ port,
54
+ dataDirectory: options.dataDirectory,
55
+ databasePath: options.databasePath,
56
+ security,
57
+ close
58
+ });
59
+ });
60
+ });
61
+ }
62
+ export function installServerShutdownHandlers(running) {
63
+ let shuttingDown = false;
64
+ const shutdown = (signal) => {
65
+ if (shuttingDown)
66
+ return;
67
+ shuttingDown = true;
68
+ console.log(`Received ${signal}, shutting down`);
69
+ void running.close().then(() => { process.exitCode = 0; }, (error) => {
70
+ console.error(error instanceof Error ? error.message : "Failed to stop Scriverse server");
71
+ process.exitCode = 1;
72
+ });
73
+ };
74
+ process.once("SIGINT", () => shutdown("SIGINT"));
75
+ process.once("SIGTERM", () => shutdown("SIGTERM"));
76
+ }
77
+ //# sourceMappingURL=server-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-runtime.js","sourceRoot":"","sources":["../src/server-runtime.ts"],"names":[],"mappings":"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"}
package/dist/server.js ADDED
@@ -0,0 +1,15 @@
1
+ import { join } from "node:path";
2
+ import { installServerShutdownHandlers, startLocalServer } from "./server-runtime.js";
3
+ const port = Number(process.env.PORT ?? 13210);
4
+ const host = process.env.HOST ?? "127.0.0.1";
5
+ const dataDirectory = process.env.DATA_DIR ?? join(process.cwd(), ".data");
6
+ const running = await startLocalServer({
7
+ port,
8
+ host,
9
+ dataDirectory,
10
+ databasePath: process.env.DATABASE_PATH ?? join(dataDirectory, "novel.db"),
11
+ env: process.env
12
+ });
13
+ console.log(`Scriverse listening on ${running.url} (user authentication enabled${running.security.auth ? ", deployment gateway enabled" : ""})`);
14
+ installServerShutdownHandlers(running);
15
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEtF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC;AAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,WAAW,CAAC;AAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AAC3E,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC;IACrC,IAAI;IACJ,IAAI;IACJ,aAAa;IACb,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;IAC1E,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,CAAC;AAEH,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,CAAC,GAAG,gCAAgC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACjJ,6BAA6B,CAAC,OAAO,CAAC,CAAC"}