@musnows/scriverse 0.2.0 → 0.3.1

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 (74) hide show
  1. package/README.en.md +13 -4
  2. package/README.md +13 -4
  3. package/dist/ai.js +3548 -0
  4. package/dist/ai.js.map +1 -0
  5. package/dist/app.js +1079 -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 +1220 -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/http-logging.js +76 -0
  20. package/dist/http-logging.js.map +1 -0
  21. package/dist/image-captcha.js +173 -0
  22. package/dist/image-captcha.js.map +1 -0
  23. package/dist/image-metadata.js +128 -0
  24. package/dist/image-metadata.js.map +1 -0
  25. package/dist/import-security.js +46 -0
  26. package/dist/import-security.js.map +1 -0
  27. package/dist/logger.js +110 -0
  28. package/dist/logger.js.map +1 -0
  29. package/dist/parser.js +223 -0
  30. package/dist/parser.js.map +1 -0
  31. package/dist/public/ai-context-meter.js +10 -0
  32. package/dist/public/ai-conversation.js +3 -0
  33. package/dist/public/ai-mentions.js +55 -0
  34. package/dist/public/ai-message-actions.js +27 -0
  35. package/dist/public/ai-message-meta.js +15 -0
  36. package/dist/public/ai-message-time.js +23 -0
  37. package/dist/public/ai-prompt-keyboard.js +3 -0
  38. package/dist/public/app.js +4435 -0
  39. package/dist/public/character-profile.d.ts +9 -0
  40. package/dist/public/character-profile.js +65 -0
  41. package/dist/public/character-version.d.ts +2 -0
  42. package/dist/public/character-version.js +31 -0
  43. package/dist/public/entity-version.js +34 -0
  44. package/dist/public/icon.svg +10 -0
  45. package/dist/public/index.html +547 -0
  46. package/dist/public/line-number-layout.js +15 -0
  47. package/dist/public/markdown.js +199 -0
  48. package/dist/public/model-config.d.ts +17 -0
  49. package/dist/public/model-config.js +57 -0
  50. package/dist/public/page-route.d.ts +11 -0
  51. package/dist/public/page-route.js +81 -0
  52. package/dist/public/relationship-graph.js +2017 -0
  53. package/dist/public/site.webmanifest +17 -0
  54. package/dist/public/styles.css +1441 -0
  55. package/dist/public/text-formatting.d.ts +2 -0
  56. package/dist/public/text-formatting.js +20 -0
  57. package/dist/public/theme-init.js +8 -0
  58. package/dist/public/theme.js +13 -0
  59. package/dist/public/whitespace-visualization.js +20 -0
  60. package/dist/request-context.js +16 -0
  61. package/dist/request-context.js.map +1 -0
  62. package/dist/security.js +247 -0
  63. package/dist/security.js.map +1 -0
  64. package/dist/server-runtime.js +90 -0
  65. package/dist/server-runtime.js.map +1 -0
  66. package/dist/server.js +26 -0
  67. package/dist/server.js.map +1 -0
  68. package/dist/store.js +2568 -0
  69. package/dist/store.js.map +1 -0
  70. package/dist/user-auth.js +515 -0
  71. package/dist/user-auth.js.map +1 -0
  72. package/dist/utils.js +67 -0
  73. package/dist/utils.js.map +1 -0
  74. 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,16 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const requestStorage = new AsyncLocalStorage();
