feat: add fluxer upstream source and self-hosting documentation
- Clone of github.com/fluxerapp/fluxer (official upstream) - SELF_HOSTING.md: full VM rebuild procedure, architecture overview, service reference, step-by-step setup, troubleshooting, seattle reference - dev/.env.example: all env vars with secrets redacted and generation instructions - dev/livekit.yaml: LiveKit config template with placeholder keys - fluxer-seattle/: existing seattle deployment setup scripts
This commit is contained in:
1943
fluxer/packages/api/src/database/Cassandra.tsx
Normal file
1943
fluxer/packages/api/src/database/Cassandra.tsx
Normal file
File diff suppressed because it is too large
Load Diff
457
fluxer/packages/api/src/database/SqliteKV.tsx
Normal file
457
fluxer/packages/api/src/database/SqliteKV.tsx
Normal file
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {mkdirSync} from 'node:fs';
|
||||
import {dirname} from 'node:path';
|
||||
import {DatabaseSync, type StatementSync} from 'node:sqlite';
|
||||
import {Config} from '@fluxer/api/src/Config';
|
||||
import {Logger} from '@fluxer/api/src/Logger';
|
||||
|
||||
export interface KvEntry<T = Record<string, unknown>> {
|
||||
key: string;
|
||||
table: string;
|
||||
value: T;
|
||||
expiresAt: number | null;
|
||||
}
|
||||
|
||||
interface SqliteExecutor {
|
||||
exec(sql: string): void;
|
||||
}
|
||||
|
||||
export function executeSqliteTransaction<T>(db: SqliteExecutor, fn: () => T): T {
|
||||
db.exec('BEGIN');
|
||||
try {
|
||||
const result = fn();
|
||||
db.exec('COMMIT');
|
||||
return result;
|
||||
} catch (error) {
|
||||
try {
|
||||
db.exec('ROLLBACK');
|
||||
} catch {}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function upperBound(prefix: string): string {
|
||||
return `${prefix}\u{10FFFF}`;
|
||||
}
|
||||
|
||||
const FLUXER_TAG = '__fluxer__' as const;
|
||||
const FLUXER_TAG_VERSION = 1 as const;
|
||||
|
||||
type FluxerTagType = 'bigint' | 'date' | 'set' | 'map' | 'buffer' | 'uint8array';
|
||||
|
||||
type FluxerTagged =
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'bigint'; d: string}}
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'date'; d: string}}
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'set'; d: Array<unknown>}}
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'map'; d: Array<[unknown, unknown]>}}
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'buffer'; d: string}}
|
||||
| {[FLUXER_TAG]: {v: typeof FLUXER_TAG_VERSION; t: 'uint8array'; d: string}};
|
||||
|
||||
class FluxerSerialisationError extends Error {
|
||||
override name = 'FluxerSerialisationError';
|
||||
}
|
||||
|
||||
class FluxerDeserialisationError extends Error {
|
||||
override name = 'FluxerDeserialisationError';
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
if (value === null || typeof value !== 'object') return false;
|
||||
const proto = Object.getPrototypeOf(value);
|
||||
return proto === Object.prototype || proto === null;
|
||||
}
|
||||
|
||||
function tag<T extends FluxerTagged[typeof FLUXER_TAG]['t']>(
|
||||
t: T,
|
||||
d: Extract<FluxerTagged, {[FLUXER_TAG]: {t: T}}>['__fluxer__']['d'],
|
||||
): Extract<FluxerTagged, {[FLUXER_TAG]: {t: T}}> {
|
||||
return {[FLUXER_TAG]: {v: FLUXER_TAG_VERSION, t, d}} as Extract<FluxerTagged, {[FLUXER_TAG]: {t: T}}>;
|
||||
}
|
||||
|
||||
function isKnownTagType(t: unknown): t is FluxerTagType {
|
||||
return t === 'bigint' || t === 'date' || t === 'set' || t === 'map' || t === 'buffer' || t === 'uint8array';
|
||||
}
|
||||
|
||||
function assertNever(_x: never, msg: string): never {
|
||||
throw new FluxerDeserialisationError(msg);
|
||||
}
|
||||
|
||||
function fluxerReplacer(this: unknown, key: string, value: unknown): unknown {
|
||||
const holder = this as Record<string, unknown> | null;
|
||||
const original = key === '' ? value : holder?.[key];
|
||||
|
||||
if (typeof original === 'bigint') {
|
||||
return tag('bigint', original.toString());
|
||||
}
|
||||
|
||||
if (original instanceof Date) {
|
||||
return tag('date', original.toISOString());
|
||||
}
|
||||
|
||||
if (original instanceof Set) {
|
||||
return tag('set', Array.from(original));
|
||||
}
|
||||
|
||||
if (original instanceof Map) {
|
||||
return tag('map', Array.from(original.entries()));
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(original)) {
|
||||
return tag('buffer', original.toString('base64'));
|
||||
}
|
||||
|
||||
if (original instanceof Uint8Array && !Buffer.isBuffer(original)) {
|
||||
return tag('uint8array', Buffer.from(original).toString('base64'));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function decodeTagged(meta: unknown): unknown {
|
||||
if (!isPlainObject(meta)) {
|
||||
throw new FluxerDeserialisationError('Malformed __fluxer__ tag: meta is not an object');
|
||||
}
|
||||
|
||||
const v = meta['v'];
|
||||
const t = meta['t'];
|
||||
const d = meta['d'];
|
||||
|
||||
if (v !== FLUXER_TAG_VERSION) {
|
||||
throw new FluxerDeserialisationError(
|
||||
`Unsupported __fluxer__ tag version: ${String(v)} (expected ${String(FLUXER_TAG_VERSION)})`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isKnownTagType(t)) {
|
||||
throw new FluxerDeserialisationError(`Unknown __fluxer__ tag type: ${String(t)}`);
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
case 'bigint': {
|
||||
if (typeof d !== 'string') throw new FluxerDeserialisationError('Malformed bigint tag: d must be a string');
|
||||
try {
|
||||
return BigInt(d);
|
||||
} catch (_e) {
|
||||
throw new FluxerDeserialisationError(`Invalid bigint payload: ${String(d)}`);
|
||||
}
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
if (typeof d !== 'string') throw new FluxerDeserialisationError('Malformed date tag: d must be a string');
|
||||
const dt = new Date(d);
|
||||
if (Number.isNaN(dt.getTime())) {
|
||||
throw new FluxerDeserialisationError(`Invalid date payload: ${String(d)}`);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
case 'set': {
|
||||
if (!Array.isArray(d)) throw new FluxerDeserialisationError('Malformed set tag: d must be an array');
|
||||
return new Set(d);
|
||||
}
|
||||
|
||||
case 'map': {
|
||||
if (!Array.isArray(d)) throw new FluxerDeserialisationError('Malformed map tag: d must be an array');
|
||||
for (const entry of d) {
|
||||
if (!Array.isArray(entry) || entry.length !== 2) {
|
||||
throw new FluxerDeserialisationError('Malformed map tag: every entry must be a [k, v] tuple');
|
||||
}
|
||||
}
|
||||
return new Map(d as Array<[unknown, unknown]>);
|
||||
}
|
||||
|
||||
case 'buffer': {
|
||||
if (typeof d !== 'string') throw new FluxerDeserialisationError('Malformed buffer tag: d must be a string');
|
||||
try {
|
||||
return Buffer.from(d, 'base64');
|
||||
} catch {
|
||||
throw new FluxerDeserialisationError('Invalid buffer payload: base64 decode failed');
|
||||
}
|
||||
}
|
||||
|
||||
case 'uint8array': {
|
||||
if (typeof d !== 'string') throw new FluxerDeserialisationError('Malformed uint8array tag: d must be a string');
|
||||
let buf: Buffer;
|
||||
try {
|
||||
buf = Buffer.from(d, 'base64');
|
||||
} catch {
|
||||
throw new FluxerDeserialisationError('Invalid uint8array payload: base64 decode failed');
|
||||
}
|
||||
return new Uint8Array(buf);
|
||||
}
|
||||
|
||||
default:
|
||||
return assertNever(t, `Unhandled __fluxer__ tag type: ${String(t)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function fluxerReviver(_key: string, value: unknown): unknown {
|
||||
if (isPlainObject(value)) {
|
||||
const keys = Object.keys(value);
|
||||
|
||||
if (keys.length === 1 && keys[0] === FLUXER_TAG) {
|
||||
const meta = (value as Record<string, unknown>)[FLUXER_TAG];
|
||||
return decodeTagged(meta);
|
||||
}
|
||||
|
||||
if (value['type'] === 'Buffer') {
|
||||
const data = (value as Record<string, unknown>)['data'];
|
||||
if (!Array.isArray(data)) throw new FluxerDeserialisationError('Malformed Buffer JSON: data must be an array');
|
||||
|
||||
for (const n of data) {
|
||||
if (typeof n !== 'number' || !Number.isInteger(n) || n < 0 || n > 255) {
|
||||
throw new FluxerDeserialisationError('Malformed Buffer JSON: data must be byte integers 0..255');
|
||||
}
|
||||
}
|
||||
|
||||
return Buffer.from(data as Array<number>);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function serialize(value: unknown): Buffer {
|
||||
try {
|
||||
const json = JSON.stringify(value, fluxerReplacer);
|
||||
if (json === undefined) {
|
||||
throw new FluxerSerialisationError('Value is not JSON serialisable');
|
||||
}
|
||||
return Buffer.from(json, 'utf8');
|
||||
} catch (e) {
|
||||
if (e instanceof FluxerSerialisationError) throw e;
|
||||
throw new FluxerSerialisationError(`Failed to serialise value: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function deserialize<T>(blob: Buffer | Uint8Array | string): T {
|
||||
const text =
|
||||
typeof blob === 'string'
|
||||
? blob
|
||||
: Buffer.isBuffer(blob)
|
||||
? blob.toString('utf8')
|
||||
: Buffer.from(blob).toString('utf8');
|
||||
|
||||
try {
|
||||
return JSON.parse(text, fluxerReviver) as T;
|
||||
} catch (e) {
|
||||
if (e instanceof FluxerDeserialisationError) throw e;
|
||||
throw new FluxerDeserialisationError(`Failed to deserialise value: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
}
|
||||
|
||||
type KvRow = {
|
||||
key: string;
|
||||
value: Uint8Array | Buffer | string;
|
||||
expires_at: number | null;
|
||||
};
|
||||
|
||||
class SqliteKvStore {
|
||||
private db: DatabaseSync;
|
||||
|
||||
private purgeExpiredStmt: StatementSync;
|
||||
private putStmt: StatementSync;
|
||||
private getStmt: StatementSync;
|
||||
private deleteStmt: StatementSync;
|
||||
private deletePrefixStmt: StatementSync;
|
||||
private scanPrefixStmt: StatementSync;
|
||||
private scanAllStmt: StatementSync;
|
||||
|
||||
constructor(path: string) {
|
||||
this.db = new DatabaseSync(path);
|
||||
|
||||
this.db.exec(`
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = NORMAL;
|
||||
PRAGMA busy_timeout = 5000;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS kv_store (
|
||||
table_name TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value BLOB NOT NULL,
|
||||
expires_at INTEGER,
|
||||
PRIMARY KEY(table_name, key)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS kv_store_expires_idx ON kv_store(expires_at);
|
||||
`);
|
||||
|
||||
this.purgeExpiredStmt = this.db.prepare(`DELETE FROM kv_store WHERE expires_at IS NOT NULL AND expires_at <= ?;`);
|
||||
|
||||
this.putStmt = this.db.prepare(`
|
||||
INSERT INTO kv_store (table_name, key, value, expires_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(table_name, key) DO UPDATE SET
|
||||
value = excluded.value,
|
||||
expires_at = excluded.expires_at;
|
||||
`);
|
||||
|
||||
this.getStmt = this.db.prepare(`SELECT value, expires_at FROM kv_store WHERE table_name = ? AND key = ?;`);
|
||||
this.deleteStmt = this.db.prepare(`DELETE FROM kv_store WHERE table_name = ? AND key = ?;`);
|
||||
this.deletePrefixStmt = this.db.prepare(`DELETE FROM kv_store WHERE table_name = ? AND key >= ? AND key < ?;`);
|
||||
|
||||
this.scanPrefixStmt = this.db.prepare(`
|
||||
SELECT key, value, expires_at
|
||||
FROM kv_store
|
||||
WHERE table_name = ? AND key >= ? AND key < ?
|
||||
ORDER BY key ASC;
|
||||
`);
|
||||
|
||||
this.scanAllStmt = this.db.prepare(`
|
||||
SELECT key, value, expires_at
|
||||
FROM kv_store
|
||||
WHERE table_name = ?
|
||||
ORDER BY key ASC;
|
||||
`);
|
||||
}
|
||||
|
||||
private purgeExpired(now: number): void {
|
||||
this.purgeExpiredStmt.run(now);
|
||||
}
|
||||
|
||||
private runInTransaction<T>(fn: () => T): T {
|
||||
return executeSqliteTransaction(this.db, fn);
|
||||
}
|
||||
|
||||
put(table: string, key: string, value: unknown, ttlSeconds?: number): void {
|
||||
let expiresAt: number | null = null;
|
||||
|
||||
if (ttlSeconds !== undefined) {
|
||||
if (!Number.isFinite(ttlSeconds)) throw new TypeError('ttlSeconds must be a finite number');
|
||||
|
||||
if (ttlSeconds <= 0) {
|
||||
expiresAt = Date.now();
|
||||
} else {
|
||||
const ms = ttlSeconds * 1000;
|
||||
const now = Date.now();
|
||||
const sum = now + ms;
|
||||
expiresAt = Number.isSafeInteger(sum) ? sum : Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
}
|
||||
|
||||
this.putStmt.run(table, key, serialize(value), expiresAt);
|
||||
}
|
||||
|
||||
get<T>(table: string, key: string): T | null {
|
||||
const row = this.getStmt.get(table, key) as
|
||||
| {value: Uint8Array | Buffer | string; expires_at: number | null}
|
||||
| undefined;
|
||||
|
||||
if (!row) return null;
|
||||
|
||||
const now = Date.now();
|
||||
if (row.expires_at !== null && row.expires_at <= now) {
|
||||
this.delete(table, key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return deserialize<T>(row.value);
|
||||
}
|
||||
|
||||
delete(table: string, key: string): void {
|
||||
this.deleteStmt.run(table, key);
|
||||
}
|
||||
|
||||
deletePrefix(table: string, prefix: string): void {
|
||||
this.deletePrefixStmt.run(table, prefix, upperBound(prefix));
|
||||
}
|
||||
|
||||
scan<T>(table: string, prefix?: string): Array<KvEntry<T>> {
|
||||
const now = Date.now();
|
||||
|
||||
return this.runInTransaction(() => {
|
||||
this.purgeExpired(now);
|
||||
|
||||
const rows: Array<KvRow> = prefix
|
||||
? (this.scanPrefixStmt.all(table, prefix, upperBound(prefix)) as Array<KvRow>)
|
||||
: (this.scanAllStmt.all(table) as Array<KvRow>);
|
||||
|
||||
const out: Array<KvEntry<T>> = [];
|
||||
|
||||
for (const row of rows) {
|
||||
if (row.expires_at !== null && row.expires_at <= now) continue;
|
||||
|
||||
out.push({
|
||||
key: row.key,
|
||||
table,
|
||||
value: deserialize<T>(row.value),
|
||||
expiresAt: row.expires_at,
|
||||
});
|
||||
}
|
||||
|
||||
return out;
|
||||
});
|
||||
}
|
||||
|
||||
clearAll(): void {
|
||||
executeSqliteTransaction(this.db, () => {
|
||||
this.db.exec('DELETE FROM kv_store;');
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
getDatabase(): DatabaseSync {
|
||||
return this.db;
|
||||
}
|
||||
}
|
||||
|
||||
let kvStore: SqliteKvStore | null = null;
|
||||
|
||||
export function getKvStore(): SqliteKvStore {
|
||||
if (!kvStore) {
|
||||
const path = Config.database?.sqlitePath ?? ':memory:';
|
||||
|
||||
if (path !== ':memory:') {
|
||||
mkdirSync(dirname(path), {recursive: true});
|
||||
}
|
||||
|
||||
Logger.info({path}, 'Initialising SQLite KV backend');
|
||||
kvStore = new SqliteKvStore(path);
|
||||
}
|
||||
|
||||
return kvStore;
|
||||
}
|
||||
|
||||
export function clearSqliteStore(): void {
|
||||
const store = getKvStore();
|
||||
store.clearAll();
|
||||
}
|
||||
|
||||
function encodeKeyPart(part: unknown): string {
|
||||
if (part === null) return encodeURIComponent('null');
|
||||
if (part === undefined) return encodeURIComponent('undefined');
|
||||
|
||||
switch (typeof part) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
case 'bigint':
|
||||
return encodeURIComponent(String(part));
|
||||
default: {
|
||||
const normalised = part instanceof Uint8Array && !(part instanceof Buffer) ? Buffer.from(part) : part;
|
||||
return encodeURIComponent(serialize(normalised).toString('utf8'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeKey(parts: ReadonlyArray<unknown>): string {
|
||||
return parts.map(encodeKeyPart).join('|');
|
||||
}
|
||||
94
fluxer/packages/api/src/database/types/AdminArchiveTypes.tsx
Normal file
94
fluxer/packages/api/src/database/types/AdminArchiveTypes.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface AdminArchiveRow {
|
||||
subject_type: 'user' | 'guild';
|
||||
subject_id: bigint;
|
||||
archive_id: bigint;
|
||||
requested_by: bigint;
|
||||
requested_at: Date;
|
||||
started_at: Date | null;
|
||||
completed_at: Date | null;
|
||||
failed_at: Date | null;
|
||||
storage_key: string | null;
|
||||
file_size: bigint | null;
|
||||
progress_percent: number;
|
||||
progress_step: string | null;
|
||||
error_message: string | null;
|
||||
download_url_expires_at: Date | null;
|
||||
expires_at: Date | null;
|
||||
}
|
||||
|
||||
export const ADMIN_ARCHIVE_COLUMNS = [
|
||||
'subject_type',
|
||||
'subject_id',
|
||||
'archive_id',
|
||||
'requested_by',
|
||||
'requested_at',
|
||||
'started_at',
|
||||
'completed_at',
|
||||
'failed_at',
|
||||
'storage_key',
|
||||
'file_size',
|
||||
'progress_percent',
|
||||
'progress_step',
|
||||
'error_message',
|
||||
'download_url_expires_at',
|
||||
'expires_at',
|
||||
] as const satisfies ReadonlyArray<keyof AdminArchiveRow>;
|
||||
|
||||
export interface AdminAuditLogRow {
|
||||
log_id: bigint;
|
||||
admin_user_id: bigint;
|
||||
target_type: string;
|
||||
target_id: bigint;
|
||||
action: string;
|
||||
audit_log_reason: string | null;
|
||||
metadata: Map<string, string>;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export const ADMIN_AUDIT_LOG_COLUMNS = [
|
||||
'log_id',
|
||||
'admin_user_id',
|
||||
'target_type',
|
||||
'target_id',
|
||||
'action',
|
||||
'audit_log_reason',
|
||||
'metadata',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof AdminAuditLogRow>;
|
||||
|
||||
export interface BannedIpRow {
|
||||
ip: string;
|
||||
}
|
||||
|
||||
export const BANNED_IP_COLUMNS = ['ip'] as const satisfies ReadonlyArray<keyof BannedIpRow>;
|
||||
|
||||
export interface BannedEmailRow {
|
||||
email_lower: string;
|
||||
}
|
||||
|
||||
export const BANNED_EMAIL_COLUMNS = ['email_lower'] as const satisfies ReadonlyArray<keyof BannedEmailRow>;
|
||||
|
||||
export interface BannedPhoneRow {
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export const BANNED_PHONE_COLUMNS = ['phone'] as const satisfies ReadonlyArray<keyof BannedPhoneRow>;
|
||||
68
fluxer/packages/api/src/database/types/AdminAuthTypes.tsx
Normal file
68
fluxer/packages/api/src/database/types/AdminAuthTypes.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface AdminApiKeyRow {
|
||||
key_id: bigint;
|
||||
key_hash: string;
|
||||
name: string;
|
||||
created_by_user_id: UserID;
|
||||
created_at: Date;
|
||||
last_used_at: Nullish<Date>;
|
||||
expires_at: Nullish<Date>;
|
||||
version: number;
|
||||
acls: Nullish<Set<string>>;
|
||||
}
|
||||
|
||||
export interface AdminApiKeyByCreatorRow {
|
||||
created_by_user_id: UserID;
|
||||
key_id: bigint;
|
||||
created_at: Date;
|
||||
name: string;
|
||||
expires_at: Nullish<Date>;
|
||||
last_used_at: Nullish<Date>;
|
||||
version: number;
|
||||
acls: Nullish<Set<string>>;
|
||||
}
|
||||
|
||||
export const ADMIN_API_KEY_COLUMNS = [
|
||||
'key_id',
|
||||
'key_hash',
|
||||
'name',
|
||||
'created_by_user_id',
|
||||
'created_at',
|
||||
'last_used_at',
|
||||
'expires_at',
|
||||
'version',
|
||||
'acls',
|
||||
] as const satisfies ReadonlyArray<keyof AdminApiKeyRow>;
|
||||
|
||||
export const ADMIN_API_KEY_BY_CREATOR_COLUMNS = [
|
||||
'created_by_user_id',
|
||||
'key_id',
|
||||
'created_at',
|
||||
'name',
|
||||
'expires_at',
|
||||
'last_used_at',
|
||||
'version',
|
||||
'acls',
|
||||
] as const satisfies ReadonlyArray<keyof AdminApiKeyByCreatorRow>;
|
||||
224
fluxer/packages/api/src/database/types/AuthTypes.tsx
Normal file
224
fluxer/packages/api/src/database/types/AuthTypes.tsx
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
EmailRevertToken,
|
||||
EmailVerificationToken,
|
||||
IpAuthorizationToken,
|
||||
MfaBackupCode,
|
||||
PasswordResetToken,
|
||||
UserID,
|
||||
} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface AuthSessionRow {
|
||||
user_id: UserID;
|
||||
session_id_hash: Buffer;
|
||||
created_at: Date;
|
||||
approx_last_used_at: Date;
|
||||
client_ip: string;
|
||||
client_user_agent: Nullish<string>;
|
||||
client_is_desktop: Nullish<boolean>;
|
||||
client_os?: Nullish<string>;
|
||||
client_platform?: Nullish<string>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface MfaBackupCodeRow {
|
||||
user_id: UserID;
|
||||
code: MfaBackupCode;
|
||||
consumed: boolean;
|
||||
}
|
||||
|
||||
export interface EmailVerificationTokenRow {
|
||||
token_: EmailVerificationToken;
|
||||
user_id: UserID;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface PasswordResetTokenRow {
|
||||
token_: PasswordResetToken;
|
||||
user_id: UserID;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface EmailRevertTokenRow {
|
||||
token_: EmailRevertToken;
|
||||
user_id: UserID;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface IpAuthorizationTokenRow {
|
||||
token_: IpAuthorizationToken;
|
||||
user_id: UserID;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface AuthorizedIpRow {
|
||||
user_id: UserID;
|
||||
ip: string;
|
||||
}
|
||||
|
||||
export interface WebAuthnCredentialRow {
|
||||
user_id: UserID;
|
||||
credential_id: string;
|
||||
public_key: Buffer;
|
||||
counter: bigint;
|
||||
transports: Nullish<Set<string>>;
|
||||
name: string;
|
||||
created_at: Date;
|
||||
last_used_at: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface PhoneTokenRow {
|
||||
token_: string;
|
||||
phone: string;
|
||||
user_id: Nullish<UserID>;
|
||||
}
|
||||
|
||||
export interface EmailChangeTicketRow {
|
||||
ticket: string;
|
||||
user_id: UserID;
|
||||
require_original: boolean;
|
||||
original_email: Nullish<string>;
|
||||
original_verified: boolean;
|
||||
original_proof: Nullish<string>;
|
||||
original_code: Nullish<string>;
|
||||
original_code_sent_at: Nullish<Date>;
|
||||
original_code_expires_at: Nullish<Date>;
|
||||
new_email: Nullish<string>;
|
||||
new_code: Nullish<string>;
|
||||
new_code_sent_at: Nullish<Date>;
|
||||
new_code_expires_at: Nullish<Date>;
|
||||
status: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface EmailChangeTokenRow {
|
||||
token_: string;
|
||||
user_id: UserID;
|
||||
new_email: string;
|
||||
expires_at: Date;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export const AUTH_SESSION_COLUMNS = [
|
||||
'user_id',
|
||||
'session_id_hash',
|
||||
'created_at',
|
||||
'approx_last_used_at',
|
||||
'client_ip',
|
||||
'client_user_agent',
|
||||
'client_is_desktop',
|
||||
'client_os',
|
||||
'client_platform',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof AuthSessionRow>;
|
||||
|
||||
export const MFA_BACKUP_CODE_COLUMNS = ['user_id', 'code', 'consumed'] as const satisfies ReadonlyArray<
|
||||
keyof MfaBackupCodeRow
|
||||
>;
|
||||
|
||||
export const EMAIL_VERIFICATION_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
|
||||
keyof EmailVerificationTokenRow
|
||||
>;
|
||||
|
||||
export const PASSWORD_RESET_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
|
||||
keyof PasswordResetTokenRow
|
||||
>;
|
||||
|
||||
export const EMAIL_REVERT_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
|
||||
keyof EmailRevertTokenRow
|
||||
>;
|
||||
|
||||
export const IP_AUTHORIZATION_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
|
||||
keyof IpAuthorizationTokenRow
|
||||
>;
|
||||
|
||||
export const AUTHORIZED_IP_COLUMNS = ['user_id', 'ip'] as const satisfies ReadonlyArray<keyof AuthorizedIpRow>;
|
||||
|
||||
export const WEBAUTHN_CREDENTIAL_COLUMNS = [
|
||||
'user_id',
|
||||
'credential_id',
|
||||
'public_key',
|
||||
'counter',
|
||||
'transports',
|
||||
'name',
|
||||
'created_at',
|
||||
'last_used_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof WebAuthnCredentialRow>;
|
||||
|
||||
export const PHONE_TOKEN_COLUMNS = ['token_', 'phone', 'user_id'] as const satisfies ReadonlyArray<keyof PhoneTokenRow>;
|
||||
|
||||
export interface PasswordChangeTicketRow {
|
||||
ticket: string;
|
||||
user_id: UserID;
|
||||
code: Nullish<string>;
|
||||
code_sent_at: Nullish<Date>;
|
||||
code_expires_at: Nullish<Date>;
|
||||
verified: boolean;
|
||||
verification_proof: Nullish<string>;
|
||||
status: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export const PASSWORD_CHANGE_TICKET_COLUMNS = [
|
||||
'ticket',
|
||||
'user_id',
|
||||
'code',
|
||||
'code_sent_at',
|
||||
'code_expires_at',
|
||||
'verified',
|
||||
'verification_proof',
|
||||
'status',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof PasswordChangeTicketRow>;
|
||||
|
||||
export const EMAIL_CHANGE_TICKET_COLUMNS = [
|
||||
'ticket',
|
||||
'user_id',
|
||||
'require_original',
|
||||
'original_email',
|
||||
'original_verified',
|
||||
'original_proof',
|
||||
'original_code',
|
||||
'original_code_sent_at',
|
||||
'original_code_expires_at',
|
||||
'new_email',
|
||||
'new_code',
|
||||
'new_code_sent_at',
|
||||
'new_code_expires_at',
|
||||
'status',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof EmailChangeTicketRow>;
|
||||
|
||||
export const EMAIL_CHANGE_TOKEN_COLUMNS = [
|
||||
'token_',
|
||||
'user_id',
|
||||
'new_email',
|
||||
'expires_at',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof EmailChangeTokenRow>;
|
||||
186
fluxer/packages/api/src/database/types/ChannelTypes.tsx
Normal file
186
fluxer/packages/api/src/database/types/ChannelTypes.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
ChannelID,
|
||||
GuildID,
|
||||
InviteCode,
|
||||
MessageID,
|
||||
RoleID,
|
||||
UserID,
|
||||
WebhookID,
|
||||
WebhookToken,
|
||||
} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface PermissionOverwrite {
|
||||
type: number;
|
||||
allow_: Nullish<bigint>;
|
||||
deny_: Nullish<bigint>;
|
||||
}
|
||||
|
||||
export interface ChannelRow {
|
||||
channel_id: ChannelID;
|
||||
guild_id: Nullish<GuildID>;
|
||||
type: number;
|
||||
name: Nullish<string>;
|
||||
topic: Nullish<string>;
|
||||
icon_hash: Nullish<string>;
|
||||
url: Nullish<string>;
|
||||
parent_id: Nullish<ChannelID>;
|
||||
position: Nullish<number>;
|
||||
owner_id: Nullish<UserID>;
|
||||
recipient_ids: Nullish<Set<UserID>>;
|
||||
nsfw: Nullish<boolean>;
|
||||
rate_limit_per_user: Nullish<number>;
|
||||
bitrate: Nullish<number>;
|
||||
user_limit: Nullish<number>;
|
||||
rtc_region: Nullish<string>;
|
||||
last_message_id: Nullish<MessageID>;
|
||||
last_pin_timestamp: Nullish<Date>;
|
||||
permission_overwrites: Nullish<Map<RoleID | UserID, PermissionOverwrite>>;
|
||||
nicks: Nullish<Map<string, string>>;
|
||||
soft_deleted: boolean;
|
||||
indexed_at: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface InviteRow {
|
||||
code: InviteCode;
|
||||
type: number;
|
||||
guild_id: Nullish<GuildID>;
|
||||
channel_id: Nullish<ChannelID>;
|
||||
inviter_id: Nullish<UserID>;
|
||||
created_at: Date;
|
||||
uses: number;
|
||||
max_uses: number;
|
||||
max_age: number;
|
||||
temporary: Nullish<boolean>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface WebhookRow {
|
||||
webhook_id: WebhookID;
|
||||
webhook_token: WebhookToken;
|
||||
type: number;
|
||||
guild_id: Nullish<GuildID>;
|
||||
channel_id: Nullish<ChannelID>;
|
||||
creator_id: Nullish<UserID>;
|
||||
name: string;
|
||||
avatar_hash: Nullish<string>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface PrivateChannelRow {
|
||||
user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
is_gdm: boolean;
|
||||
}
|
||||
|
||||
export interface DmStateRow {
|
||||
hi_user_id: UserID;
|
||||
lo_user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
}
|
||||
|
||||
export interface ReadStateRow {
|
||||
user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
message_id: Nullish<MessageID>;
|
||||
mention_count: number;
|
||||
last_pin_timestamp: Nullish<Date>;
|
||||
}
|
||||
|
||||
export const CHANNEL_COLUMNS = [
|
||||
'channel_id',
|
||||
'guild_id',
|
||||
'type',
|
||||
'name',
|
||||
'topic',
|
||||
'icon_hash',
|
||||
'url',
|
||||
'parent_id',
|
||||
'position',
|
||||
'owner_id',
|
||||
'recipient_ids',
|
||||
'nsfw',
|
||||
'rate_limit_per_user',
|
||||
'bitrate',
|
||||
'user_limit',
|
||||
'rtc_region',
|
||||
'last_message_id',
|
||||
'last_pin_timestamp',
|
||||
'permission_overwrites',
|
||||
'nicks',
|
||||
'soft_deleted',
|
||||
'indexed_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof ChannelRow>;
|
||||
|
||||
export interface ChannelsByGuildRow {
|
||||
guild_id: GuildID;
|
||||
channel_id: ChannelID;
|
||||
}
|
||||
|
||||
export const CHANNELS_BY_GUILD_COLUMNS = ['guild_id', 'channel_id'] as const satisfies ReadonlyArray<
|
||||
keyof ChannelsByGuildRow
|
||||
>;
|
||||
|
||||
export const INVITE_COLUMNS = [
|
||||
'code',
|
||||
'type',
|
||||
'guild_id',
|
||||
'channel_id',
|
||||
'inviter_id',
|
||||
'created_at',
|
||||
'uses',
|
||||
'max_uses',
|
||||
'max_age',
|
||||
'temporary',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof InviteRow>;
|
||||
|
||||
export const WEBHOOK_COLUMNS = [
|
||||
'webhook_id',
|
||||
'webhook_token',
|
||||
'type',
|
||||
'guild_id',
|
||||
'channel_id',
|
||||
'creator_id',
|
||||
'name',
|
||||
'avatar_hash',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof WebhookRow>;
|
||||
|
||||
export const READ_STATE_COLUMNS = [
|
||||
'user_id',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'mention_count',
|
||||
'last_pin_timestamp',
|
||||
] as const satisfies ReadonlyArray<keyof ReadStateRow>;
|
||||
|
||||
export const PRIVATE_CHANNEL_COLUMNS = ['user_id', 'channel_id', 'is_gdm'] as const satisfies ReadonlyArray<
|
||||
keyof PrivateChannelRow
|
||||
>;
|
||||
|
||||
export const DM_STATE_COLUMNS = ['hi_user_id', 'lo_user_id', 'channel_id'] as const satisfies ReadonlyArray<
|
||||
keyof DmStateRow
|
||||
>;
|
||||
55
fluxer/packages/api/src/database/types/ConnectionTypes.tsx
Normal file
55
fluxer/packages/api/src/database/types/ConnectionTypes.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {ConnectionType} from '@fluxer/constants/src/ConnectionConstants';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface UserConnectionRow {
|
||||
user_id: UserID;
|
||||
connection_id: string;
|
||||
connection_type: ConnectionType;
|
||||
identifier: string;
|
||||
name: string;
|
||||
verified: boolean;
|
||||
visibility_flags: number;
|
||||
sort_order: number;
|
||||
verification_token: string;
|
||||
verified_at: Nullish<Date>;
|
||||
last_verified_at: Nullish<Date>;
|
||||
created_at: Date;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const USER_CONNECTION_COLUMNS = [
|
||||
'user_id',
|
||||
'connection_id',
|
||||
'connection_type',
|
||||
'identifier',
|
||||
'name',
|
||||
'verified',
|
||||
'visibility_flags',
|
||||
'sort_order',
|
||||
'verification_token',
|
||||
'verified_at',
|
||||
'last_verified_at',
|
||||
'created_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof UserConnectionRow>;
|
||||
152
fluxer/packages/api/src/database/types/CsamTypes.tsx
Normal file
152
fluxer/packages/api/src/database/types/CsamTypes.tsx
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface CsamEvidencePackageRow {
|
||||
report_id: bigint;
|
||||
resource_type: string;
|
||||
bucket: string;
|
||||
key: string;
|
||||
cdn_url: string | null;
|
||||
filename: string;
|
||||
content_type: string | null;
|
||||
channel_id: bigint | null;
|
||||
message_id: bigint | null;
|
||||
guild_id: bigint | null;
|
||||
user_id: bigint | null;
|
||||
match_tracking_id: string | null;
|
||||
match_details: string | null;
|
||||
frames: string | null;
|
||||
hashes: string | null;
|
||||
context_snapshot: string | null;
|
||||
created_at: Date;
|
||||
expires_at: Date;
|
||||
integrity_sha256: string;
|
||||
evidence_zip_key: string;
|
||||
}
|
||||
|
||||
export interface CsamEvidenceLegalHoldRow {
|
||||
report_id: bigint;
|
||||
held_until: Date | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface CsamScanJobRow {
|
||||
job_id: string;
|
||||
resource_type: string;
|
||||
bucket: string | null;
|
||||
key: string | null;
|
||||
cdn_url: string | null;
|
||||
filename: string | null;
|
||||
content_type: string | null;
|
||||
channel_id: bigint | null;
|
||||
message_id: bigint | null;
|
||||
guild_id: bigint | null;
|
||||
user_id: bigint | null;
|
||||
status: string;
|
||||
enqueue_time: Date;
|
||||
last_updated: Date;
|
||||
match_tracking_id: string | null;
|
||||
match_details: string | null;
|
||||
hashes: string | null;
|
||||
error_message: string | null;
|
||||
expires_at: Date;
|
||||
}
|
||||
|
||||
export const CSAM_EVIDENCE_PACKAGE_COLUMNS = [
|
||||
'report_id',
|
||||
'resource_type',
|
||||
'bucket',
|
||||
'key',
|
||||
'cdn_url',
|
||||
'filename',
|
||||
'content_type',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'guild_id',
|
||||
'user_id',
|
||||
'match_tracking_id',
|
||||
'match_details',
|
||||
'frames',
|
||||
'hashes',
|
||||
'context_snapshot',
|
||||
'created_at',
|
||||
'expires_at',
|
||||
'integrity_sha256',
|
||||
'evidence_zip_key',
|
||||
] as const satisfies ReadonlyArray<keyof CsamEvidencePackageRow>;
|
||||
|
||||
export const CSAM_EVIDENCE_LEGAL_HOLD_COLUMNS = [
|
||||
'report_id',
|
||||
'held_until',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof CsamEvidenceLegalHoldRow>;
|
||||
|
||||
export const CSAM_SCAN_JOB_COLUMNS = [
|
||||
'job_id',
|
||||
'resource_type',
|
||||
'bucket',
|
||||
'key',
|
||||
'cdn_url',
|
||||
'filename',
|
||||
'content_type',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'guild_id',
|
||||
'user_id',
|
||||
'status',
|
||||
'enqueue_time',
|
||||
'last_updated',
|
||||
'match_tracking_id',
|
||||
'match_details',
|
||||
'hashes',
|
||||
'error_message',
|
||||
'expires_at',
|
||||
] as const satisfies ReadonlyArray<keyof CsamScanJobRow>;
|
||||
|
||||
export interface CsamEvidenceExpirationRow {
|
||||
bucket: string;
|
||||
expires_at: Date;
|
||||
report_id: bigint;
|
||||
}
|
||||
|
||||
export const CSAM_EVIDENCE_EXPIRATION_COLUMNS = ['bucket', 'expires_at', 'report_id'] as const satisfies ReadonlyArray<
|
||||
keyof CsamEvidenceExpirationRow
|
||||
>;
|
||||
|
||||
export interface NcmecSubmissionRow {
|
||||
report_id: bigint;
|
||||
status: string;
|
||||
ncmec_report_id: string | null;
|
||||
submitted_at: Date | null;
|
||||
submitted_by_admin_id: bigint | null;
|
||||
failure_reason: string | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export const NCMEC_SUBMISSION_COLUMNS = [
|
||||
'report_id',
|
||||
'status',
|
||||
'ncmec_report_id',
|
||||
'submitted_at',
|
||||
'submitted_by_admin_id',
|
||||
'failure_reason',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof NcmecSubmissionRow>;
|
||||
20
fluxer/packages/api/src/database/types/DatabaseRowTypes.tsx
Normal file
20
fluxer/packages/api/src/database/types/DatabaseRowTypes.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export type ExactRow<T> = T;
|
||||
96
fluxer/packages/api/src/database/types/DonationTypes.tsx
Normal file
96
fluxer/packages/api/src/database/types/DonationTypes.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface DonorRow {
|
||||
email: string;
|
||||
stripe_customer_id: Nullish<string>;
|
||||
business_name: Nullish<string>;
|
||||
tax_id: Nullish<string>;
|
||||
tax_id_type: Nullish<string>;
|
||||
stripe_subscription_id: Nullish<string>;
|
||||
subscription_amount_cents: Nullish<number>;
|
||||
subscription_currency: Nullish<string>;
|
||||
subscription_interval: Nullish<string>;
|
||||
subscription_current_period_end: Nullish<Date>;
|
||||
subscription_cancel_at: Nullish<Date>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface DonorByStripeCustomerIdRow {
|
||||
stripe_customer_id: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface DonorByStripeSubscriptionIdRow {
|
||||
stripe_subscription_id: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface DonorMagicLinkTokenRow {
|
||||
token_: string;
|
||||
donor_email: string;
|
||||
expires_at: Date;
|
||||
used_at: Nullish<Date>;
|
||||
}
|
||||
|
||||
export interface DonorMagicLinkTokenByEmailRow {
|
||||
donor_email: string;
|
||||
token_: string;
|
||||
}
|
||||
|
||||
export const DONOR_COLUMNS = [
|
||||
'email',
|
||||
'stripe_customer_id',
|
||||
'business_name',
|
||||
'tax_id',
|
||||
'tax_id_type',
|
||||
'stripe_subscription_id',
|
||||
'subscription_amount_cents',
|
||||
'subscription_currency',
|
||||
'subscription_interval',
|
||||
'subscription_current_period_end',
|
||||
'subscription_cancel_at',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof DonorRow>;
|
||||
|
||||
export const DONOR_BY_STRIPE_CUSTOMER_ID_COLUMNS = ['stripe_customer_id', 'email'] as const satisfies ReadonlyArray<
|
||||
keyof DonorByStripeCustomerIdRow
|
||||
>;
|
||||
|
||||
export const DONOR_BY_STRIPE_SUBSCRIPTION_ID_COLUMNS = [
|
||||
'stripe_subscription_id',
|
||||
'email',
|
||||
] as const satisfies ReadonlyArray<keyof DonorByStripeSubscriptionIdRow>;
|
||||
|
||||
export const DONOR_MAGIC_LINK_TOKEN_COLUMNS = [
|
||||
'token_',
|
||||
'donor_email',
|
||||
'expires_at',
|
||||
'used_at',
|
||||
] as const satisfies ReadonlyArray<keyof DonorMagicLinkTokenRow>;
|
||||
|
||||
export const DONOR_MAGIC_LINK_TOKEN_BY_EMAIL_COLUMNS = ['donor_email', 'token_'] as const satisfies ReadonlyArray<
|
||||
keyof DonorMagicLinkTokenByEmailRow
|
||||
>;
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface GuildDiscoveryRow {
|
||||
guild_id: GuildID;
|
||||
status: string;
|
||||
category_type: number;
|
||||
description: string;
|
||||
applied_at: Date;
|
||||
reviewed_at: Nullish<Date>;
|
||||
reviewed_by: Nullish<UserID>;
|
||||
review_reason: Nullish<string>;
|
||||
removed_at: Nullish<Date>;
|
||||
removed_by: Nullish<UserID>;
|
||||
removal_reason: Nullish<string>;
|
||||
}
|
||||
|
||||
export const GUILD_DISCOVERY_COLUMNS = [
|
||||
'guild_id',
|
||||
'status',
|
||||
'category_type',
|
||||
'description',
|
||||
'applied_at',
|
||||
'reviewed_at',
|
||||
'reviewed_by',
|
||||
'review_reason',
|
||||
'removed_at',
|
||||
'removed_by',
|
||||
'removal_reason',
|
||||
] as const satisfies ReadonlyArray<keyof GuildDiscoveryRow>;
|
||||
|
||||
export interface GuildDiscoveryByStatusRow {
|
||||
status: string;
|
||||
applied_at: Date;
|
||||
guild_id: GuildID;
|
||||
}
|
||||
|
||||
export const GUILD_DISCOVERY_BY_STATUS_COLUMNS = ['status', 'applied_at', 'guild_id'] as const satisfies ReadonlyArray<
|
||||
keyof GuildDiscoveryByStatusRow
|
||||
>;
|
||||
297
fluxer/packages/api/src/database/types/GuildTypes.tsx
Normal file
297
fluxer/packages/api/src/database/types/GuildTypes.tsx
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
ChannelID,
|
||||
EmojiID,
|
||||
GuildID,
|
||||
InviteCode,
|
||||
RoleID,
|
||||
StickerID,
|
||||
UserID,
|
||||
VanityURLCode,
|
||||
} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {AuditLogActionType} from '@fluxer/constants/src/AuditLogActionType';
|
||||
import type {GuildSplashCardAlignmentValue} from '@fluxer/constants/src/GuildConstants';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface GuildRow {
|
||||
guild_id: GuildID;
|
||||
owner_id: UserID;
|
||||
name: string;
|
||||
vanity_url_code: Nullish<VanityURLCode>;
|
||||
icon_hash: Nullish<string>;
|
||||
banner_hash: Nullish<string>;
|
||||
banner_width: Nullish<number>;
|
||||
banner_height: Nullish<number>;
|
||||
splash_hash: Nullish<string>;
|
||||
splash_width: Nullish<number>;
|
||||
splash_height: Nullish<number>;
|
||||
splash_card_alignment: Nullish<GuildSplashCardAlignmentValue>;
|
||||
embed_splash_hash: Nullish<string>;
|
||||
embed_splash_width: Nullish<number>;
|
||||
embed_splash_height: Nullish<number>;
|
||||
features: Nullish<Set<string>>;
|
||||
verification_level: number;
|
||||
mfa_level: number;
|
||||
nsfw_level: number;
|
||||
explicit_content_filter: number;
|
||||
default_message_notifications: number;
|
||||
system_channel_id: Nullish<ChannelID>;
|
||||
system_channel_flags: number;
|
||||
rules_channel_id: Nullish<ChannelID>;
|
||||
afk_channel_id: Nullish<ChannelID>;
|
||||
afk_timeout: number;
|
||||
disabled_operations: number;
|
||||
member_count: number;
|
||||
audit_logs_indexed_at: Nullish<Date>;
|
||||
members_indexed_at: Nullish<Date>;
|
||||
message_history_cutoff: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const GUILD_COLUMNS = [
|
||||
'guild_id',
|
||||
'owner_id',
|
||||
'name',
|
||||
'vanity_url_code',
|
||||
'icon_hash',
|
||||
'banner_hash',
|
||||
'banner_width',
|
||||
'banner_height',
|
||||
'splash_hash',
|
||||
'splash_width',
|
||||
'splash_height',
|
||||
'splash_card_alignment',
|
||||
'embed_splash_hash',
|
||||
'embed_splash_width',
|
||||
'embed_splash_height',
|
||||
'features',
|
||||
'verification_level',
|
||||
'mfa_level',
|
||||
'nsfw_level',
|
||||
'explicit_content_filter',
|
||||
'default_message_notifications',
|
||||
'system_channel_id',
|
||||
'system_channel_flags',
|
||||
'rules_channel_id',
|
||||
'afk_channel_id',
|
||||
'afk_timeout',
|
||||
'disabled_operations',
|
||||
'member_count',
|
||||
'audit_logs_indexed_at',
|
||||
'members_indexed_at',
|
||||
'message_history_cutoff',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof GuildRow>;
|
||||
|
||||
export interface GuildMemberRow {
|
||||
guild_id: GuildID;
|
||||
user_id: UserID;
|
||||
joined_at: Date;
|
||||
nick: Nullish<string>;
|
||||
avatar_hash: Nullish<string>;
|
||||
banner_hash: Nullish<string>;
|
||||
bio: Nullish<string>;
|
||||
pronouns: Nullish<string>;
|
||||
accent_color: Nullish<number>;
|
||||
join_source_type: Nullish<number>;
|
||||
source_invite_code: Nullish<InviteCode>;
|
||||
inviter_id: Nullish<UserID>;
|
||||
deaf: boolean;
|
||||
mute: boolean;
|
||||
communication_disabled_until: Nullish<Date>;
|
||||
role_ids: Nullish<Set<RoleID>>;
|
||||
is_premium_sanitized: Nullish<boolean>;
|
||||
temporary: Nullish<boolean>;
|
||||
profile_flags: Nullish<number>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const GUILD_MEMBER_COLUMNS = [
|
||||
'guild_id',
|
||||
'user_id',
|
||||
'joined_at',
|
||||
'nick',
|
||||
'avatar_hash',
|
||||
'banner_hash',
|
||||
'bio',
|
||||
'pronouns',
|
||||
'accent_color',
|
||||
'join_source_type',
|
||||
'source_invite_code',
|
||||
'inviter_id',
|
||||
'deaf',
|
||||
'mute',
|
||||
'communication_disabled_until',
|
||||
'role_ids',
|
||||
'is_premium_sanitized',
|
||||
'temporary',
|
||||
'profile_flags',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof GuildMemberRow>;
|
||||
|
||||
export interface GuildAuditLogRow {
|
||||
guild_id: GuildID;
|
||||
log_id: bigint;
|
||||
user_id: UserID;
|
||||
target_id: Nullish<string>;
|
||||
action_type: AuditLogActionType;
|
||||
reason: Nullish<string>;
|
||||
options: Nullish<Map<string, string>>;
|
||||
changes: Nullish<string>;
|
||||
}
|
||||
|
||||
export const GUILD_AUDIT_LOG_COLUMNS = [
|
||||
'guild_id',
|
||||
'log_id',
|
||||
'user_id',
|
||||
'target_id',
|
||||
'action_type',
|
||||
'reason',
|
||||
'options',
|
||||
'changes',
|
||||
] as const satisfies ReadonlyArray<keyof GuildAuditLogRow>;
|
||||
|
||||
export interface GuildRoleRow {
|
||||
guild_id: GuildID;
|
||||
role_id: RoleID;
|
||||
name: string;
|
||||
permissions: bigint;
|
||||
position: number;
|
||||
hoist_position: Nullish<number>;
|
||||
color: number;
|
||||
icon_hash: Nullish<string>;
|
||||
unicode_emoji: Nullish<string>;
|
||||
hoist: boolean;
|
||||
mentionable: boolean;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const GUILD_ROLE_COLUMNS = [
|
||||
'guild_id',
|
||||
'role_id',
|
||||
'name',
|
||||
'permissions',
|
||||
'position',
|
||||
'hoist_position',
|
||||
'color',
|
||||
'icon_hash',
|
||||
'unicode_emoji',
|
||||
'hoist',
|
||||
'mentionable',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof GuildRoleRow>;
|
||||
|
||||
export interface GuildBanRow {
|
||||
guild_id: GuildID;
|
||||
user_id: UserID;
|
||||
moderator_id: UserID;
|
||||
banned_at: Date;
|
||||
expires_at: Nullish<Date>;
|
||||
reason: Nullish<string>;
|
||||
ip: Nullish<string>;
|
||||
}
|
||||
|
||||
export const GUILD_BAN_COLUMNS = [
|
||||
'guild_id',
|
||||
'user_id',
|
||||
'moderator_id',
|
||||
'banned_at',
|
||||
'expires_at',
|
||||
'reason',
|
||||
'ip',
|
||||
] as const satisfies ReadonlyArray<keyof GuildBanRow>;
|
||||
|
||||
export interface GuildEmojiRow {
|
||||
guild_id: GuildID;
|
||||
emoji_id: EmojiID;
|
||||
name: string;
|
||||
creator_id: UserID;
|
||||
animated: boolean;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const GUILD_EMOJI_COLUMNS = [
|
||||
'guild_id',
|
||||
'emoji_id',
|
||||
'name',
|
||||
'creator_id',
|
||||
'animated',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof GuildEmojiRow>;
|
||||
|
||||
export const GUILD_EMOJI_BY_EMOJI_ID_COLUMNS = [
|
||||
'guild_id',
|
||||
'emoji_id',
|
||||
'name',
|
||||
'creator_id',
|
||||
'animated',
|
||||
] as const satisfies ReadonlyArray<keyof GuildEmojiRow>;
|
||||
|
||||
export interface GuildStickerRow {
|
||||
guild_id: GuildID;
|
||||
sticker_id: StickerID;
|
||||
name: string;
|
||||
description: Nullish<string>;
|
||||
animated: boolean;
|
||||
tags: Nullish<Array<string>>;
|
||||
creator_id: UserID;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const GUILD_STICKER_COLUMNS = [
|
||||
'guild_id',
|
||||
'sticker_id',
|
||||
'name',
|
||||
'description',
|
||||
'animated',
|
||||
'tags',
|
||||
'creator_id',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof GuildStickerRow>;
|
||||
|
||||
export const GUILD_STICKER_BY_STICKER_ID_COLUMNS = [
|
||||
'guild_id',
|
||||
'sticker_id',
|
||||
'name',
|
||||
'description',
|
||||
'animated',
|
||||
'tags',
|
||||
'creator_id',
|
||||
] as const satisfies ReadonlyArray<keyof GuildStickerRow>;
|
||||
|
||||
export interface GuildMemberByUserIdRow {
|
||||
user_id: UserID;
|
||||
guild_id: GuildID;
|
||||
}
|
||||
|
||||
export const GUILD_MEMBER_BY_USER_ID_COLUMNS = ['user_id', 'guild_id'] as const satisfies ReadonlyArray<
|
||||
keyof GuildMemberByUserIdRow
|
||||
>;
|
||||
|
||||
export interface GuildByOwnerIdRow {
|
||||
owner_id: UserID;
|
||||
guild_id: GuildID;
|
||||
}
|
||||
|
||||
export const GUILD_BY_OWNER_ID_COLUMNS = ['owner_id', 'guild_id'] as const satisfies ReadonlyArray<
|
||||
keyof GuildByOwnerIdRow
|
||||
>;
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface InstanceConfigurationRow {
|
||||
key: string;
|
||||
value: string | null;
|
||||
updated_at: Date | null;
|
||||
}
|
||||
|
||||
export const INSTANCE_CONFIGURATION_COLUMNS = ['key', 'value', 'updated_at'] as const satisfies ReadonlyArray<
|
||||
keyof InstanceConfigurationRow
|
||||
>;
|
||||
284
fluxer/packages/api/src/database/types/MessageTypes.tsx
Normal file
284
fluxer/packages/api/src/database/types/MessageTypes.tsx
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {
|
||||
AttachmentID,
|
||||
ChannelID,
|
||||
EmojiID,
|
||||
GuildID,
|
||||
MessageID,
|
||||
RoleID,
|
||||
StickerID,
|
||||
UserID,
|
||||
WebhookID,
|
||||
} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface MessageAttachment {
|
||||
attachment_id: AttachmentID;
|
||||
filename: string;
|
||||
size: bigint;
|
||||
title: Nullish<string>;
|
||||
description: Nullish<string>;
|
||||
width: Nullish<number>;
|
||||
height: Nullish<number>;
|
||||
content_type: string;
|
||||
content_hash: Nullish<string>;
|
||||
placeholder: Nullish<string>;
|
||||
flags: number;
|
||||
duration: Nullish<number>;
|
||||
nsfw: Nullish<boolean>;
|
||||
waveform: Nullish<string>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedAuthor {
|
||||
name: Nullish<string>;
|
||||
url: Nullish<string>;
|
||||
icon_url: Nullish<string>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedProvider {
|
||||
name: Nullish<string>;
|
||||
url: Nullish<string>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedFooter {
|
||||
text: Nullish<string>;
|
||||
icon_url: Nullish<string>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedMedia {
|
||||
url: Nullish<string>;
|
||||
width: Nullish<number>;
|
||||
height: Nullish<number>;
|
||||
description: Nullish<string>;
|
||||
content_type: Nullish<string>;
|
||||
content_hash: Nullish<string>;
|
||||
placeholder: Nullish<string>;
|
||||
flags: number;
|
||||
duration: Nullish<number>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedField {
|
||||
name: Nullish<string>;
|
||||
value: Nullish<string>;
|
||||
inline: boolean;
|
||||
}
|
||||
|
||||
interface MessageEmbedBase {
|
||||
type: Nullish<string>;
|
||||
title: Nullish<string>;
|
||||
description: Nullish<string>;
|
||||
url: Nullish<string>;
|
||||
timestamp: Nullish<Date>;
|
||||
color: Nullish<number>;
|
||||
author: Nullish<MessageEmbedAuthor>;
|
||||
provider: Nullish<MessageEmbedProvider>;
|
||||
thumbnail: Nullish<MessageEmbedMedia>;
|
||||
image: Nullish<MessageEmbedMedia>;
|
||||
video: Nullish<MessageEmbedMedia>;
|
||||
footer: Nullish<MessageEmbedFooter>;
|
||||
fields: Nullish<Array<MessageEmbedField>>;
|
||||
nsfw: Nullish<boolean>;
|
||||
}
|
||||
|
||||
export interface MessageEmbedChild extends MessageEmbedBase {}
|
||||
|
||||
export interface MessageEmbed extends MessageEmbedBase {
|
||||
children?: Nullish<Array<MessageEmbedChild>>;
|
||||
}
|
||||
|
||||
export interface MessageStickerItem {
|
||||
sticker_id: StickerID;
|
||||
name: string;
|
||||
animated?: boolean;
|
||||
}
|
||||
|
||||
export interface MessageReference {
|
||||
channel_id: ChannelID;
|
||||
message_id: MessageID;
|
||||
guild_id: Nullish<GuildID>;
|
||||
type: number;
|
||||
}
|
||||
|
||||
export interface MessageSnapshot {
|
||||
content: Nullish<string>;
|
||||
timestamp: Date;
|
||||
edited_timestamp: Nullish<Date>;
|
||||
mention_users: Nullish<Set<UserID>>;
|
||||
mention_roles: Nullish<Set<RoleID>>;
|
||||
mention_channels: Nullish<Set<ChannelID>>;
|
||||
attachments: Nullish<Array<MessageAttachment>>;
|
||||
embeds: Nullish<Array<MessageEmbed>>;
|
||||
sticker_items: Nullish<Array<MessageStickerItem>>;
|
||||
type: number;
|
||||
flags: number;
|
||||
}
|
||||
|
||||
export interface MessageCall {
|
||||
participant_ids: Nullish<Set<UserID>>;
|
||||
ended_timestamp: Nullish<Date>;
|
||||
}
|
||||
|
||||
export interface MessageRow {
|
||||
channel_id: ChannelID;
|
||||
bucket: number;
|
||||
message_id: MessageID;
|
||||
author_id: Nullish<UserID>;
|
||||
type: number;
|
||||
webhook_id: Nullish<WebhookID>;
|
||||
webhook_name: Nullish<string>;
|
||||
webhook_avatar_hash: Nullish<string>;
|
||||
content: Nullish<string>;
|
||||
edited_timestamp: Nullish<Date>;
|
||||
pinned_timestamp: Nullish<Date>;
|
||||
flags: number;
|
||||
mention_everyone: boolean;
|
||||
mention_users: Nullish<Set<UserID>>;
|
||||
mention_roles: Nullish<Set<RoleID>>;
|
||||
mention_channels: Nullish<Set<ChannelID>>;
|
||||
attachments: Nullish<Array<MessageAttachment>>;
|
||||
embeds: Nullish<Array<MessageEmbed>>;
|
||||
sticker_items: Nullish<Array<MessageStickerItem>>;
|
||||
message_reference: Nullish<MessageReference>;
|
||||
message_snapshots: Nullish<Array<MessageSnapshot>>;
|
||||
call: Nullish<MessageCall>;
|
||||
has_reaction: Nullish<boolean>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const MESSAGE_COLUMNS = [
|
||||
'channel_id',
|
||||
'bucket',
|
||||
'message_id',
|
||||
'author_id',
|
||||
'type',
|
||||
'webhook_id',
|
||||
'webhook_name',
|
||||
'webhook_avatar_hash',
|
||||
'content',
|
||||
'edited_timestamp',
|
||||
'pinned_timestamp',
|
||||
'flags',
|
||||
'mention_everyone',
|
||||
'mention_users',
|
||||
'mention_roles',
|
||||
'mention_channels',
|
||||
'attachments',
|
||||
'embeds',
|
||||
'sticker_items',
|
||||
'message_reference',
|
||||
'message_snapshots',
|
||||
'call',
|
||||
'has_reaction',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof MessageRow>;
|
||||
|
||||
export interface ChannelPinRow {
|
||||
channel_id: ChannelID;
|
||||
message_id: MessageID;
|
||||
pinned_timestamp: Date;
|
||||
}
|
||||
|
||||
export interface MessageReactionRow {
|
||||
channel_id: ChannelID;
|
||||
bucket: number;
|
||||
message_id: MessageID;
|
||||
user_id: UserID;
|
||||
emoji_id: EmojiID;
|
||||
emoji_name: string;
|
||||
emoji_animated: boolean;
|
||||
}
|
||||
|
||||
export interface AttachmentLookupRow {
|
||||
channel_id: ChannelID;
|
||||
attachment_id: AttachmentID;
|
||||
filename: string;
|
||||
message_id: MessageID;
|
||||
}
|
||||
|
||||
export const ATTACHMENT_LOOKUP_COLUMNS = [
|
||||
'channel_id',
|
||||
'attachment_id',
|
||||
'filename',
|
||||
'message_id',
|
||||
] as const satisfies ReadonlyArray<keyof AttachmentLookupRow>;
|
||||
|
||||
export const CHANNEL_PIN_COLUMNS = ['channel_id', 'message_id', 'pinned_timestamp'] as const satisfies ReadonlyArray<
|
||||
keyof ChannelPinRow
|
||||
>;
|
||||
|
||||
export const MESSAGE_REACTION_COLUMNS = [
|
||||
'channel_id',
|
||||
'bucket',
|
||||
'message_id',
|
||||
'user_id',
|
||||
'emoji_id',
|
||||
'emoji_name',
|
||||
'emoji_animated',
|
||||
] as const satisfies ReadonlyArray<keyof MessageReactionRow>;
|
||||
|
||||
export interface MessageByAuthorRow {
|
||||
author_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
message_id: MessageID;
|
||||
}
|
||||
|
||||
export const MESSAGE_BY_AUTHOR_COLUMNS = ['author_id', 'channel_id', 'message_id'] as const satisfies ReadonlyArray<
|
||||
keyof MessageByAuthorRow
|
||||
>;
|
||||
|
||||
export interface ChannelStateRow {
|
||||
channel_id: ChannelID;
|
||||
created_bucket: number;
|
||||
has_messages: boolean;
|
||||
last_message_id: Nullish<MessageID>;
|
||||
last_message_bucket: Nullish<number>;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export const CHANNEL_STATE_COLUMNS = [
|
||||
'channel_id',
|
||||
'created_bucket',
|
||||
'has_messages',
|
||||
'last_message_id',
|
||||
'last_message_bucket',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof ChannelStateRow>;
|
||||
|
||||
export interface ChannelMessageBucketRow {
|
||||
channel_id: ChannelID;
|
||||
bucket: number;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export const CHANNEL_MESSAGE_BUCKET_COLUMNS = ['channel_id', 'bucket', 'updated_at'] as const satisfies ReadonlyArray<
|
||||
keyof ChannelMessageBucketRow
|
||||
>;
|
||||
|
||||
export interface ChannelEmptyBucketRow {
|
||||
channel_id: ChannelID;
|
||||
bucket: number;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export const CHANNEL_EMPTY_BUCKET_COLUMNS = ['channel_id', 'bucket', 'updated_at'] as const satisfies ReadonlyArray<
|
||||
keyof ChannelEmptyBucketRow
|
||||
>;
|
||||
119
fluxer/packages/api/src/database/types/OAuth2Types.tsx
Normal file
119
fluxer/packages/api/src/database/types/OAuth2Types.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {ApplicationID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
export interface ApplicationRow {
|
||||
application_id: ApplicationID;
|
||||
owner_user_id: UserID;
|
||||
name: string;
|
||||
bot_user_id: UserID | null;
|
||||
bot_is_public: boolean | null;
|
||||
bot_require_code_grant?: boolean | null;
|
||||
oauth2_redirect_uris: Set<string>;
|
||||
client_secret_hash: string | null;
|
||||
bot_token_hash: string | null;
|
||||
bot_token_preview: string | null;
|
||||
bot_token_created_at: Date | null;
|
||||
client_secret_created_at: Date | null;
|
||||
version?: number | null;
|
||||
}
|
||||
|
||||
export interface ApplicationByOwnerRow {
|
||||
owner_user_id: UserID;
|
||||
application_id: ApplicationID;
|
||||
}
|
||||
|
||||
export interface OAuth2AuthorizationCodeRow {
|
||||
code: string;
|
||||
application_id: ApplicationID;
|
||||
user_id: UserID;
|
||||
redirect_uri: string;
|
||||
scope: Set<string>;
|
||||
nonce: string | null;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface OAuth2AccessTokenRow {
|
||||
token_: string;
|
||||
application_id: ApplicationID;
|
||||
user_id: UserID | null;
|
||||
scope: Set<string>;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface OAuth2AccessTokenByUserRow {
|
||||
user_id: UserID;
|
||||
token_: string;
|
||||
}
|
||||
|
||||
export interface OAuth2RefreshTokenRow {
|
||||
token_: string;
|
||||
application_id: ApplicationID;
|
||||
user_id: UserID;
|
||||
scope: Set<string>;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export interface OAuth2RefreshTokenByUserRow {
|
||||
user_id: UserID;
|
||||
token_: string;
|
||||
}
|
||||
|
||||
export const APPLICATION_COLUMNS = [
|
||||
'application_id',
|
||||
'owner_user_id',
|
||||
'name',
|
||||
'bot_user_id',
|
||||
'bot_is_public',
|
||||
'bot_require_code_grant',
|
||||
'oauth2_redirect_uris',
|
||||
'client_secret_hash',
|
||||
'bot_token_hash',
|
||||
'bot_token_preview',
|
||||
'bot_token_created_at',
|
||||
'client_secret_created_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof ApplicationRow>;
|
||||
|
||||
export const OAUTH2_AUTHORIZATION_CODE_COLUMNS = [
|
||||
'code',
|
||||
'application_id',
|
||||
'user_id',
|
||||
'redirect_uri',
|
||||
'scope',
|
||||
'nonce',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof OAuth2AuthorizationCodeRow>;
|
||||
|
||||
export const OAUTH2_ACCESS_TOKEN_COLUMNS = [
|
||||
'token_',
|
||||
'application_id',
|
||||
'user_id',
|
||||
'scope',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof OAuth2AccessTokenRow>;
|
||||
|
||||
export const OAUTH2_REFRESH_TOKEN_COLUMNS = [
|
||||
'token_',
|
||||
'application_id',
|
||||
'user_id',
|
||||
'scope',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof OAuth2RefreshTokenRow>;
|
||||
145
fluxer/packages/api/src/database/types/PaymentTypes.tsx
Normal file
145
fluxer/packages/api/src/database/types/PaymentTypes.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface GiftCodeRow {
|
||||
code: string;
|
||||
duration_months: number;
|
||||
created_at: Date;
|
||||
created_by_user_id: UserID;
|
||||
redeemed_at: Nullish<Date>;
|
||||
redeemed_by_user_id: Nullish<UserID>;
|
||||
stripe_payment_intent_id: Nullish<string>;
|
||||
visionary_sequence_number: Nullish<number>;
|
||||
checkout_session_id: Nullish<string>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface PaymentRow {
|
||||
checkout_session_id: string;
|
||||
user_id: UserID;
|
||||
stripe_customer_id: Nullish<string>;
|
||||
payment_intent_id: Nullish<string>;
|
||||
subscription_id: Nullish<string>;
|
||||
invoice_id: Nullish<string>;
|
||||
price_id: Nullish<string>;
|
||||
product_type: Nullish<string>;
|
||||
amount_cents: number;
|
||||
currency: string;
|
||||
status: string;
|
||||
is_gift: boolean;
|
||||
gift_code: Nullish<string>;
|
||||
created_at: Date;
|
||||
completed_at: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface PaymentBySubscriptionRow {
|
||||
subscription_id: string;
|
||||
checkout_session_id: string;
|
||||
user_id: UserID;
|
||||
price_id: string;
|
||||
product_type: string;
|
||||
}
|
||||
|
||||
export interface VisionarySlotRow {
|
||||
slot_index: number;
|
||||
user_id: UserID | null;
|
||||
}
|
||||
|
||||
export const PAYMENT_COLUMNS = [
|
||||
'checkout_session_id',
|
||||
'user_id',
|
||||
'stripe_customer_id',
|
||||
'payment_intent_id',
|
||||
'subscription_id',
|
||||
'invoice_id',
|
||||
'price_id',
|
||||
'product_type',
|
||||
'amount_cents',
|
||||
'currency',
|
||||
'status',
|
||||
'is_gift',
|
||||
'gift_code',
|
||||
'created_at',
|
||||
'completed_at',
|
||||
'version',
|
||||
] as const;
|
||||
|
||||
export const PAYMENT_BY_SUBSCRIPTION_COLUMNS = [
|
||||
'subscription_id',
|
||||
'checkout_session_id',
|
||||
'user_id',
|
||||
'price_id',
|
||||
'product_type',
|
||||
] as const;
|
||||
|
||||
export const PAYMENT_BY_PAYMENT_INTENT_COLUMNS = ['payment_intent_id', 'checkout_session_id'] as const;
|
||||
|
||||
export const PAYMENT_BY_USER_COLUMNS = ['user_id', 'created_at', 'checkout_session_id'] as const;
|
||||
|
||||
export const GIFT_CODE_COLUMNS = [
|
||||
'code',
|
||||
'duration_months',
|
||||
'created_at',
|
||||
'created_by_user_id',
|
||||
'redeemed_at',
|
||||
'redeemed_by_user_id',
|
||||
'stripe_payment_intent_id',
|
||||
'visionary_sequence_number',
|
||||
'checkout_session_id',
|
||||
'version',
|
||||
] as const;
|
||||
|
||||
export const GIFT_CODE_BY_CREATOR_COLUMNS = ['created_by_user_id', 'code'] as const;
|
||||
|
||||
export const GIFT_CODE_BY_PAYMENT_INTENT_COLUMNS = ['stripe_payment_intent_id', 'code'] as const;
|
||||
|
||||
export const GIFT_CODE_BY_REDEEMER_COLUMNS = ['redeemed_by_user_id', 'code'] as const;
|
||||
|
||||
export const VISIONARY_SLOT_COLUMNS = ['slot_index', 'user_id'] as const;
|
||||
|
||||
export interface PaymentByPaymentIntentRow {
|
||||
payment_intent_id: string;
|
||||
checkout_session_id: string;
|
||||
}
|
||||
|
||||
export interface PaymentByUserRow {
|
||||
user_id: UserID;
|
||||
created_at: Date;
|
||||
checkout_session_id: string;
|
||||
}
|
||||
|
||||
export interface GiftCodeByCreatorRow {
|
||||
created_by_user_id: UserID;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface GiftCodeByPaymentIntentRow {
|
||||
stripe_payment_intent_id: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface GiftCodeByRedeemerRow {
|
||||
redeemed_by_user_id: UserID;
|
||||
code: string;
|
||||
}
|
||||
127
fluxer/packages/api/src/database/types/ReportTypes.tsx
Normal file
127
fluxer/packages/api/src/database/types/ReportTypes.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {MessageAttachment, MessageEmbed, MessageStickerItem} from '@fluxer/api/src/database/types/MessageTypes';
|
||||
|
||||
type MentionCollection = ReadonlyArray<bigint> | Set<bigint> | null | undefined;
|
||||
|
||||
export interface IARMessageContextRow {
|
||||
message_id: bigint;
|
||||
channel_id: bigint | null;
|
||||
author_id: bigint;
|
||||
author_username: string;
|
||||
author_discriminator: number;
|
||||
author_avatar_hash: string | null;
|
||||
content: string | null;
|
||||
timestamp: Date;
|
||||
edited_timestamp: Date | null;
|
||||
type: number;
|
||||
flags: number;
|
||||
mention_everyone: boolean;
|
||||
mention_users: MentionCollection;
|
||||
mention_roles: MentionCollection;
|
||||
mention_channels: MentionCollection;
|
||||
attachments: Array<MessageAttachment> | null;
|
||||
embeds: Array<MessageEmbed> | null;
|
||||
sticker_items: Array<MessageStickerItem> | null;
|
||||
}
|
||||
|
||||
export interface IARSubmissionRow {
|
||||
report_id: bigint;
|
||||
reporter_id: bigint | null;
|
||||
reporter_email: string | null;
|
||||
reporter_full_legal_name: string | null;
|
||||
reporter_country_of_residence: string | null;
|
||||
reported_at: Date;
|
||||
status: number;
|
||||
report_type: number;
|
||||
category: string;
|
||||
additional_info: string | null;
|
||||
reported_user_id: bigint | null;
|
||||
reported_user_avatar_hash: string | null;
|
||||
reported_guild_id: bigint | null;
|
||||
reported_guild_name: string | null;
|
||||
reported_guild_icon_hash: string | null;
|
||||
reported_message_id: bigint | null;
|
||||
reported_channel_id: bigint | null;
|
||||
reported_channel_name: string | null;
|
||||
message_context: Array<IARMessageContextRow> | null;
|
||||
guild_context_id: bigint | null;
|
||||
resolved_at: Date | null;
|
||||
resolved_by_admin_id: bigint | null;
|
||||
public_comment: string | null;
|
||||
audit_log_reason: string | null;
|
||||
reported_guild_invite_code: string | null;
|
||||
}
|
||||
|
||||
export interface DSAReportEmailVerificationRow {
|
||||
email_lower: string;
|
||||
code_hash: string;
|
||||
expires_at: Date;
|
||||
last_sent_at: Date;
|
||||
}
|
||||
|
||||
export interface DSAReportTicketRow {
|
||||
ticket: string;
|
||||
email_lower: string;
|
||||
expires_at: Date;
|
||||
created_at: Date;
|
||||
}
|
||||
|
||||
export const IAR_SUBMISSION_COLUMNS = [
|
||||
'report_id',
|
||||
'reporter_id',
|
||||
'reporter_email',
|
||||
'reporter_full_legal_name',
|
||||
'reporter_country_of_residence',
|
||||
'reported_at',
|
||||
'status',
|
||||
'report_type',
|
||||
'category',
|
||||
'additional_info',
|
||||
'reported_user_id',
|
||||
'reported_user_avatar_hash',
|
||||
'reported_guild_id',
|
||||
'reported_guild_name',
|
||||
'reported_guild_icon_hash',
|
||||
'reported_message_id',
|
||||
'reported_channel_id',
|
||||
'reported_channel_name',
|
||||
'message_context',
|
||||
'guild_context_id',
|
||||
'resolved_at',
|
||||
'resolved_by_admin_id',
|
||||
'public_comment',
|
||||
'audit_log_reason',
|
||||
'reported_guild_invite_code',
|
||||
] as const satisfies ReadonlyArray<keyof IARSubmissionRow>;
|
||||
|
||||
export const DSA_REPORT_EMAIL_VERIFICATION_COLUMNS = [
|
||||
'email_lower',
|
||||
'code_hash',
|
||||
'expires_at',
|
||||
'last_sent_at',
|
||||
] as const satisfies ReadonlyArray<keyof DSAReportEmailVerificationRow>;
|
||||
|
||||
export const DSA_REPORT_TICKET_COLUMNS = [
|
||||
'ticket',
|
||||
'email_lower',
|
||||
'expires_at',
|
||||
'created_at',
|
||||
] as const satisfies ReadonlyArray<keyof DSAReportTicketRow>;
|
||||
61
fluxer/packages/api/src/database/types/SystemDmJobTypes.tsx
Normal file
61
fluxer/packages/api/src/database/types/SystemDmJobTypes.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
|
||||
export type SystemDmJobStatus = 'pending' | 'approved' | 'running' | 'completed' | 'failed';
|
||||
export interface SystemDmJobRow {
|
||||
job_type: string;
|
||||
job_id: bigint;
|
||||
admin_user_id: UserID;
|
||||
status: SystemDmJobStatus;
|
||||
content: string;
|
||||
registration_start: Date | null;
|
||||
registration_end: Date | null;
|
||||
excluded_guild_ids: ReadonlySet<string>;
|
||||
target_count: number;
|
||||
sent_count: number;
|
||||
failed_count: number;
|
||||
last_error: string | null;
|
||||
worker_job_key: string | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
approved_by: UserID | null;
|
||||
approved_at: Date | null;
|
||||
}
|
||||
|
||||
export const SYSTEM_DM_JOB_COLUMNS = [
|
||||
'job_type',
|
||||
'job_id',
|
||||
'admin_user_id',
|
||||
'status',
|
||||
'content',
|
||||
'registration_start',
|
||||
'registration_end',
|
||||
'excluded_guild_ids',
|
||||
'target_count',
|
||||
'sent_count',
|
||||
'failed_count',
|
||||
'last_error',
|
||||
'worker_job_key',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'approved_by',
|
||||
'approved_at',
|
||||
] as const satisfies ReadonlyArray<keyof SystemDmJobRow>;
|
||||
614
fluxer/packages/api/src/database/types/UserTypes.tsx
Normal file
614
fluxer/packages/api/src/database/types/UserTypes.tsx
Normal file
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {AttachmentID, ChannelID, EmojiID, GuildID, MemeID, MessageID, UserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import type {LocaleCode} from '@fluxer/constants/src/Locales';
|
||||
import type {GuildFolderIcon} from '@fluxer/constants/src/UserConstants';
|
||||
import type {types} from 'cassandra-driver';
|
||||
|
||||
type Nullish<T> = T | null;
|
||||
|
||||
export interface UserRow {
|
||||
user_id: UserID;
|
||||
username: string;
|
||||
discriminator: number;
|
||||
global_name: Nullish<string>;
|
||||
bot: Nullish<boolean>;
|
||||
system: Nullish<boolean>;
|
||||
email: Nullish<string>;
|
||||
email_verified: Nullish<boolean>;
|
||||
email_bounced: Nullish<boolean>;
|
||||
phone: Nullish<string>;
|
||||
password_hash: Nullish<string>;
|
||||
password_last_changed_at: Nullish<Date>;
|
||||
totp_secret: Nullish<string>;
|
||||
authenticator_types: Nullish<Set<number>>;
|
||||
avatar_hash: Nullish<string>;
|
||||
avatar_color: Nullish<number>;
|
||||
banner_hash: Nullish<string>;
|
||||
banner_color: Nullish<number>;
|
||||
bio: Nullish<string>;
|
||||
pronouns: Nullish<string>;
|
||||
accent_color: Nullish<number>;
|
||||
date_of_birth: Nullish<types.LocalDate>;
|
||||
locale: Nullish<string>;
|
||||
flags: Nullish<bigint>;
|
||||
premium_type: Nullish<number>;
|
||||
premium_since: Nullish<Date>;
|
||||
premium_until: Nullish<Date>;
|
||||
premium_will_cancel: Nullish<boolean>;
|
||||
premium_billing_cycle: Nullish<string>;
|
||||
premium_lifetime_sequence: Nullish<number>;
|
||||
stripe_subscription_id: Nullish<string>;
|
||||
stripe_customer_id: Nullish<string>;
|
||||
has_ever_purchased: Nullish<boolean>;
|
||||
suspicious_activity_flags: Nullish<number>;
|
||||
terms_agreed_at: Nullish<Date>;
|
||||
privacy_agreed_at: Nullish<Date>;
|
||||
last_active_at: Nullish<Date>;
|
||||
last_active_ip: Nullish<string>;
|
||||
temp_banned_until: Nullish<Date>;
|
||||
pending_bulk_message_deletion_at: Nullish<Date>;
|
||||
pending_bulk_message_deletion_channel_count: Nullish<number>;
|
||||
pending_bulk_message_deletion_message_count: Nullish<number>;
|
||||
pending_deletion_at: Nullish<Date>;
|
||||
deletion_reason_code: Nullish<number>;
|
||||
deletion_public_reason: Nullish<string>;
|
||||
deletion_audit_log_reason: Nullish<string>;
|
||||
acls: Nullish<Set<string>>;
|
||||
traits: Nullish<Set<string>>;
|
||||
first_refund_at: Nullish<Date>;
|
||||
gift_inventory_server_seq: Nullish<number>;
|
||||
gift_inventory_client_seq: Nullish<number>;
|
||||
premium_onboarding_dismissed_at: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const USER_COLUMNS = [
|
||||
'user_id',
|
||||
'username',
|
||||
'discriminator',
|
||||
'global_name',
|
||||
'bot',
|
||||
'system',
|
||||
'email',
|
||||
'email_verified',
|
||||
'email_bounced',
|
||||
'phone',
|
||||
'password_hash',
|
||||
'password_last_changed_at',
|
||||
'totp_secret',
|
||||
'authenticator_types',
|
||||
'avatar_hash',
|
||||
'avatar_color',
|
||||
'banner_hash',
|
||||
'banner_color',
|
||||
'bio',
|
||||
'pronouns',
|
||||
'accent_color',
|
||||
'date_of_birth',
|
||||
'locale',
|
||||
'flags',
|
||||
'premium_type',
|
||||
'premium_since',
|
||||
'premium_until',
|
||||
'premium_will_cancel',
|
||||
'premium_billing_cycle',
|
||||
'premium_lifetime_sequence',
|
||||
'stripe_subscription_id',
|
||||
'stripe_customer_id',
|
||||
'has_ever_purchased',
|
||||
'suspicious_activity_flags',
|
||||
'terms_agreed_at',
|
||||
'privacy_agreed_at',
|
||||
'last_active_at',
|
||||
'last_active_ip',
|
||||
'temp_banned_until',
|
||||
'pending_bulk_message_deletion_at',
|
||||
'pending_bulk_message_deletion_channel_count',
|
||||
'pending_bulk_message_deletion_message_count',
|
||||
'pending_deletion_at',
|
||||
'deletion_reason_code',
|
||||
'deletion_public_reason',
|
||||
'deletion_audit_log_reason',
|
||||
'acls',
|
||||
'traits',
|
||||
'first_refund_at',
|
||||
'gift_inventory_server_seq',
|
||||
'gift_inventory_client_seq',
|
||||
'premium_onboarding_dismissed_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof UserRow>;
|
||||
|
||||
export const EMPTY_USER_ROW: UserRow = {
|
||||
user_id: -1n as UserID,
|
||||
username: '',
|
||||
discriminator: 0,
|
||||
global_name: null,
|
||||
bot: null,
|
||||
system: null,
|
||||
email: null,
|
||||
email_verified: null,
|
||||
email_bounced: null,
|
||||
phone: null,
|
||||
password_hash: null,
|
||||
password_last_changed_at: null,
|
||||
totp_secret: null,
|
||||
authenticator_types: null,
|
||||
avatar_hash: null,
|
||||
avatar_color: null,
|
||||
banner_hash: null,
|
||||
banner_color: null,
|
||||
bio: null,
|
||||
pronouns: null,
|
||||
accent_color: null,
|
||||
date_of_birth: null,
|
||||
locale: null,
|
||||
flags: null,
|
||||
premium_type: null,
|
||||
premium_since: null,
|
||||
premium_until: null,
|
||||
premium_will_cancel: null,
|
||||
premium_billing_cycle: null,
|
||||
premium_lifetime_sequence: null,
|
||||
stripe_subscription_id: null,
|
||||
stripe_customer_id: null,
|
||||
has_ever_purchased: null,
|
||||
suspicious_activity_flags: null,
|
||||
terms_agreed_at: null,
|
||||
privacy_agreed_at: null,
|
||||
last_active_at: null,
|
||||
last_active_ip: null,
|
||||
temp_banned_until: null,
|
||||
pending_bulk_message_deletion_at: null,
|
||||
pending_bulk_message_deletion_channel_count: null,
|
||||
pending_bulk_message_deletion_message_count: null,
|
||||
pending_deletion_at: null,
|
||||
deletion_reason_code: null,
|
||||
deletion_public_reason: null,
|
||||
deletion_audit_log_reason: null,
|
||||
acls: null,
|
||||
traits: null,
|
||||
first_refund_at: null,
|
||||
gift_inventory_server_seq: null,
|
||||
gift_inventory_client_seq: null,
|
||||
premium_onboarding_dismissed_at: null,
|
||||
version: 1,
|
||||
};
|
||||
|
||||
export interface CustomStatus {
|
||||
text: Nullish<string>;
|
||||
emoji_id: Nullish<EmojiID>;
|
||||
emoji_name: Nullish<string>;
|
||||
emoji_animated: boolean;
|
||||
expires_at: Nullish<Date>;
|
||||
}
|
||||
|
||||
export interface GuildFolder {
|
||||
folder_id: number;
|
||||
name: Nullish<string>;
|
||||
color: Nullish<number>;
|
||||
flags: Nullish<number>;
|
||||
icon: Nullish<GuildFolderIcon>;
|
||||
guild_ids: Nullish<Array<GuildID>>;
|
||||
}
|
||||
|
||||
export interface UserSettingsRow {
|
||||
user_id: UserID;
|
||||
locale: LocaleCode;
|
||||
theme: string;
|
||||
status: string;
|
||||
status_resets_at: Nullish<Date>;
|
||||
status_resets_to: Nullish<string>;
|
||||
custom_status: Nullish<CustomStatus>;
|
||||
developer_mode: boolean;
|
||||
message_display_compact: boolean;
|
||||
animate_emoji: boolean;
|
||||
animate_stickers: number;
|
||||
gif_auto_play: boolean;
|
||||
render_embeds: boolean;
|
||||
render_reactions: boolean;
|
||||
render_spoilers: number;
|
||||
inline_attachment_media: boolean;
|
||||
inline_embed_media: boolean;
|
||||
explicit_content_filter: number;
|
||||
friend_source_flags: number;
|
||||
incoming_call_flags: number;
|
||||
group_dm_add_permission_flags: number;
|
||||
default_guilds_restricted: boolean;
|
||||
bot_default_guilds_restricted: boolean;
|
||||
restricted_guilds: Nullish<Set<GuildID>>;
|
||||
bot_restricted_guilds: Nullish<Set<GuildID>>;
|
||||
guild_positions: Nullish<Array<GuildID>>;
|
||||
guild_folders: Nullish<Array<GuildFolder>>;
|
||||
afk_timeout: Nullish<number>;
|
||||
time_format: Nullish<number>;
|
||||
trusted_domains: Nullish<Set<string>>;
|
||||
default_hide_muted_channels: Nullish<boolean>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface RelationshipRow {
|
||||
source_user_id: UserID;
|
||||
target_user_id: UserID;
|
||||
type: number;
|
||||
nickname: Nullish<string>;
|
||||
since: Nullish<Date>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface NoteRow {
|
||||
source_user_id: UserID;
|
||||
target_user_id: UserID;
|
||||
note: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface MuteConfig {
|
||||
end_time: Nullish<Date>;
|
||||
selected_time_window: Nullish<number>;
|
||||
}
|
||||
|
||||
export interface ChannelOverride {
|
||||
collapsed: boolean;
|
||||
message_notifications: Nullish<number>;
|
||||
muted: boolean;
|
||||
mute_config: Nullish<MuteConfig>;
|
||||
}
|
||||
|
||||
export interface UserGuildSettingsRow {
|
||||
user_id: UserID;
|
||||
guild_id: GuildID;
|
||||
message_notifications: Nullish<number>;
|
||||
muted: boolean;
|
||||
mute_config: Nullish<MuteConfig>;
|
||||
mobile_push: boolean;
|
||||
suppress_everyone: boolean;
|
||||
suppress_roles: boolean;
|
||||
hide_muted_channels: boolean;
|
||||
channel_overrides: Nullish<Map<ChannelID, ChannelOverride>>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface ExpressionPackRow {
|
||||
pack_id: GuildID;
|
||||
pack_type: string;
|
||||
creator_id: UserID;
|
||||
name: string;
|
||||
description: Nullish<string>;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface PackInstallationRow {
|
||||
user_id: UserID;
|
||||
pack_id: GuildID;
|
||||
pack_type: string;
|
||||
installed_at: Date;
|
||||
}
|
||||
|
||||
export interface SavedMessageRow {
|
||||
user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
message_id: MessageID;
|
||||
saved_at: Date;
|
||||
}
|
||||
|
||||
export const SAVED_MESSAGE_COLUMNS = [
|
||||
'user_id',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'saved_at',
|
||||
] as const satisfies ReadonlyArray<keyof SavedMessageRow>;
|
||||
|
||||
export interface ScheduledMessageRow {
|
||||
user_id: UserID;
|
||||
scheduled_message_id: MessageID;
|
||||
channel_id: ChannelID;
|
||||
payload: string;
|
||||
scheduled_at: Date;
|
||||
scheduled_local_at: string;
|
||||
timezone: string;
|
||||
status: string;
|
||||
status_reason: string | null;
|
||||
created_at: Date;
|
||||
invalidated_at: Date | null;
|
||||
}
|
||||
|
||||
export const SCHEDULED_MESSAGE_COLUMNS = [
|
||||
'user_id',
|
||||
'scheduled_message_id',
|
||||
'channel_id',
|
||||
'payload',
|
||||
'scheduled_at',
|
||||
'scheduled_local_at',
|
||||
'timezone',
|
||||
'status',
|
||||
'status_reason',
|
||||
'created_at',
|
||||
'invalidated_at',
|
||||
] as const satisfies ReadonlyArray<keyof ScheduledMessageRow>;
|
||||
|
||||
export interface FavoriteMemeRow {
|
||||
user_id: UserID;
|
||||
meme_id: MemeID;
|
||||
name: string;
|
||||
alt_text: Nullish<string>;
|
||||
tags: Nullish<Array<string>>;
|
||||
attachment_id: AttachmentID;
|
||||
filename: string;
|
||||
content_type: string;
|
||||
content_hash: Nullish<string>;
|
||||
size: bigint;
|
||||
width: Nullish<number>;
|
||||
height: Nullish<number>;
|
||||
duration: Nullish<number>;
|
||||
is_gifv: boolean;
|
||||
klipy_slug: Nullish<string>;
|
||||
tenor_id_str: Nullish<string>;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const FAVORITE_MEME_COLUMNS = [
|
||||
'user_id',
|
||||
'meme_id',
|
||||
'name',
|
||||
'alt_text',
|
||||
'tags',
|
||||
'attachment_id',
|
||||
'filename',
|
||||
'content_type',
|
||||
'content_hash',
|
||||
'size',
|
||||
'width',
|
||||
'height',
|
||||
'duration',
|
||||
'is_gifv',
|
||||
'klipy_slug',
|
||||
'tenor_id_str',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof FavoriteMemeRow>;
|
||||
|
||||
export interface RecentMentionRow {
|
||||
user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
message_id: MessageID;
|
||||
guild_id: GuildID;
|
||||
is_everyone: boolean;
|
||||
is_role: boolean;
|
||||
}
|
||||
|
||||
export const RECENT_MENTION_COLUMNS = [
|
||||
'user_id',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'guild_id',
|
||||
'is_everyone',
|
||||
'is_role',
|
||||
] as const satisfies ReadonlyArray<keyof RecentMentionRow>;
|
||||
|
||||
export interface UserHarvestRow {
|
||||
user_id: UserID;
|
||||
harvest_id: bigint;
|
||||
requested_at: Date;
|
||||
started_at: Nullish<Date>;
|
||||
completed_at: Nullish<Date>;
|
||||
failed_at: Nullish<Date>;
|
||||
storage_key: Nullish<string>;
|
||||
file_size: Nullish<bigint>;
|
||||
progress_percent: number;
|
||||
progress_step: Nullish<string>;
|
||||
error_message: Nullish<string>;
|
||||
download_url_expires_at: Nullish<Date>;
|
||||
}
|
||||
|
||||
export const USER_HARVEST_COLUMNS = [
|
||||
'user_id',
|
||||
'harvest_id',
|
||||
'requested_at',
|
||||
'started_at',
|
||||
'completed_at',
|
||||
'failed_at',
|
||||
'storage_key',
|
||||
'file_size',
|
||||
'progress_percent',
|
||||
'progress_step',
|
||||
'error_message',
|
||||
'download_url_expires_at',
|
||||
] as const satisfies ReadonlyArray<keyof UserHarvestRow>;
|
||||
|
||||
export interface PushSubscriptionRow {
|
||||
user_id: UserID;
|
||||
subscription_id: string;
|
||||
endpoint: string;
|
||||
p256dh_key: string;
|
||||
auth_key: string;
|
||||
user_agent: Nullish<string>;
|
||||
}
|
||||
|
||||
export const PUSH_SUBSCRIPTION_COLUMNS = [
|
||||
'user_id',
|
||||
'subscription_id',
|
||||
'endpoint',
|
||||
'p256dh_key',
|
||||
'auth_key',
|
||||
'user_agent',
|
||||
] as const satisfies ReadonlyArray<keyof PushSubscriptionRow>;
|
||||
|
||||
export interface UserContactChangeLogRow {
|
||||
user_id: UserID;
|
||||
event_id: types.TimeUuid;
|
||||
field: string;
|
||||
old_value: Nullish<string>;
|
||||
new_value: Nullish<string>;
|
||||
reason: string;
|
||||
actor_user_id: Nullish<UserID>;
|
||||
event_at: Date;
|
||||
}
|
||||
|
||||
export const USER_SETTINGS_COLUMNS = [
|
||||
'user_id',
|
||||
'locale',
|
||||
'theme',
|
||||
'status',
|
||||
'status_resets_at',
|
||||
'status_resets_to',
|
||||
'custom_status',
|
||||
'developer_mode',
|
||||
'message_display_compact',
|
||||
'animate_emoji',
|
||||
'animate_stickers',
|
||||
'gif_auto_play',
|
||||
'render_embeds',
|
||||
'render_reactions',
|
||||
'render_spoilers',
|
||||
'inline_attachment_media',
|
||||
'inline_embed_media',
|
||||
'explicit_content_filter',
|
||||
'friend_source_flags',
|
||||
'incoming_call_flags',
|
||||
'group_dm_add_permission_flags',
|
||||
'default_guilds_restricted',
|
||||
'bot_default_guilds_restricted',
|
||||
'restricted_guilds',
|
||||
'bot_restricted_guilds',
|
||||
'guild_positions',
|
||||
'guild_folders',
|
||||
'afk_timeout',
|
||||
'time_format',
|
||||
'trusted_domains',
|
||||
'default_hide_muted_channels',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof UserSettingsRow>;
|
||||
|
||||
export const EXPRESSION_PACK_COLUMNS = [
|
||||
'pack_id',
|
||||
'pack_type',
|
||||
'creator_id',
|
||||
'name',
|
||||
'description',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof ExpressionPackRow>;
|
||||
|
||||
export const USER_GUILD_SETTINGS_COLUMNS = [
|
||||
'user_id',
|
||||
'guild_id',
|
||||
'message_notifications',
|
||||
'muted',
|
||||
'mute_config',
|
||||
'mobile_push',
|
||||
'suppress_everyone',
|
||||
'suppress_roles',
|
||||
'hide_muted_channels',
|
||||
'channel_overrides',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof UserGuildSettingsRow>;
|
||||
|
||||
export const RELATIONSHIP_COLUMNS = [
|
||||
'source_user_id',
|
||||
'target_user_id',
|
||||
'type',
|
||||
'nickname',
|
||||
'since',
|
||||
'version',
|
||||
] as const satisfies ReadonlyArray<keyof RelationshipRow>;
|
||||
|
||||
export const NOTE_COLUMNS = ['source_user_id', 'target_user_id', 'note', 'version'] as const satisfies ReadonlyArray<
|
||||
keyof NoteRow
|
||||
>;
|
||||
|
||||
export const USER_CONTACT_CHANGE_LOG_COLUMNS = [
|
||||
'user_id',
|
||||
'event_id',
|
||||
'field',
|
||||
'old_value',
|
||||
'new_value',
|
||||
'reason',
|
||||
'actor_user_id',
|
||||
'event_at',
|
||||
] as const satisfies ReadonlyArray<keyof UserContactChangeLogRow>;
|
||||
|
||||
export interface UserByUsernameRow {
|
||||
username: string;
|
||||
discriminator: number;
|
||||
user_id: UserID;
|
||||
}
|
||||
|
||||
export interface UserByEmailRow {
|
||||
email_lower: string;
|
||||
user_id: UserID;
|
||||
}
|
||||
|
||||
export interface UserByPhoneRow {
|
||||
phone: string;
|
||||
user_id: UserID;
|
||||
}
|
||||
|
||||
export interface UserByStripeCustomerIdRow {
|
||||
stripe_customer_id: string;
|
||||
user_id: UserID;
|
||||
}
|
||||
|
||||
export interface UserByStripeSubscriptionIdRow {
|
||||
stripe_subscription_id: string;
|
||||
user_id: UserID;
|
||||
}
|
||||
|
||||
export const USER_BY_USERNAME_COLUMNS = ['username', 'discriminator', 'user_id'] as const satisfies ReadonlyArray<
|
||||
keyof UserByUsernameRow
|
||||
>;
|
||||
|
||||
export const USER_BY_EMAIL_COLUMNS = ['email_lower', 'user_id'] as const satisfies ReadonlyArray<keyof UserByEmailRow>;
|
||||
|
||||
export const USER_BY_PHONE_COLUMNS = ['phone', 'user_id'] as const satisfies ReadonlyArray<keyof UserByPhoneRow>;
|
||||
|
||||
export const USER_BY_STRIPE_CUSTOMER_ID_COLUMNS = ['stripe_customer_id', 'user_id'] as const satisfies ReadonlyArray<
|
||||
keyof UserByStripeCustomerIdRow
|
||||
>;
|
||||
|
||||
export const USER_BY_STRIPE_SUBSCRIPTION_ID_COLUMNS = [
|
||||
'stripe_subscription_id',
|
||||
'user_id',
|
||||
] as const satisfies ReadonlyArray<keyof UserByStripeSubscriptionIdRow>;
|
||||
|
||||
export interface UsersPendingDeletionRow {
|
||||
deletion_date: string;
|
||||
pending_deletion_at: Date;
|
||||
user_id: UserID;
|
||||
deletion_reason_code: number;
|
||||
}
|
||||
|
||||
export const USERS_PENDING_DELETION_COLUMNS = [
|
||||
'deletion_date',
|
||||
'pending_deletion_at',
|
||||
'user_id',
|
||||
'deletion_reason_code',
|
||||
] as const satisfies ReadonlyArray<keyof UsersPendingDeletionRow>;
|
||||
|
||||
export interface UserDmHistoryRow {
|
||||
user_id: UserID;
|
||||
channel_id: ChannelID;
|
||||
}
|
||||
|
||||
export const USER_DM_HISTORY_COLUMNS = ['user_id', 'channel_id'] as const satisfies ReadonlyArray<
|
||||
keyof UserDmHistoryRow
|
||||
>;
|
||||
78
fluxer/packages/api/src/database/types/VoiceTypes.tsx
Normal file
78
fluxer/packages/api/src/database/types/VoiceTypes.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface VoiceRegionRow {
|
||||
id: string;
|
||||
name: string;
|
||||
emoji: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
is_default: boolean | null;
|
||||
vip_only: boolean | null;
|
||||
required_guild_features: Set<string> | null;
|
||||
allowed_guild_ids: Set<bigint> | null;
|
||||
allowed_user_ids: Set<bigint> | null;
|
||||
created_at: Date | null;
|
||||
updated_at: Date | null;
|
||||
}
|
||||
|
||||
export const VOICE_REGION_COLUMNS = [
|
||||
'id',
|
||||
'name',
|
||||
'emoji',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'is_default',
|
||||
'vip_only',
|
||||
'required_guild_features',
|
||||
'allowed_guild_ids',
|
||||
'allowed_user_ids',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof VoiceRegionRow>;
|
||||
|
||||
export interface VoiceServerRow {
|
||||
region_id: string;
|
||||
server_id: string;
|
||||
endpoint: string;
|
||||
api_key: string;
|
||||
api_secret: string;
|
||||
is_active: boolean | null;
|
||||
vip_only: boolean | null;
|
||||
required_guild_features: Set<string> | null;
|
||||
allowed_guild_ids: Set<bigint> | null;
|
||||
allowed_user_ids: Set<bigint> | null;
|
||||
created_at: Date | null;
|
||||
updated_at: Date | null;
|
||||
}
|
||||
|
||||
export const VOICE_SERVER_COLUMNS = [
|
||||
'region_id',
|
||||
'server_id',
|
||||
'endpoint',
|
||||
'api_key',
|
||||
'api_secret',
|
||||
'is_active',
|
||||
'vip_only',
|
||||
'required_guild_features',
|
||||
'allowed_guild_ids',
|
||||
'allowed_user_ids',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
] as const satisfies ReadonlyArray<keyof VoiceServerRow>;
|
||||
Reference in New Issue
Block a user