chore: add CI, lint config, login rate limit and split large modules
- Rate-limit failed logins (8 per 15 min per IP or username, 429 + Retry-After) - Add ruff/mypy config and GitHub Actions workflow (ruff, pytest, tsc, tests, build) - Apply ruff autofixes (import order, pyupgrade) - Extract rpy_helpers.py, engine-util.ts, TranslationParts.tsx and translation-types.ts from oversized modules - Add dependency-free React UI tests - Refresh README and ARCHITECTURE (Naninovel/Tomie, status and plans) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
57a4edcbfd
commit
bbbcc6a5d8
42 files changed
+678
-391
No files matched your search
@@ -1,35 +1,17 @@
|
||||
// PGVN interpreter + in-game UI.
|
||||
|
||||
import { AudioSystem, type Volumes } from "./audio";
|
||||
import { AudioSystem } from "./audio";
|
||||
import { JumpSignal, PyDict, Python, decodeValue, encodeValue, pyStr, truthy, type Scope } from "./python";
|
||||
import { Renderer, type ResolvedImage } from "./renderer";
|
||||
import { fastPoint, interpolate, parseText, plainText, renderText, waitPoints } from "./text";
|
||||
import { languageName, rememberLanguage, type Translator } from "./i18n";
|
||||
import { naniText } from "./naninovel";
|
||||
import { DEFAULT_SETTINGS, SLOTS, Restart, el, loadJSON, saveJSON, type SaveApi, type SaveMeta, type Settings } from "./engine-util";
|
||||
import type {
|
||||
CharacterDef, Expr, Frame, GameData, ImageDef, Label, Layer, Manifest, Node, SaveData, ScriptModule,
|
||||
} from "./types";
|
||||
|
||||
export interface SaveMeta {
|
||||
slot: string;
|
||||
title: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SaveApi<T = SaveData> {
|
||||
list(): Promise<SaveMeta[]>;
|
||||
get(slot: string): Promise<T | null>;
|
||||
put(slot: string, title: string, data: T): Promise<void>;
|
||||
remove(slot: string): Promise<void>;
|
||||
}
|
||||
|
||||
interface Settings extends Volumes {
|
||||
cps: number; // characters per second, 0 = instant
|
||||
autoDelay: number; // seconds per 20 characters in auto mode
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: Settings = { cps: 45, autoDelay: 1.2, music: 0.7, sound: 0.8, voice: 1 };
|
||||
const SLOTS = 12;
|
||||
export type { SaveApi, SaveMeta } from "./engine-util";
|
||||
|
||||
interface LabelRef {
|
||||
label: Label;
|
||||
@@ -37,32 +19,6 @@ interface LabelRef {
|
||||
index: number;
|
||||
}
|
||||
|
||||
class Restart extends Error {}
|
||||
|
||||
function el<K extends keyof HTMLElementTagNameMap>(tag: K, cls = "", text = ""): HTMLElementTagNameMap[K] {
|
||||
const e = document.createElement(tag);
|
||||
if (cls) e.className = cls;
|
||||
if (text) e.textContent = text;
|
||||
return e;
|
||||
}
|
||||
|
||||
function loadJSON<T>(key: string, fallback: T): T {
|
||||
try {
|
||||
const raw = localStorage.getItem(key);
|
||||
return raw ? { ...fallback, ...JSON.parse(raw) } : fallback;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function saveJSON(key: string, value: unknown) {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(value));
|
||||
} catch {
|
||||
/* storage unavailable */
|
||||
}
|
||||
}
|
||||
|
||||
export class Engine {
|
||||
private labels = new Map<string, LabelRef>();
|
||||
private anchors = new Map<string, { label: string; path: number[]; params?: [string, Expr | null][] | null }>();
|
||||
|
||||
Reference in new issue
Block a user