3
+ export function runWithRequestContext(context, operation) {
4
+ return requestStorage.run(context, operation);
5
+ }
6
+ export function runWithRequestActor(actor, operation) {
7
+ const current = requestStorage.getStore();
8
+ return requestStorage.run({ ...(current?.requestId ? { requestId: current.requestId } : {}), actor }, operation);
9
+ }
10
+ export function currentRequestActor() {
11
+ return requestStorage.getStore()?.actor ?? null;
12
+ }
13
+ export function currentRequestContext() {
14
+ return requestStorage.getStore() ?? null;
15
+ }
16
+ //# 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;AAerD,MAAM,cAAc,GAAG,IAAI,iBAAiB,EAAyB,CAAC;AAEtE,MAAM,UAAU,qBAAqB,CAAI,OAAuB,EAAE,SAAkB;IAClF,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAI,KAA0B,EAAE,SAAkB;IACnF,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,CAAC;IAC1C,OAAO,cAAc,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;AACnH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,cAAc,CAAC,QAAQ,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,cAAc,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,247 @@
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
+ import { logger } from "./logger.js";
6
+ const digest = (value) => createHash("sha256").update(value).digest();
7
+ const constantTimeEqual = (left, right) => timingSafeEqual(digest(left), digest(right));
8
+ function requestKey(request) {
9
+ return request.ip || request.socket.remoteAddress || "unknown";
10
+ }
11
+ function consumeRate(entries, key, limit, windowMs) {
12
+ const currentTime = Date.now();
13
+ const existing = entries.get(key);
14
+ const entry = !existing || existing.resetAt <= currentTime ? { count: 0, resetAt: currentTime + windowMs } : existing;
15
+ entry.count += 1;
16
+ entries.set(key, entry);
17
+ if (entries.size > 10_000) {
18
+ for (const [candidate, value] of entries)
19
+ if (value.resetAt <= currentTime)
20
+ entries.delete(candidate);
21
+ }
22
+ return { allowed: entry.count <= limit, retryAfter: Math.max(1, Math.ceil((entry.resetAt - currentTime) / 1000)) };
23
+ }
24
+ function unauthorized(response, realm) {
25
+ response.setHeader("WWW-Authenticate", `Basic realm="${realm.replace(/["\\]/gu, "")}", charset="UTF-8"`);
26
+ response.setHeader("Cache-Control", "no-store");
27
+ response.status(401).json({ error: { code: "AUTH_REQUIRED", message: "需要管理员身份验证" } });
28
+ }
29
+ function parseBasicCredentials(header) {
30
+ if (!header?.startsWith("Basic "))
31
+ return null;
32
+ try {
33
+ const decoded = Buffer.from(header.slice(6).trim(), "base64").toString("utf8");
34
+ const separator = decoded.indexOf(":");
35
+ if (separator < 0)
36
+ return null;
37
+ return { username: decoded.slice(0, separator), password: decoded.slice(separator + 1) };
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ export function createBasicAuthMiddleware(options) {
44
+ const realm = options.realm ?? "Scriverse";
45
+ const failureLimit = options.failureLimit ?? 10;
46
+ const failureWindowMs = options.failureWindowMs ?? 15 * 60_000;
47
+ const failures = new Map();
48
+ return (request, response, next) => {
49
+ if (request.path === "/api/health")
50
+ return next();
51
+ const key = requestKey(request);
52
+ const credentials = parseBasicCredentials(request.get("authorization"));
53
+ const valid = credentials
54
+ && constantTimeEqual(credentials.username, options.username)
55
+ && constantTimeEqual(credentials.password, options.password);
56
+ if (valid) {
57
+ failures.delete(key);
58
+ logger.debug("security.deployment_auth.succeeded");
59
+ return next();
60
+ }
61
+ const rate = consumeRate(failures, key, failureLimit, failureWindowMs);
62
+ if (!rate.allowed) {
63
+ logger.warn("security.request.blocked", { control: "deployment_auth_rate_limit", retryAfterSeconds: rate.retryAfter });
64
+ response.setHeader("Retry-After", String(rate.retryAfter));
65
+ response.status(429).json({ error: { code: "AUTH_RATE_LIMITED", message: "身份验证失败次数过多,请稍后重试" } });
66
+ return;
67
+ }
68
+ logger.warn("security.request.blocked", { control: "deployment_auth", reason: credentials ? "invalid_credentials" : "missing_credentials" });
69
+ unauthorized(response, realm);
70
+ };
71
+ }
72
+ export function createSecurityHeadersMiddleware() {
73
+ return (request, response, next) => {
74
+ 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'");
75
+ response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
76
+ response.setHeader("Cross-Origin-Resource-Policy", "same-origin");
77
+ response.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(), usb=()");
78
+ response.setHeader("Referrer-Policy", "same-origin");
79
+ response.setHeader("X-Content-Type-Options", "nosniff");
80
+ response.setHeader("X-Frame-Options", "DENY");
81
+ response.setHeader("X-Permitted-Cross-Domain-Policies", "none");
82
+ response.setHeader("Cache-Control", request.path.startsWith("/api/") ? "no-store" : "private, no-cache");
83
+ response.vary("Authorization");
84
+ if (request.secure)
85
+ response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
86
+ next();
87
+ };
88
+ }
89
+ export function createSameOriginMiddleware() {
90
+ return (request, response, next) => {
91
+ if (["GET", "HEAD", "OPTIONS"].includes(request.method))
92
+ return next();
93
+ if (request.get("sec-fetch-site") === "cross-site") {
94
+ logger.warn("security.request.blocked", { control: "same_origin", reason: "cross_site_fetch" });
95
+ response.status(403).json({ error: { code: "CROSS_ORIGIN_WRITE_BLOCKED", message: "已拒绝跨站写请求" } });
96
+ return;
97
+ }
98
+ const origin = request.get("origin");
99
+ if (!origin)
100
+ return next();
101
+ const host = request.get("host");
102
+ let expectedOrigin = "";
103
+ try {
104
+ expectedOrigin = new URL(`${request.protocol}://${host}`).origin;
105
+ }
106
+ catch {
107
+ logger.warn("security.request.blocked", { control: "same_origin", reason: "invalid_host" });
108
+ response.status(400).json({ error: { code: "INVALID_HOST", message: "请求主机信息无效" } });
109
+ return;
110
+ }
111
+ if (origin !== expectedOrigin) {
112
+ logger.warn("security.request.blocked", { control: "same_origin", reason: "origin_mismatch" });
113
+ response.status(403).json({ error: { code: "CROSS_ORIGIN_WRITE_BLOCKED", message: "已拒绝跨站写请求" } });
114
+ return;
115
+ }
116
+ next();
117
+ };
118
+ }
119
+ export function createApiRateLimitMiddleware(limit = 600, windowMs = 60_000) {
120
+ const entries = new Map();
121
+ return (request, response, next) => {
122
+ if (!request.path.startsWith("/api/") || request.path === "/api/health")
123
+ return next();
124
+ const rate = consumeRate(entries, requestKey(request), limit, windowMs);
125
+ if (rate.allowed)
126
+ return next();
127
+ logger.warn("security.request.blocked", { control: "api_rate_limit", retryAfterSeconds: rate.retryAfter });
128
+ response.setHeader("Retry-After", String(rate.retryAfter));
129
+ response.status(429).json({ error: { code: "API_RATE_LIMITED", message: "请求过于频繁,请稍后重试" } });
130
+ };
131
+ }
132
+ export function createAuthenticationRateLimitMiddleware(limit = 20, windowMs = 15 * 60_000) {
133
+ const entries = new Map();
134
+ return (request, response, next) => {
135
+ const authenticationWrite = request.method === "POST" && ["/api/auth/login", "/api/auth/register"].includes(request.path);
136
+ if (!authenticationWrite)
137
+ return next();
138
+ const rate = consumeRate(entries, `${requestKey(request)}:${request.path}`, limit, windowMs);
139
+ if (rate.allowed)
140
+ return next();
141
+ logger.warn("security.request.blocked", { control: "authentication_rate_limit", retryAfterSeconds: rate.retryAfter });
142
+ response.setHeader("Retry-After", String(rate.retryAfter));
143
+ response.status(429).json({ error: { code: "AUTH_RATE_LIMITED", message: "登录或注册尝试过于频繁,请稍后重试" } });
144
+ };
145
+ }
146
+ function parseIpv4(address) {
147
+ if (isIP(address) !== 4)
148
+ return null;
149
+ return address.split(".").map(Number);
150
+ }
151
+ function unsafeIpKind(address) {
152
+ const ipv4 = parseIpv4(address);
153
+ if (ipv4) {
154
+ const a = ipv4[0] ?? -1;
155
+ const b = ipv4[1] ?? -1;
156
+ if (a === 127 || a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168))
157
+ return "private";
158
+ if (a === 0 || (a === 100 && b >= 64 && b <= 127) || (a === 169 && b === 254) || a >= 224)
159
+ return "blocked";
160
+ return null;
161
+ }
162
+ const normalized = address.toLocaleLowerCase();
163
+ if (normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd"))
164
+ return "private";
165
+ if (normalized === "::" || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb") || normalized.startsWith("ff"))
166
+ return "blocked";
167
+ if (normalized.startsWith("::ffff:"))
168
+ return unsafeIpKind(normalized.slice(7));
169
+ return null;
170
+ }
171
+ export async function assertSafeAiEndpoint(value, allowPrivateNetwork = false) {
172
+ const endpoint = new URL(value);
173
+ if (!['http:', 'https:'].includes(endpoint.protocol) || endpoint.username || endpoint.password) {
174
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商地址必须是无内嵌凭据的 HTTP 或 HTTPS 地址");
175
+ }
176
+ const addresses = isIP(endpoint.hostname)
177
+ ? [{ address: endpoint.hostname }]
178
+ : await lookup(endpoint.hostname, { all: true, verbatim: true }).catch(() => []);
179
+ if (!addresses.length)
180
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商域名无法解析");
181
+ for (const { address } of addresses) {
182
+ const kind = unsafeIpKind(address);
183
+ if (kind === "blocked" || (kind === "private" && !allowPrivateNetwork)) {
184
+ logger.warn("security.ai_endpoint.blocked", { hostname: endpoint.hostname, addressKind: kind });
185
+ throw new AppError(400, "UNSAFE_PROVIDER_ENDPOINT", "AI 供应商地址指向受保护的本机、内网或链路本地网络");
186
+ }
187
+ }
188
+ }
189
+ const redirectStatuses = new Set([301, 302, 303, 307, 308]);
190
+ /**
191
+ * 出站 AI 请求:禁止浏览器式自动跟随重定向。
192
+ * 每一跳都重新做 SSRF 校验;跨主机跳转时剥离 Authorization,避免密钥泄露到跳转目标。
193
+ */
194
+ export async function fetchSafeAiEndpoint(fetchImpl, url, init, validateOutboundUrl, maxRedirects = 5) {
195
+ let currentUrl = url;
196
+ const baseHeaders = new Headers(init.headers);
197
+ for (let hop = 0; hop <= maxRedirects; hop += 1) {
198
+ logger.debug("ai.outbound_request.validating", { hostname: new URL(currentUrl).hostname, hop });
199
+ await validateOutboundUrl?.(currentUrl);
200
+ const response = await fetchImpl(currentUrl, { ...init, headers: baseHeaders, redirect: "manual" });
201
+ logger.debug("ai.outbound_request.response", { hostname: new URL(currentUrl).hostname, hop, status: response.status });
202
+ if (!redirectStatuses.has(response.status))
203
+ return response;
204
+ const location = response.headers.get("location");
205
+ if (!location) {
206
+ throw new AppError(502, "PROVIDER_REDIRECT_INVALID", "AI 供应商返回了无效的重定向响应");
207
+ }
208
+ let nextUrl;
209
+ try {
210
+ nextUrl = new URL(location, currentUrl);
211
+ }
212
+ catch {
213
+ throw new AppError(502, "PROVIDER_REDIRECT_INVALID", "AI 供应商返回了无效的重定向地址");
214
+ }
215
+ if (nextUrl.origin !== new URL(currentUrl).origin) {
216
+ baseHeaders.delete("authorization");
217
+ }
218
+ if (response.status === 303) {
219
+ init = { ...init, method: "GET", body: undefined };
220
+ }
221
+ currentUrl = nextUrl.toString();
222
+ }
223
+ throw new AppError(502, "PROVIDER_REDIRECT_LIMIT", "AI 供应商重定向次数过多");
224
+ }
225
+ export function resolveRuntimeSecurity(environment, requireAuthentication = false) {
226
+ const production = environment.NODE_ENV === "production";
227
+ const username = environment.APP_AUTH_USERNAME?.trim() ?? "";
228
+ const password = environment.APP_AUTH_PASSWORD ?? "";
229
+ if (Boolean(username) !== Boolean(password))
230
+ throw new Error("APP_AUTH_USERNAME 与 APP_AUTH_PASSWORD 必须同时配置");
231
+ if (requireAuthentication && (!username || !password))
232
+ throw new Error("当前部署策略要求配置 APP_AUTH_USERNAME 与 APP_AUTH_PASSWORD");
233
+ if (password && password.length < 12)
234
+ throw new Error("APP_AUTH_PASSWORD 至少需要 12 个字符");
235
+ const trustProxyValue = environment.APP_TRUST_PROXY?.trim() ?? "";
236
+ const trustProxy = trustProxyValue === "true" ? true : /^\d+$/u.test(trustProxyValue) ? Number(trustProxyValue) : false;
237
+ if (typeof trustProxy === "number" && (trustProxy < 0 || trustProxy > 10))
238
+ throw new Error("APP_TRUST_PROXY 只能是 true 或 0-10 的整数");
239
+ return {
240
+ ...(username ? { auth: { username, password } } : {}),
241
+ trustProxy,
242
+ enforceSameOrigin: true,
243
+ allowPrivateAiEndpoints: environment.APP_ALLOW_PRIVATE_AI_ENDPOINTS === "true" || !production,
244
+ allowRegistration: environment.APP_ALLOW_REGISTRATION !== "false"
245
+ };
246
+ }
247
+ //# 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,90 @@
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
+ import { logger, sanitizeError } from "./logger.js";
7
+ const publicPath = fileURLToPath(new URL("./public/", import.meta.url));
8
+ export async function startLocalServer(options) {
9
+ logger.info("server.starting", { host: options.host, port: options.port, dataDirectory: options.dataDirectory, databasePath: options.databasePath });
10
+ let security;
11
+ let runtime;
12
+ try {
13
+ security = resolveRuntimeSecurity(options.env);
14
+ runtime = createRuntime({
15
+ databasePath: options.databasePath,
16
+ masterSecret: loadMasterSecret(join(options.dataDirectory, "master.key"), options.env.AI_NOVEL_MASTER_KEY),
17
+ publicPath,
18
+ security
19
+ });
20
+ }
21
+ catch (error) {
22
+ logger.error("server.initialization_failed", { host: options.host, port: options.port, error: sanitizeError(error) });
23
+ throw error;
24
+ }
25
+ return await new Promise((resolveStart, rejectStart) => {
26
+ const server = runtime.app.listen(options.port, options.host);
27
+ const handleStartupError = (error) => {
28
+ logger.error("server.start_failed", { host: options.host, port: options.port, error: sanitizeError(error) });
29
+ runtime.close();
30
+ rejectStart(error);
31
+ };
32
+ server.once("error", handleStartupError);
33
+ server.once("listening", () => {
34
+ server.off("error", handleStartupError);
35
+ const address = server.address();
36
+ if (!address || typeof address === "string") {
37
+ server.close();
38
+ runtime.close();
39
+ rejectStart(new Error("Scriverse server did not expose a TCP port"));
40
+ return;
41
+ }
42
+ const port = address.port;
43
+ const displayHost = options.host.includes(":") ? `[${options.host}]` : options.host;
44
+ let closed = false;
45
+ const close = async () => {
46
+ if (closed)
47
+ return;
48
+ closed = true;
49
+ logger.info("server.stopping", { host: options.host, port });
50
+ server.closeAllConnections();
51
+ try {
52
+ await new Promise((resolveClose, rejectClose) => {
53
+ server.close((error) => error ? rejectClose(error) : resolveClose());
54
+ });
55
+ }
56
+ finally {
57
+ runtime.close();
58
+ logger.info("server.stopped", { host: options.host, port });
59
+ }
60
+ };
61
+ resolveStart({
62
+ server,
63
+ runtime,
64
+ url: `http://${displayHost}:${port}`,
65
+ host: options.host,
66
+ port,
67
+ dataDirectory: options.dataDirectory,
68
+ databasePath: options.databasePath,
69
+ security,
70
+ close
71
+ });
72
+ });
73
+ });
74
+ }
75
+ export function installServerShutdownHandlers(running) {
76
+ let shuttingDown = false;
77
+ const shutdown = (signal) => {
78
+ if (shuttingDown)
79
+ return;
80
+ shuttingDown = true;
81
+ logger.info("server.shutdown_signal_received", { signal });
82
+ void running.close().then(() => { process.exitCode = 0; }, (error) => {
83
+ logger.error("server.stop_failed", { signal, error: sanitizeError(error) });
84
+ process.exitCode = 1;
85
+ });
86
+ };
87
+ process.once("SIGINT", () => shutdown("SIGINT"));
88
+ process.once("SIGTERM", () => shutdown("SIGTERM"));
89
+ }
90
+ //# 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,26 @@
1
+ import { join } from "node:path";
2
+ import { installServerShutdownHandlers, startLocalServer } from "./server-runtime.js";
3
+ import { logger, resolveLogLevel } from "./logger.js";
4
+ const port = Number(process.env.PORT ?? 13210);
5
+ const host = process.env.HOST ?? "127.0.0.1";
6
+ const dataDirectory = process.env.DATA_DIR ?? join(process.cwd(), ".data");
7
+ process.on("uncaughtExceptionMonitor", (error, origin) => {
8
+ logger.error("process.uncaught_exception", { origin, error });
9
+ });
10
+ const running = await startLocalServer({
11
+ port,
12
+ host,
13
+ dataDirectory,
14
+ databasePath: process.env.DATABASE_PATH ?? join(dataDirectory, "novel.db"),
15
+ env: process.env
16
+ });
17
+ logger.info("server.listening", {
18
+ url: running.url,
19
+ host: running.host,
20
+ port: running.port,
21
+ logLevel: resolveLogLevel(process.env),
22
+ userAuthenticationEnabled: true,
23
+ deploymentGatewayEnabled: Boolean(running.security.auth)
24
+ });
25
+ installServerShutdownHandlers(running);
26
+ //# 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;AACtF,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEtD,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,OAAO,CAAC,EAAE,CAAC,0BAA0B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;IACvD,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC;AACH,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,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;IAC9B,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,IAAI,EAAE,OAAO,CAAC,IAAI;IAClB,IAAI,EAAE,OAAO,CAAC,IAAI;IAClB,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC;IACtC,yBAAyB,EAAE,IAAI;IAC/B,wBAAwB,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;CACzD,CAAC,CAAC;AACH,6BAA6B,CAAC,OAAO,CAAC,CAAC"}