Init Commit
quality / commitlint (push) Skipped
CD / update-wiki (push) Failing after 7s
quality / changes (push) Successful in 4s
quality / docker-check (push) Skipped
quality / web (push) Failing after 38s
quality / api (push) Successful in 49s
CD / quality (push) Failing after 1m36s
CD / publish (push) Skipped

This commit is contained in:
Denozordec
2026-09-04 11:48:19 +07:00
commit cb8a79260e
300 changed files with 42404 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
declare const appSettings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
name: "app_settings";
schema: undefined;
columns: {
id: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "id";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: false;
isPrimaryKey: true;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
show_quick_actions: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "show_quick_actions";
tableName: "app_settings";
dataType: "boolean";
columnType: "SQLiteBoolean";
data: boolean;
driverParam: number;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: undefined;
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {}>;
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "created_at";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
updated_at: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "updated_at";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
};
dialect: "sqlite";
}>;
declare const schema: {
appSettings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
name: "app_settings";
schema: undefined;
columns: {
id: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "id";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: false;
isPrimaryKey: true;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
show_quick_actions: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "show_quick_actions";
tableName: "app_settings";
dataType: "boolean";
columnType: "SQLiteBoolean";
data: boolean;
driverParam: number;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: undefined;
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {}>;
created_at: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "created_at";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
updated_at: drizzle_orm_sqlite_core.SQLiteColumn<{
name: "updated_at";
tableName: "app_settings";
dataType: "string";
columnType: "SQLiteText";
data: string;
driverParam: string;
notNull: true;
hasDefault: true;
isPrimaryKey: false;
isAutoincrement: false;
hasRuntimeDefault: false;
enumValues: [string, ...string[]];
baseColumn: never;
identity: undefined;
generated: undefined;
}, {}, {
length: number | undefined;
}>;
};
dialect: "sqlite";
}>;
};
type Sqlite = Database.Database;
type Db = ReturnType<typeof drizzle<typeof schema>>;
declare function resolveDatabasePath(databaseUrl: string): string;
declare function createDb(databaseUrl: string): {
db: Db;
sqlite: Sqlite;
};
declare function createMemoryDb(): {
db: Db;
sqlite: Sqlite;
};
declare function runMigrations(sqlite: Sqlite): void;
declare function healthCheck(sqlite: Sqlite): void;
declare class NotFoundError extends Error {
constructor(message: string);
}
declare class ConflictError extends Error {
constructor(message: string);
}
type AppSettingsDto = {
id: string;
showQuickActions: boolean;
};
type AppSettingsPatch = {
showQuickActions?: boolean;
};
declare function getAppSettings(db: Db): AppSettingsDto;
declare function updateAppSettings(db: Db, patch: AppSettingsPatch): AppSettingsDto;
export { type AppSettingsDto, type AppSettingsPatch, ConflictError, type Db, NotFoundError, type Sqlite, appSettings, createDb, createMemoryDb, getAppSettings, healthCheck, resolveDatabasePath, runMigrations, schema, updateAppSettings };
+120
View File
@@ -0,0 +1,120 @@
// src/schema.ts
import { sql } from "drizzle-orm";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
var appSettings = sqliteTable("app_settings", {
id: text("id").primaryKey(),
show_quick_actions: integer("show_quick_actions", { mode: "boolean" }).notNull().default(true),
created_at: text("created_at").notNull().default(sql`datetime('now')`),
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
});
var schema = {
appSettings
};
// src/client.ts
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { readFileSync, readdirSync } from "fs";
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
var __dirname = dirname(fileURLToPath(import.meta.url));
function resolveDatabasePath(databaseUrl) {
const url = databaseUrl.startsWith("sqlite:") ? databaseUrl.slice("sqlite:".length) : databaseUrl;
return url;
}
function createDb(databaseUrl) {
const path = resolveDatabasePath(databaseUrl);
const sqlite = new Database(path);
sqlite.pragma("journal_mode = WAL");
sqlite.pragma("synchronous = NORMAL");
sqlite.pragma("foreign_keys = ON");
const db = drizzle(sqlite, { schema });
return { db, sqlite };
}
function createMemoryDb() {
const sqlite = new Database(":memory:");
sqlite.pragma("foreign_keys = ON");
const db = drizzle(sqlite, { schema });
return { db, sqlite };
}
function runMigrations(sqlite) {
const migrationsDir = join(__dirname, "..", "migrations");
const files = readdirSync(migrationsDir).filter((f) => f.endsWith(".sql")).sort();
sqlite.exec(
`CREATE TABLE IF NOT EXISTS _migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
)`
);
for (const file of files) {
const applied = sqlite.prepare("SELECT 1 FROM _migrations WHERE name = ?").get(file);
if (applied) continue;
const sql2 = readFileSync(join(migrationsDir, file), "utf-8");
sqlite.exec(sql2);
sqlite.prepare("INSERT INTO _migrations (name) VALUES (?)").run(file);
}
}
function healthCheck(sqlite) {
sqlite.prepare("SELECT 1").get();
}
// src/errors.ts
var NotFoundError = class extends Error {
constructor(message) {
super(message);
this.name = "NotFoundError";
}
};
var ConflictError = class extends Error {
constructor(message) {
super(message);
this.name = "ConflictError";
}
};
// src/settings-repo.ts
import { eq } from "drizzle-orm";
var SETTINGS_ID = "settings-main";
function toDto(row) {
return {
id: row.id,
showQuickActions: row.show_quick_actions == null ? true : Boolean(row.show_quick_actions)
};
}
function ensureRow(db) {
const existing = db.select().from(appSettings).where(eq(appSettings.id, SETTINGS_ID)).get();
if (existing) return existing;
db.insert(appSettings).values({
id: SETTINGS_ID,
show_quick_actions: true
}).run();
return db.select().from(appSettings).where(eq(appSettings.id, SETTINGS_ID)).get();
}
function getAppSettings(db) {
return toDto(ensureRow(db));
}
function updateAppSettings(db, patch) {
ensureRow(db);
const updates = {
updated_at: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
};
if (patch.showQuickActions !== void 0) {
updates.show_quick_actions = patch.showQuickActions;
}
db.update(appSettings).set(updates).where(eq(appSettings.id, SETTINGS_ID)).run();
return getAppSettings(db);
}
export {
ConflictError,
NotFoundError,
appSettings,
createDb,
createMemoryDb,
getAppSettings,
healthCheck,
resolveDatabasePath,
runMigrations,
schema,
updateAppSettings
};
+10
View File
@@ -0,0 +1,10 @@
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/schema.ts",
out: "./drizzle",
dialect: "sqlite",
dbCredentials: {
url: "data/app.db",
},
});
+9
View File
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS app_settings (
id TEXT PRIMARY KEY NOT NULL,
show_quick_actions INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
INSERT OR IGNORE INTO app_settings (id, show_quick_actions)
VALUES ('settings-main', 1);
+35
View File
@@ -0,0 +1,35 @@
{
"name": "@cdnmanager/db",
"version": "0.0.0",
"private": true,
"type": "module",
"files": [
"dist",
"migrations",
"package.json"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"development": "./src/index.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsup src/index.ts --format esm --dts",
"dev": "tsup src/index.ts --format esm --dts --watch",
"db:generate": "drizzle-kit generate",
"db:push": "drizzle-kit push"
},
"dependencies": {
"@cdnmanager/shared": "workspace:*",
"better-sqlite3": "^11.10.0",
"drizzle-orm": "^0.44.2"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"drizzle-kit": "^0.31.1",
"tsup": "^8.5.0",
"typescript": "^5.8.3"
}
}
+38
View File
@@ -0,0 +1,38 @@
import Database from "better-sqlite3";
import { existsSync } from "node:fs";
const path = process.argv[2] ?? "../../data/app.db";
if (!existsSync(path)) {
console.log("missing:", path);
process.exit(1);
}
const db = new Database(path, { readonly: true });
const tables = db
.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
.all()
.map((t) => t.name);
console.log("path:", path);
console.log("tables:", tables.join(", "));
for (const t of [
"domains",
"groups",
"dns_records",
"services",
"_migrations",
]) {
if (!tables.includes(t)) continue;
console.log(t, db.prepare(`SELECT COUNT(*) as c FROM ${t}`).get().c);
}
if (tables.includes("domains")) {
console.log(
"sample:",
db.prepare("SELECT id, zone_name FROM domains LIMIT 5").all(),
);
}
if (tables.includes("_migrations")) {
console.log(
"migrations:",
db.prepare("SELECT name FROM _migrations ORDER BY name").all(),
);
}
+65
View File
@@ -0,0 +1,65 @@
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { readFileSync, readdirSync } from "node:fs";
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import { schema } from "./schema.js";
export type Sqlite = Database.Database;
export type Db = ReturnType<typeof drizzle<typeof schema>>;
const __dirname = dirname(fileURLToPath(import.meta.url));
export function resolveDatabasePath(databaseUrl: string): string {
const url = databaseUrl.startsWith("sqlite:")
? databaseUrl.slice("sqlite:".length)
: databaseUrl;
return url;
}
export function createDb(databaseUrl: string): { db: Db; sqlite: Sqlite } {
const path = resolveDatabasePath(databaseUrl);
const sqlite = new Database(path);
sqlite.pragma("journal_mode = WAL");
sqlite.pragma("synchronous = NORMAL");
sqlite.pragma("foreign_keys = ON");
const db = drizzle(sqlite, { schema });
return { db, sqlite };
}
export function createMemoryDb(): { db: Db; sqlite: Sqlite } {
const sqlite = new Database(":memory:");
sqlite.pragma("foreign_keys = ON");
const db = drizzle(sqlite, { schema });
return { db, sqlite };
}
export function runMigrations(sqlite: Sqlite): void {
const migrationsDir = join(__dirname, "..", "migrations");
const files = readdirSync(migrationsDir)
.filter((f) => f.endsWith(".sql"))
.sort();
sqlite.exec(
`CREATE TABLE IF NOT EXISTS _migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
)`,
);
for (const file of files) {
const applied = sqlite
.prepare("SELECT 1 FROM _migrations WHERE name = ?")
.get(file);
if (applied) continue;
const sql = readFileSync(join(migrationsDir, file), "utf-8");
sqlite.exec(sql);
sqlite.prepare("INSERT INTO _migrations (name) VALUES (?)").run(file);
}
}
export function healthCheck(sqlite: Sqlite): void {
sqlite.prepare("SELECT 1").get();
}
+13
View File
@@ -0,0 +1,13 @@
export class NotFoundError extends Error {
constructor(message: string) {
super(message);
this.name = "NotFoundError";
}
}
export class ConflictError extends Error {
constructor(message: string) {
super(message);
this.name = "ConflictError";
}
}
+4
View File
@@ -0,0 +1,4 @@
export * from "./schema.js";
export * from "./client.js";
export * from "./errors.js";
export * from "./settings-repo.js";
+19
View File
@@ -0,0 +1,19 @@
import { sql } from "drizzle-orm";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const appSettings = sqliteTable("app_settings", {
id: text("id").primaryKey(),
show_quick_actions: integer("show_quick_actions", { mode: "boolean" })
.notNull()
.default(true),
created_at: text("created_at")
.notNull()
.default(sql`datetime('now')`),
updated_at: text("updated_at")
.notNull()
.default(sql`datetime('now')`),
});
export const schema = {
appSettings,
};
+66
View File
@@ -0,0 +1,66 @@
import { eq } from "drizzle-orm";
import type { Db } from "./client.js";
import { appSettings } from "./schema.js";
const SETTINGS_ID = "settings-main";
export type AppSettingsDto = {
id: string;
showQuickActions: boolean;
};
export type AppSettingsPatch = {
showQuickActions?: boolean;
};
function toDto(row: typeof appSettings.$inferSelect): AppSettingsDto {
return {
id: row.id,
showQuickActions:
row.show_quick_actions == null ? true : Boolean(row.show_quick_actions),
};
}
function ensureRow(db: Db): typeof appSettings.$inferSelect {
const existing = db
.select()
.from(appSettings)
.where(eq(appSettings.id, SETTINGS_ID))
.get();
if (existing) return existing;
db.insert(appSettings)
.values({
id: SETTINGS_ID,
show_quick_actions: true,
})
.run();
return db
.select()
.from(appSettings)
.where(eq(appSettings.id, SETTINGS_ID))
.get()!;
}
export function getAppSettings(db: Db): AppSettingsDto {
return toDto(ensureRow(db));
}
export function updateAppSettings(
db: Db,
patch: AppSettingsPatch,
): AppSettingsDto {
ensureRow(db);
const updates: Partial<typeof appSettings.$inferInsert> = {
updated_at: new Date().toISOString().replace("T", " ").slice(0, 19),
};
if (patch.showQuickActions !== undefined) {
updates.show_quick_actions = patch.showQuickActions;
}
db.update(appSettings)
.set(updates)
.where(eq(appSettings.id, SETTINGS_ID))
.run();
return getAppSettings(db);
}
+13
View File
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"declaration": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}