Init
This commit is contained in:
commit
b5f31c1083
227 files changed
+31375
No files matched your search
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'drizzle-kit'
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/schema/index.ts',
|
||||
out: './migrations',
|
||||
dialect: 'sqlite',
|
||||
dbCredentials: {
|
||||
url: process.env.DATABASE_URL?.replace(/^sqlite:/, '') ?? './data/app.db',
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "@telemt/db",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist",
|
||||
"package.json"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format esm --dts",
|
||||
"dev": "tsup src/index.ts --format esm --dts --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^11.10.0",
|
||||
"drizzle-orm": "^0.44.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/node": "^26.1.2",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import Database from 'better-sqlite3'
|
||||
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
||||
import * as schema from './schema/index.js'
|
||||
|
||||
export type Sqlite = Database.Database
|
||||
export type AppDb = ReturnType<typeof drizzle<typeof schema>>
|
||||
|
||||
export * from './schema/index.js'
|
||||
|
||||
export function resolveDatabasePath(databaseUrl: string): string {
|
||||
return databaseUrl.startsWith('sqlite:')
|
||||
? databaseUrl.slice('sqlite:'.length)
|
||||
: databaseUrl
|
||||
}
|
||||
|
||||
export function createDb(databaseUrl: string): { db: AppDb; sqlite: Sqlite } {
|
||||
const path = resolveDatabasePath(databaseUrl)
|
||||
const sqlite = new Database(path)
|
||||
sqlite.pragma('journal_mode = WAL')
|
||||
sqlite.pragma('foreign_keys = ON')
|
||||
sqlite.pragma('synchronous = NORMAL')
|
||||
const db = drizzle(sqlite, { schema })
|
||||
return { db, sqlite }
|
||||
}
|
||||
|
||||
export function healthCheck(sqlite: Sqlite): void {
|
||||
sqlite.prepare('SELECT 1').get()
|
||||
}
|
||||
|
||||
export function migrateSchema(sqlite: Sqlite): void {
|
||||
sqlite.exec(`
|
||||
CREATE TABLE IF NOT EXISTS operators (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'admin',
|
||||
disabled INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agents (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
token_hash TEXT,
|
||||
last_seen_at TEXT,
|
||||
agent_version TEXT,
|
||||
hostname TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS enrollment_tokens (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
token_hash TEXT NOT NULL,
|
||||
label TEXT,
|
||||
expires_at TEXT NOT NULL,
|
||||
used_at TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS jobs (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
agent_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
payload_json TEXT NOT NULL DEFAULT '{}',
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
result_json TEXT,
|
||||
error TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS managed_clients (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
secret TEXT,
|
||||
meta_json TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
actor_id TEXT,
|
||||
actor_username TEXT,
|
||||
summary TEXT NOT NULL,
|
||||
details_json TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_agent ON jobs(agent_id, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_log(created_at);
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
|
||||
|
||||
export const operators = sqliteTable('operators', {
|
||||
id: text('id').primaryKey(),
|
||||
username: text('username').notNull().unique(),
|
||||
passwordHash: text('password_hash').notNull(),
|
||||
role: text('role').notNull().default('admin'),
|
||||
disabled: integer('disabled', { mode: 'boolean' }).notNull().default(false),
|
||||
createdAt: text('created_at').notNull(),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
})
|
||||
|
||||
export const settings = sqliteTable('settings', {
|
||||
key: text('key').primaryKey(),
|
||||
value: text('value').notNull(),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
})
|
||||
|
||||
export const agents = sqliteTable('agents', {
|
||||
id: text('id').primaryKey(),
|
||||
name: text('name').notNull(),
|
||||
status: text('status').notNull().default('pending'),
|
||||
tokenHash: text('token_hash'),
|
||||
lastSeenAt: text('last_seen_at'),
|
||||
agentVersion: text('agent_version'),
|
||||
hostname: text('hostname'),
|
||||
createdAt: text('created_at').notNull(),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
})
|
||||
|
||||
export const enrollmentTokens = sqliteTable('enrollment_tokens', {
|
||||
id: text('id').primaryKey(),
|
||||
tokenHash: text('token_hash').notNull(),
|
||||
label: text('label'),
|
||||
expiresAt: text('expires_at').notNull(),
|
||||
usedAt: text('used_at'),
|
||||
createdAt: text('created_at').notNull(),
|
||||
})
|
||||
|
||||
export const jobs = sqliteTable('jobs', {
|
||||
id: text('id').primaryKey(),
|
||||
agentId: text('agent_id').notNull(),
|
||||
type: text('type').notNull(),
|
||||
payloadJson: text('payload_json').notNull().default('{}'),
|
||||
status: text('status').notNull().default('pending'),
|
||||
resultJson: text('result_json'),
|
||||
error: text('error'),
|
||||
createdAt: text('created_at').notNull(),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
})
|
||||
|
||||
export const managedClients = sqliteTable('managed_clients', {
|
||||
id: text('id').primaryKey(),
|
||||
username: text('username').notNull().unique(),
|
||||
secret: text('secret'),
|
||||
metaJson: text('meta_json').notNull().default('{}'),
|
||||
createdAt: text('created_at').notNull(),
|
||||
updatedAt: text('updated_at').notNull(),
|
||||
})
|
||||
|
||||
export const auditLog = sqliteTable('audit_log', {
|
||||
id: text('id').primaryKey(),
|
||||
action: text('action').notNull(),
|
||||
actorId: text('actor_id'),
|
||||
actorUsername: text('actor_username'),
|
||||
summary: text('summary').notNull(),
|
||||
detailsJson: text('details_json'),
|
||||
createdAt: text('created_at').notNull(),
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"noEmit": false,
|
||||
"declaration": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in new issue
Block a user