初始提交:DSH 多租户平台(dshs)
This commit is contained in:
commit
43976fea6a
167 files changed
+24456
No files matched your search
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* SQLite backend for {@link DbAdapter}. Wraps the synchronous better-sqlite3
|
||||
* repo in async methods and maps constraint errors onto the shared hierarchy.
|
||||
* Used when `deployMode=local` (no `DSHS_DB_URL`).
|
||||
*
|
||||
* NOTE: better-sqlite3 is synchronous; the `async` here only matches the
|
||||
* interface — the underlying calls still block the event loop. Fine for the
|
||||
* small single-machine local mode this backend targets (see docs/k8s.md §5.1).
|
||||
* @module dshs/db/sqlite
|
||||
*/
|
||||
|
||||
import type { DbAdapter } from './adapter.js'
|
||||
import { openDatabase, type Database } from './connection.js'
|
||||
import { mapSqliteError } from './errors.js'
|
||||
import {
|
||||
audit as auditSync,
|
||||
countAdmins as countAdminsSync,
|
||||
createSession as createSessionSync,
|
||||
createUser as createUserSync,
|
||||
deleteBusinessPlugin as deleteBusinessPluginSync,
|
||||
deleteCredentialKey as deleteCredentialKeySync,
|
||||
deleteInstance as deleteInstanceSync,
|
||||
deleteSession as deleteSessionSync,
|
||||
deleteUser as deleteUserSync,
|
||||
deleteUserInstances as deleteUserInstancesSync,
|
||||
deleteUserSessions as deleteUserSessionsSync,
|
||||
findBusinessPlugin as findBusinessPluginSync,
|
||||
findDomainById as findDomainByIdSync,
|
||||
findDomainByUser as findDomainByUserSync,
|
||||
findInstance as findInstanceSync,
|
||||
findSession as findSessionSync,
|
||||
findSessionWithUser as findSessionWithUserSync,
|
||||
hasActiveSession as hasActiveSessionSync,
|
||||
findUserById as findUserByIdSync,
|
||||
findUserBySlug as findUserBySlugSync,
|
||||
findUserByUsername as findUserByUsernameSync,
|
||||
findUserInstance as findUserInstanceSync,
|
||||
findWorkspaceByPath as findWorkspaceByPathSync,
|
||||
getEnabledCredentialKeyRef as getEnabledCredentialKeyRefSync,
|
||||
getEnabledPluginIds as getEnabledPluginIdsSync,
|
||||
getOrCreateWorkspace as getOrCreateWorkspaceSync,
|
||||
listBusinessPlugins as listBusinessPluginsSync,
|
||||
listCredentialKeys as listCredentialKeysSync,
|
||||
listDomains as listDomainsSync,
|
||||
listInstancesByRole as listInstancesByRoleSync,
|
||||
listPublicUsers as listPublicUsersSync,
|
||||
listUsersWithoutUid as listUsersWithoutUidSync,
|
||||
selectCredentialKey as selectCredentialKeySync,
|
||||
setCredentialKey as setCredentialKeySync,
|
||||
setDomainVerified as setDomainVerifiedSync,
|
||||
setFolderPlugins as setFolderPluginsSync,
|
||||
setInstanceStatus as setInstanceStatusSync,
|
||||
setUserRole as setUserRoleSync,
|
||||
setUserUid as setUserUidSync,
|
||||
upsertBusinessPlugin as upsertBusinessPluginSync,
|
||||
upsertDomain as upsertDomainSync,
|
||||
upsertInstance as upsertInstanceSync,
|
||||
} from './repo.js'
|
||||
import type {
|
||||
BusinessPlugin,
|
||||
CredentialKey,
|
||||
CreateSessionInput,
|
||||
CreateUserInput,
|
||||
Domain,
|
||||
DshInstance,
|
||||
DshInstanceRole,
|
||||
DshInstanceStatus,
|
||||
PublicUser,
|
||||
SessionRow,
|
||||
SessionUser,
|
||||
UpsertBusinessPluginInput,
|
||||
UpsertDshInstanceInput,
|
||||
User,
|
||||
UserRole,
|
||||
Workspace,
|
||||
} from './types.js'
|
||||
|
||||
export class SqliteAdapter implements DbAdapter {
|
||||
private readonly db: Database
|
||||
|
||||
constructor(path: string, private readonly baseUid: number) {
|
||||
this.db = openDatabase(path)
|
||||
}
|
||||
|
||||
async createUser(input: CreateUserInput): Promise<User> {
|
||||
try {
|
||||
return createUserSync(this.db, input, this.baseUid)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async findUserByUsername(username: string): Promise<User | undefined> {
|
||||
return findUserByUsernameSync(this.db, username)
|
||||
}
|
||||
|
||||
async findUserBySlug(slug: string): Promise<User | undefined> {
|
||||
return findUserBySlugSync(this.db, slug)
|
||||
}
|
||||
|
||||
async findUserById(id: string): Promise<User | undefined> {
|
||||
return findUserByIdSync(this.db, id)
|
||||
}
|
||||
|
||||
async listPublicUsers(): Promise<PublicUser[]> {
|
||||
return listPublicUsersSync(this.db)
|
||||
}
|
||||
|
||||
async countAdmins(): Promise<number> {
|
||||
return countAdminsSync(this.db)
|
||||
}
|
||||
|
||||
async setUserRole(id: string, role: UserRole, approvedBy?: string): Promise<boolean> {
|
||||
return setUserRoleSync(this.db, id, role, approvedBy)
|
||||
}
|
||||
|
||||
async setUserUid(userId: string, uid: number): Promise<void> {
|
||||
setUserUidSync(this.db, userId, uid)
|
||||
}
|
||||
|
||||
async listUsersWithoutUid(): Promise<string[]> {
|
||||
return listUsersWithoutUidSync(this.db)
|
||||
}
|
||||
|
||||
async createSession(input: CreateSessionInput): Promise<void> {
|
||||
try {
|
||||
createSessionSync(this.db, input)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async findSession(tokenHash: string): Promise<SessionRow | undefined> {
|
||||
return findSessionSync(this.db, tokenHash)
|
||||
}
|
||||
|
||||
async deleteSession(tokenHash: string): Promise<void> {
|
||||
deleteSessionSync(this.db, tokenHash)
|
||||
}
|
||||
|
||||
async deleteUserSessions(userId: string): Promise<void> {
|
||||
deleteUserSessionsSync(this.db, userId)
|
||||
}
|
||||
|
||||
async findSessionWithUser(tokenHash: string): Promise<SessionUser | undefined> {
|
||||
return findSessionWithUserSync(this.db, tokenHash)
|
||||
}
|
||||
|
||||
async hasActiveSession(userId: string): Promise<boolean> {
|
||||
return hasActiveSessionSync(this.db, userId)
|
||||
}
|
||||
|
||||
async audit(actor: string | null, action: string, detail?: string | null): Promise<void> {
|
||||
auditSync(this.db, actor, action, detail)
|
||||
}
|
||||
|
||||
async findWorkspaceByPath(userId: string, relPath: string): Promise<Workspace | undefined> {
|
||||
return findWorkspaceByPathSync(this.db, userId, relPath)
|
||||
}
|
||||
|
||||
async getOrCreateWorkspace(userId: string, relPath: string): Promise<Workspace> {
|
||||
try {
|
||||
return getOrCreateWorkspaceSync(this.db, userId, relPath)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async setFolderPlugins(
|
||||
workspaceId: string,
|
||||
selections: ReadonlyArray<{ id: string; enabled: boolean }>,
|
||||
): Promise<void> {
|
||||
try {
|
||||
setFolderPluginsSync(this.db, workspaceId, selections)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async getEnabledPluginIds(workspaceId: string): Promise<string[]> {
|
||||
return getEnabledPluginIdsSync(this.db, workspaceId)
|
||||
}
|
||||
|
||||
async listBusinessPlugins(): Promise<BusinessPlugin[]> {
|
||||
return listBusinessPluginsSync(this.db)
|
||||
}
|
||||
|
||||
async findBusinessPlugin(id: string): Promise<BusinessPlugin | undefined> {
|
||||
return findBusinessPluginSync(this.db, id)
|
||||
}
|
||||
|
||||
async upsertBusinessPlugin(input: UpsertBusinessPluginInput): Promise<BusinessPlugin> {
|
||||
try {
|
||||
return upsertBusinessPluginSync(this.db, input)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async deleteBusinessPlugin(id: string): Promise<boolean> {
|
||||
return deleteBusinessPluginSync(this.db, id)
|
||||
}
|
||||
|
||||
async findDomainByUser(userId: string): Promise<Domain | undefined> {
|
||||
return findDomainByUserSync(this.db, userId)
|
||||
}
|
||||
|
||||
async findDomainById(id: string): Promise<Domain | undefined> {
|
||||
return findDomainByIdSync(this.db, id)
|
||||
}
|
||||
|
||||
async listDomains(): Promise<Domain[]> {
|
||||
return listDomainsSync(this.db)
|
||||
}
|
||||
|
||||
async upsertDomain(userId: string, domain: string, nginxConfig: string): Promise<Domain> {
|
||||
try {
|
||||
return upsertDomainSync(this.db, userId, domain, nginxConfig)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async setDomainVerified(id: string, verified: boolean): Promise<boolean> {
|
||||
return setDomainVerifiedSync(this.db, id, verified)
|
||||
}
|
||||
|
||||
async listCredentialKeys(userId: string): Promise<CredentialKey[]> {
|
||||
return listCredentialKeysSync(this.db, userId)
|
||||
}
|
||||
|
||||
async getEnabledCredentialKeyRef(userId: string): Promise<string | null> {
|
||||
return getEnabledCredentialKeyRefSync(this.db, userId)
|
||||
}
|
||||
|
||||
async setCredentialKey(userId: string, name: string, encryptedRef: string): Promise<CredentialKey> {
|
||||
try {
|
||||
return setCredentialKeySync(this.db, userId, name, encryptedRef)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async selectCredentialKey(userId: string, id: string): Promise<boolean> {
|
||||
return selectCredentialKeySync(this.db, userId, id)
|
||||
}
|
||||
|
||||
async deleteCredentialKey(userId: string, id: string): Promise<boolean> {
|
||||
return deleteCredentialKeySync(this.db, userId, id)
|
||||
}
|
||||
|
||||
async deleteUser(userId: string): Promise<boolean> {
|
||||
return deleteUserSync(this.db, userId)
|
||||
}
|
||||
|
||||
async upsertInstance(input: UpsertDshInstanceInput): Promise<void> {
|
||||
try {
|
||||
upsertInstanceSync(this.db, input)
|
||||
} catch (e) {
|
||||
mapSqliteError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async findInstance(id: string): Promise<DshInstance | undefined> {
|
||||
return findInstanceSync(this.db, id)
|
||||
}
|
||||
|
||||
async findUserInstance(userId: string, role: DshInstanceRole): Promise<DshInstance | undefined> {
|
||||
return findUserInstanceSync(this.db, userId, role)
|
||||
}
|
||||
|
||||
async listInstancesByRole(role: DshInstanceRole): Promise<DshInstance[]> {
|
||||
return listInstancesByRoleSync(this.db, role)
|
||||
}
|
||||
|
||||
async setInstanceStatus(
|
||||
id: string,
|
||||
status: DshInstanceStatus,
|
||||
outcome?: { exitCode?: number; lastError?: string },
|
||||
): Promise<boolean> {
|
||||
return setInstanceStatusSync(this.db, id, status, outcome)
|
||||
}
|
||||
|
||||
async deleteInstance(id: string): Promise<boolean> {
|
||||
return deleteInstanceSync(this.db, id)
|
||||
}
|
||||
|
||||
async deleteUserInstances(userId: string): Promise<void> {
|
||||
deleteUserInstancesSync(this.db, userId)
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this.db.close()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user