feat: create model

This commit is contained in:
Justin Lin committed 2026-10-11 19:30:38 +11:00
1 parent ba5026fa56
commit 4ed8358738
14 files changed
+5033 -273

No files matched your search

+1
View File
@@ -123,6 +123,7 @@
"version": "0.0.0",
"dependencies": {
"@odyssey/constants": "workspace:*",
"@odyssey/database": "workspace:*",
"@odyssey/game": "workspace:*",
"@odyssey/models": "workspace:*",
"@odyssey/utils": "workspace:*",
+1 -1
View File
@@ -34,7 +34,7 @@ services:
networks:
- internal
ports:
- 5173:5173
- 5432:5432
volumes:
- ./postgres-data:/var/lib/postgresql
environment:
@@ -0,0 +1,7 @@
{
"from": null,
"to": "6fecb00f7a40489f8c1a9a4dad506cc6d4b95789cbb32519634132f006530c04",
"providedInvariants": [],
"createdAt": "2026-10-11T08:21:15.726Z",
"migrationHash": "99b3a1febb9f739bf258c99ebe1dbfe692b86792e8eb511fc7eef8e985e8e8cd"
}
@@ -0,0 +1,268 @@
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/6fecb00f7a40489f8c1a9a4dad506cc6d4b95789cbb32519634132f006530c04/contract';
import endContract from '../../snapshots/6fecb00f7a40489f8c1a9a4dad506cc6d4b95789cbb32519634132f006530c04/contract.json' with { type: 'json' };
import {
Migration,
MigrationCLI,
checkExpression,
col,
primaryKey,
} from '@prisma/orm-postgres/migration';
export default class M extends Migration<never, End> {
override readonly endContractJson = endContract;
override get operations() {
return [
this.createSchema({ schema: 'public' }),
this.createTable({
schema: 'public',
table: 'Command',
columns: [
col('command', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('error', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('id', 'BIGSERIAL', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
col('output', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('pwd', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('sessionId', 'int8', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
col('stage', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('timestamp', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
],
constraints: [primaryKey(['id'])],
}),
this.createTable({
schema: 'public',
table: 'LoginAttempt',
columns: [
col('id', 'BIGSERIAL', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
col('ip', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('loginMethod', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('message', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('success', 'bool', { notNull: true, codecRef: { codecId: 'pg/bool@1' } }),
col('time', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('userAgent', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('userId', 'int8', { codecRef: { codecId: 'pg/int8@1' } }),
col('username', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
],
constraints: [
primaryKey(['id']),
checkExpression(
'LoginAttempt_loginMethod_check_f8485f11',
`"loginMethod" IN ('password', 'google', 'github')`,
),
],
}),
this.createTable({
schema: 'public',
table: 'Session',
columns: [
col('completedEvents', 'text[]', {
notNull: true,
codecRef: { codecId: 'pg/text@1', many: true },
}),
col('containerId', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('containerName', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('createdAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('finishedAt', 'timestamptz', { codecRef: { codecId: 'pg/timestamptz-temporal@1' } }),
col('graph', 'jsonb', { notNull: true, codecRef: { codecId: 'pg/jsonb@1' } }),
col('id', 'BIGSERIAL', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
col('lastActivityAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('locale', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('quest', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('status', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('userId', 'int8', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
],
constraints: [
primaryKey(['id']),
checkExpression(
'Session_completedEvents_elem_not_null_b55d23f4',
'array_position("completedEvents", NULL) IS NULL',
),
checkExpression(
'Session_status_check_8fa5bbc6',
`"status" IN ('active', 'finished', 'inactive')`,
),
],
}),
this.createTable({
schema: 'public',
table: 'User',
columns: [
col('createdAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('email', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('id', 'BIGSERIAL', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
col('isGuest', 'bool', { notNull: true, codecRef: { codecId: 'pg/bool@1' } }),
col('name', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('updatedAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('username', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
],
constraints: [primaryKey(['id'])],
}),
this.createTable({
schema: 'public',
table: 'UserLoginMethod',
columns: [
col('createdAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('displayName', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('hashedPassword', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('oauthId', 'text', { codecRef: { codecId: 'pg/text@1' } }),
col('type', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('updatedAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('userId', 'int8', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
],
constraints: [
primaryKey(['userId', 'type']),
checkExpression(
'UserLoginMethod_type_check_6814314f',
`"type" IN ('password', 'google', 'github')`,
),
],
}),
this.createTable({
schema: 'public',
table: 'UserProgress',
columns: [
col('finishedAt', 'timestamptz', { codecRef: { codecId: 'pg/timestamptz-temporal@1' } }),
col('quest', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
col('startedAt', 'timestamptz', {
notNull: true,
codecRef: { codecId: 'pg/timestamptz-temporal@1' },
}),
col('userId', 'int8', { notNull: true, codecRef: { codecId: 'pg/int8@1' } }),
],
constraints: [primaryKey(['userId', 'quest'])],
}),
this.addUnique({
schema: 'public',
table: 'User',
constraint: 'User_email_key',
columns: ['email'],
}),
this.addUnique({
schema: 'public',
table: 'User',
constraint: 'User_username_key',
columns: ['username'],
}),
this.addUnique({
schema: 'public',
table: 'UserLoginMethod',
constraint: 'UserLoginMethod_type_oauthId_key',
columns: ['type', 'oauthId'],
}),
this.createIndex({
schema: 'public',
table: 'Command',
index: 'Command_sessionId_idx_29f415d4',
columns: ['sessionId'],
}),
this.createIndex({
schema: 'public',
table: 'LoginAttempt',
index: 'LoginAttempt_userId_idx_a489d58a',
columns: ['userId'],
}),
this.createIndex({
schema: 'public',
table: 'Session',
index: 'Session_userId_idx_a489d58a',
columns: ['userId'],
}),
this.createIndex({
schema: 'public',
table: 'Session',
index: 'Session_userId_quest_idx_b13626bf',
columns: ['userId', 'quest'],
}),
this.createIndex({
schema: 'public',
table: 'Session',
index: 'Session_userId_status_idx_e4a128ba',
columns: ['userId', 'status'],
}),
this.createIndex({
schema: 'public',
table: 'UserLoginMethod',
index: 'UserLoginMethod_userId_idx_a489d58a',
columns: ['userId'],
}),
this.createIndex({
schema: 'public',
table: 'UserProgress',
index: 'UserProgress_userId_idx_a489d58a',
columns: ['userId'],
}),
this.addForeignKey({
schema: 'public',
table: 'Command',
foreignKey: {
name: 'Command_sessionId_fkey',
columns: ['sessionId'],
references: { schema: 'public', table: 'Session', columns: ['id'] },
},
}),
this.addForeignKey({
schema: 'public',
table: 'LoginAttempt',
foreignKey: {
name: 'LoginAttempt_userId_fkey',
columns: ['userId'],
references: { schema: 'public', table: 'User', columns: ['id'] },
},
}),
this.addForeignKey({
schema: 'public',
table: 'Session',
foreignKey: {
name: 'Session_userId_fkey',
columns: ['userId'],
references: { schema: 'public', table: 'User', columns: ['id'] },
},
}),
this.addForeignKey({
schema: 'public',
table: 'UserLoginMethod',
foreignKey: {
name: 'UserLoginMethod_userId_fkey',
columns: ['userId'],
references: { schema: 'public', table: 'User', columns: ['id'] },
},
}),
this.addForeignKey({
schema: 'public',
table: 'UserProgress',
foreignKey: {
name: 'UserProgress_userId_fkey',
columns: ['userId'],
references: { schema: 'public', table: 'User', columns: ['id'] },
},
}),
];
}
}
MigrationCLI.run(import.meta.url, M);
@@ -0,0 +1,862 @@
[
{
"id": "schema.public",
"label": "Create schema \"public\"",
"operationClass": "additive",
"target": {
"id": "postgres"
},
"precheck": [],
"execute": [
{
"description": "Create schema \"public\"",
"sql": "CREATE SCHEMA IF NOT EXISTS \"public\"",
"params": []
}
],
"postcheck": []
},
{
"id": "table.Command",
"label": "Create table \"Command\"",
"summary": "Creates table \"Command\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "Command"
}
},
"precheck": [
{
"description": "ensure table \"Command\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Command\""
]
}
],
"execute": [
{
"description": "create table \"Command\"",
"sql": "CREATE TABLE \"public\".\"Command\" (\n \"command\" text NOT NULL,\n \"error\" text,\n \"id\" BIGSERIAL NOT NULL,\n \"output\" text,\n \"pwd\" text NOT NULL,\n \"sessionId\" int8 NOT NULL,\n \"stage\" text,\n \"timestamp\" timestamptz NOT NULL,\n PRIMARY KEY (\"id\")\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"Command\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Command\""
]
}
]
},
{
"id": "table.LoginAttempt",
"label": "Create table \"LoginAttempt\"",
"summary": "Creates table \"LoginAttempt\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "LoginAttempt"
}
},
"precheck": [
{
"description": "ensure table \"LoginAttempt\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"LoginAttempt\""
]
}
],
"execute": [
{
"description": "create table \"LoginAttempt\"",
"sql": "CREATE TABLE \"public\".\"LoginAttempt\" (\n \"id\" BIGSERIAL NOT NULL,\n \"ip\" text NOT NULL,\n \"loginMethod\" text NOT NULL,\n \"message\" text,\n \"success\" bool NOT NULL,\n \"time\" timestamptz NOT NULL,\n \"userAgent\" text NOT NULL,\n \"userId\" int8,\n \"username\" text NOT NULL,\n PRIMARY KEY (\"id\"),\n CONSTRAINT \"LoginAttempt_loginMethod_check_f8485f11\" CHECK (\"loginMethod\" IN ('password', 'google', 'github'))\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"LoginAttempt\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"LoginAttempt\""
]
}
]
},
{
"id": "table.Session",
"label": "Create table \"Session\"",
"summary": "Creates table \"Session\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "Session"
}
},
"precheck": [
{
"description": "ensure table \"Session\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Session\""
]
}
],
"execute": [
{
"description": "create table \"Session\"",
"sql": "CREATE TABLE \"public\".\"Session\" (\n \"completedEvents\" text[] NOT NULL,\n \"containerId\" text,\n \"containerName\" text,\n \"createdAt\" timestamptz NOT NULL,\n \"finishedAt\" timestamptz,\n \"graph\" jsonb NOT NULL,\n \"id\" BIGSERIAL NOT NULL,\n \"lastActivityAt\" timestamptz NOT NULL,\n \"locale\" text NOT NULL,\n \"quest\" text NOT NULL,\n \"status\" text NOT NULL,\n \"userId\" int8 NOT NULL,\n PRIMARY KEY (\"id\"),\n CONSTRAINT \"Session_completedEvents_elem_not_null_b55d23f4\" CHECK (array_position(\"completedEvents\", NULL) IS NULL),\n CONSTRAINT \"Session_status_check_8fa5bbc6\" CHECK (\"status\" IN ('active', 'finished', 'inactive'))\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"Session\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Session\""
]
}
]
},
{
"id": "table.User",
"label": "Create table \"User\"",
"summary": "Creates table \"User\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "User"
}
},
"precheck": [
{
"description": "ensure table \"User\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"User\""
]
}
],
"execute": [
{
"description": "create table \"User\"",
"sql": "CREATE TABLE \"public\".\"User\" (\n \"createdAt\" timestamptz NOT NULL,\n \"email\" text NOT NULL,\n \"id\" BIGSERIAL NOT NULL,\n \"isGuest\" bool NOT NULL,\n \"name\" text,\n \"updatedAt\" timestamptz NOT NULL,\n \"username\" text NOT NULL,\n PRIMARY KEY (\"id\")\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"User\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"User\""
]
}
]
},
{
"id": "table.UserLoginMethod",
"label": "Create table \"UserLoginMethod\"",
"summary": "Creates table \"UserLoginMethod\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "UserLoginMethod"
}
},
"precheck": [
{
"description": "ensure table \"UserLoginMethod\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"UserLoginMethod\""
]
}
],
"execute": [
{
"description": "create table \"UserLoginMethod\"",
"sql": "CREATE TABLE \"public\".\"UserLoginMethod\" (\n \"createdAt\" timestamptz NOT NULL,\n \"displayName\" text,\n \"hashedPassword\" text,\n \"oauthId\" text,\n \"type\" text NOT NULL,\n \"updatedAt\" timestamptz NOT NULL,\n \"userId\" int8 NOT NULL,\n PRIMARY KEY (\"userId\", \"type\"),\n CONSTRAINT \"UserLoginMethod_type_check_6814314f\" CHECK (\"type\" IN ('password', 'google', 'github'))\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"UserLoginMethod\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"UserLoginMethod\""
]
}
]
},
{
"id": "table.UserProgress",
"label": "Create table \"UserProgress\"",
"summary": "Creates table \"UserProgress\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "table",
"name": "UserProgress"
}
},
"precheck": [
{
"description": "ensure table \"UserProgress\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"UserProgress\""
]
}
],
"execute": [
{
"description": "create table \"UserProgress\"",
"sql": "CREATE TABLE \"public\".\"UserProgress\" (\n \"finishedAt\" timestamptz,\n \"quest\" text NOT NULL,\n \"startedAt\" timestamptz NOT NULL,\n \"userId\" int8 NOT NULL,\n PRIMARY KEY (\"userId\", \"quest\")\n)",
"params": []
}
],
"postcheck": [
{
"description": "verify table \"UserProgress\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"UserProgress\""
]
}
]
},
{
"id": "unique.User.User_email_key",
"label": "Add unique constraint on \"User\" (email)",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "unique",
"name": "User_email_key",
"table": "User"
}
},
"precheck": [
{
"description": "ensure constraint \"User_email_key\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"User_email_key",
"public",
"\"public\".\"User\""
]
}
],
"execute": [
{
"description": "add unique constraint \"User_email_key\"",
"sql": "ALTER TABLE \"public\".\"User\" ADD CONSTRAINT \"User_email_key\" UNIQUE (\"email\")"
}
],
"postcheck": [
{
"description": "verify constraint \"User_email_key\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"User_email_key",
"public",
"\"public\".\"User\""
]
}
]
},
{
"id": "unique.User.User_username_key",
"label": "Add unique constraint on \"User\" (username)",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "unique",
"name": "User_username_key",
"table": "User"
}
},
"precheck": [
{
"description": "ensure constraint \"User_username_key\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"User_username_key",
"public",
"\"public\".\"User\""
]
}
],
"execute": [
{
"description": "add unique constraint \"User_username_key\"",
"sql": "ALTER TABLE \"public\".\"User\" ADD CONSTRAINT \"User_username_key\" UNIQUE (\"username\")"
}
],
"postcheck": [
{
"description": "verify constraint \"User_username_key\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"User_username_key",
"public",
"\"public\".\"User\""
]
}
]
},
{
"id": "unique.UserLoginMethod.UserLoginMethod_type_oauthId_key",
"label": "Add unique constraint on \"UserLoginMethod\" (type, oauthId)",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "unique",
"name": "UserLoginMethod_type_oauthId_key",
"table": "UserLoginMethod"
}
},
"precheck": [
{
"description": "ensure constraint \"UserLoginMethod_type_oauthId_key\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserLoginMethod_type_oauthId_key",
"public",
"\"public\".\"UserLoginMethod\""
]
}
],
"execute": [
{
"description": "add unique constraint \"UserLoginMethod_type_oauthId_key\"",
"sql": "ALTER TABLE \"public\".\"UserLoginMethod\" ADD CONSTRAINT \"UserLoginMethod_type_oauthId_key\" UNIQUE (\"type\", \"oauthId\")"
}
],
"postcheck": [
{
"description": "verify constraint \"UserLoginMethod_type_oauthId_key\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserLoginMethod_type_oauthId_key",
"public",
"\"public\".\"UserLoginMethod\""
]
}
]
},
{
"id": "index.Command.Command_sessionId_idx_29f415d4",
"label": "Create index \"Command_sessionId_idx_29f415d4\" on \"Command\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "Command_sessionId_idx_29f415d4",
"table": "Command"
}
},
"precheck": [
{
"description": "ensure index \"Command_sessionId_idx_29f415d4\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Command_sessionId_idx_29f415d4\""
]
}
],
"execute": [
{
"description": "create index \"Command_sessionId_idx_29f415d4\"",
"sql": "CREATE INDEX \"Command_sessionId_idx_29f415d4\" ON \"public\".\"Command\" (\"sessionId\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"Command_sessionId_idx_29f415d4\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Command_sessionId_idx_29f415d4\""
]
}
]
},
{
"id": "index.LoginAttempt.LoginAttempt_userId_idx_a489d58a",
"label": "Create index \"LoginAttempt_userId_idx_a489d58a\" on \"LoginAttempt\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "LoginAttempt_userId_idx_a489d58a",
"table": "LoginAttempt"
}
},
"precheck": [
{
"description": "ensure index \"LoginAttempt_userId_idx_a489d58a\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"LoginAttempt_userId_idx_a489d58a\""
]
}
],
"execute": [
{
"description": "create index \"LoginAttempt_userId_idx_a489d58a\"",
"sql": "CREATE INDEX \"LoginAttempt_userId_idx_a489d58a\" ON \"public\".\"LoginAttempt\" (\"userId\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"LoginAttempt_userId_idx_a489d58a\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"LoginAttempt_userId_idx_a489d58a\""
]
}
]
},
{
"id": "index.Session.Session_userId_idx_a489d58a",
"label": "Create index \"Session_userId_idx_a489d58a\" on \"Session\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "Session_userId_idx_a489d58a",
"table": "Session"
}
},
"precheck": [
{
"description": "ensure index \"Session_userId_idx_a489d58a\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_idx_a489d58a\""
]
}
],
"execute": [
{
"description": "create index \"Session_userId_idx_a489d58a\"",
"sql": "CREATE INDEX \"Session_userId_idx_a489d58a\" ON \"public\".\"Session\" (\"userId\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"Session_userId_idx_a489d58a\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_idx_a489d58a\""
]
}
]
},
{
"id": "index.Session.Session_userId_quest_idx_b13626bf",
"label": "Create index \"Session_userId_quest_idx_b13626bf\" on \"Session\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "Session_userId_quest_idx_b13626bf",
"table": "Session"
}
},
"precheck": [
{
"description": "ensure index \"Session_userId_quest_idx_b13626bf\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_quest_idx_b13626bf\""
]
}
],
"execute": [
{
"description": "create index \"Session_userId_quest_idx_b13626bf\"",
"sql": "CREATE INDEX \"Session_userId_quest_idx_b13626bf\" ON \"public\".\"Session\" (\"userId\", \"quest\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"Session_userId_quest_idx_b13626bf\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_quest_idx_b13626bf\""
]
}
]
},
{
"id": "index.Session.Session_userId_status_idx_e4a128ba",
"label": "Create index \"Session_userId_status_idx_e4a128ba\" on \"Session\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "Session_userId_status_idx_e4a128ba",
"table": "Session"
}
},
"precheck": [
{
"description": "ensure index \"Session_userId_status_idx_e4a128ba\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_status_idx_e4a128ba\""
]
}
],
"execute": [
{
"description": "create index \"Session_userId_status_idx_e4a128ba\"",
"sql": "CREATE INDEX \"Session_userId_status_idx_e4a128ba\" ON \"public\".\"Session\" (\"userId\", \"status\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"Session_userId_status_idx_e4a128ba\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"Session_userId_status_idx_e4a128ba\""
]
}
]
},
{
"id": "index.UserLoginMethod.UserLoginMethod_userId_idx_a489d58a",
"label": "Create index \"UserLoginMethod_userId_idx_a489d58a\" on \"UserLoginMethod\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "UserLoginMethod_userId_idx_a489d58a",
"table": "UserLoginMethod"
}
},
"precheck": [
{
"description": "ensure index \"UserLoginMethod_userId_idx_a489d58a\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"UserLoginMethod_userId_idx_a489d58a\""
]
}
],
"execute": [
{
"description": "create index \"UserLoginMethod_userId_idx_a489d58a\"",
"sql": "CREATE INDEX \"UserLoginMethod_userId_idx_a489d58a\" ON \"public\".\"UserLoginMethod\" (\"userId\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"UserLoginMethod_userId_idx_a489d58a\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"UserLoginMethod_userId_idx_a489d58a\""
]
}
]
},
{
"id": "index.UserProgress.UserProgress_userId_idx_a489d58a",
"label": "Create index \"UserProgress_userId_idx_a489d58a\" on \"UserProgress\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "index",
"name": "UserProgress_userId_idx_a489d58a",
"table": "UserProgress"
}
},
"precheck": [
{
"description": "ensure index \"UserProgress_userId_idx_a489d58a\" does not exist",
"sql": "SELECT (to_regclass($1)) IS NULL AS \"result\"",
"params": [
"\"public\".\"UserProgress_userId_idx_a489d58a\""
]
}
],
"execute": [
{
"description": "create index \"UserProgress_userId_idx_a489d58a\"",
"sql": "CREATE INDEX \"UserProgress_userId_idx_a489d58a\" ON \"public\".\"UserProgress\" (\"userId\")",
"params": []
}
],
"postcheck": [
{
"description": "verify index \"UserProgress_userId_idx_a489d58a\" exists",
"sql": "SELECT (to_regclass($1)) IS NOT NULL AS \"result\"",
"params": [
"\"public\".\"UserProgress_userId_idx_a489d58a\""
]
}
]
},
{
"id": "foreignKey.Command.Command_sessionId_fkey",
"label": "Add foreign key \"Command_sessionId_fkey\" on \"Command\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "foreignKey",
"name": "Command_sessionId_fkey",
"table": "Command"
}
},
"precheck": [
{
"description": "ensure FK \"Command_sessionId_fkey\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"Command_sessionId_fkey",
"public",
"\"public\".\"Command\""
]
}
],
"execute": [
{
"description": "add FK \"Command_sessionId_fkey\"",
"sql": "ALTER TABLE \"public\".\"Command\"\nADD CONSTRAINT \"Command_sessionId_fkey\"\nFOREIGN KEY (\"sessionId\")\nREFERENCES \"public\".\"Session\" (\"id\")"
}
],
"postcheck": [
{
"description": "verify FK \"Command_sessionId_fkey\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"Command_sessionId_fkey",
"public",
"\"public\".\"Command\""
]
}
]
},
{
"id": "foreignKey.LoginAttempt.LoginAttempt_userId_fkey",
"label": "Add foreign key \"LoginAttempt_userId_fkey\" on \"LoginAttempt\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "foreignKey",
"name": "LoginAttempt_userId_fkey",
"table": "LoginAttempt"
}
},
"precheck": [
{
"description": "ensure FK \"LoginAttempt_userId_fkey\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"LoginAttempt_userId_fkey",
"public",
"\"public\".\"LoginAttempt\""
]
}
],
"execute": [
{
"description": "add FK \"LoginAttempt_userId_fkey\"",
"sql": "ALTER TABLE \"public\".\"LoginAttempt\"\nADD CONSTRAINT \"LoginAttempt_userId_fkey\"\nFOREIGN KEY (\"userId\")\nREFERENCES \"public\".\"User\" (\"id\")"
}
],
"postcheck": [
{
"description": "verify FK \"LoginAttempt_userId_fkey\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"LoginAttempt_userId_fkey",
"public",
"\"public\".\"LoginAttempt\""
]
}
]
},
{
"id": "foreignKey.Session.Session_userId_fkey",
"label": "Add foreign key \"Session_userId_fkey\" on \"Session\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "foreignKey",
"name": "Session_userId_fkey",
"table": "Session"
}
},
"precheck": [
{
"description": "ensure FK \"Session_userId_fkey\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"Session_userId_fkey",
"public",
"\"public\".\"Session\""
]
}
],
"execute": [
{
"description": "add FK \"Session_userId_fkey\"",
"sql": "ALTER TABLE \"public\".\"Session\"\nADD CONSTRAINT \"Session_userId_fkey\"\nFOREIGN KEY (\"userId\")\nREFERENCES \"public\".\"User\" (\"id\")"
}
],
"postcheck": [
{
"description": "verify FK \"Session_userId_fkey\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"Session_userId_fkey",
"public",
"\"public\".\"Session\""
]
}
]
},
{
"id": "foreignKey.UserLoginMethod.UserLoginMethod_userId_fkey",
"label": "Add foreign key \"UserLoginMethod_userId_fkey\" on \"UserLoginMethod\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "foreignKey",
"name": "UserLoginMethod_userId_fkey",
"table": "UserLoginMethod"
}
},
"precheck": [
{
"description": "ensure FK \"UserLoginMethod_userId_fkey\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserLoginMethod_userId_fkey",
"public",
"\"public\".\"UserLoginMethod\""
]
}
],
"execute": [
{
"description": "add FK \"UserLoginMethod_userId_fkey\"",
"sql": "ALTER TABLE \"public\".\"UserLoginMethod\"\nADD CONSTRAINT \"UserLoginMethod_userId_fkey\"\nFOREIGN KEY (\"userId\")\nREFERENCES \"public\".\"User\" (\"id\")"
}
],
"postcheck": [
{
"description": "verify FK \"UserLoginMethod_userId_fkey\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserLoginMethod_userId_fkey",
"public",
"\"public\".\"UserLoginMethod\""
]
}
]
},
{
"id": "foreignKey.UserProgress.UserProgress_userId_fkey",
"label": "Add foreign key \"UserProgress_userId_fkey\" on \"UserProgress\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "public",
"objectType": "foreignKey",
"name": "UserProgress_userId_fkey",
"table": "UserProgress"
}
},
"precheck": [
{
"description": "ensure FK \"UserProgress_userId_fkey\" does not exist",
"sql": "SELECT NOT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserProgress_userId_fkey",
"public",
"\"public\".\"UserProgress\""
]
}
],
"execute": [
{
"description": "add FK \"UserProgress_userId_fkey\"",
"sql": "ALTER TABLE \"public\".\"UserProgress\"\nADD CONSTRAINT \"UserProgress_userId_fkey\"\nFOREIGN KEY (\"userId\")\nREFERENCES \"public\".\"User\" (\"id\")"
}
],
"postcheck": [
{
"description": "verify FK \"UserProgress_userId_fkey\" exists",
"sql": "SELECT EXISTS (SELECT 1 AS \"one\" FROM \"pg_constraint\" AS \"c\" INNER JOIN \"pg_namespace\" AS \"n\" ON \"n\".\"oid\" = \"c\".\"connamespace\" WHERE (\"c\".\"conname\" = $1 AND \"n\".\"nspname\" = $2 AND \"c\".\"conrelid\" = to_regclass($3))) AS \"result\"",
"params": [
"UserProgress_userId_fkey",
"public",
"\"public\".\"UserProgress\""
]
}
]
}
]
@@ -0,0 +1 @@
{"_generated":{"message":"This file is automatically generated by \"prisma contract emit\".","regenerate":"To regenerate, run: prisma contract emit","warning":"⚠️ GENERATED FILE - DO NOT EDIT"},"capabilities":{"postgres":{"distinctOn":true,"forKeyShare":true,"forNoKeyUpdate":true,"jsonAgg":true,"lateral":true,"limit":true,"orderBy":true,"returning":true},"sql":{"checkConstraint":true,"defaultInInsert":true,"enums":true,"forShare":true,"forUpdate":true,"insertOnConflictSkip":true,"insertOnConflictWithoutTarget":true,"lateral":true,"lockNowait":true,"lockOf":true,"lockSkipLocked":true,"returning":true,"scalarList":true}},"domain":{"namespaces":{"public":{"enum":{"LoginMethod":{"codecId":"pg/text@1","members":[{"name":"Password","value":"password"},{"name":"Google","value":"google"},{"name":"GitHub","value":"github"}]},"SessionStatus":{"codecId":"pg/text@1","members":[{"name":"Active","value":"active"},{"name":"Finished","value":"finished"},{"name":"Inactive","value":"inactive"}]}},"models":{"Command":{"fields":{"command":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"error":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"id":{"nullable":false,"type":{"codecId":"pg/int8@1","kind":"scalar"}},"output":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"pwd":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"sessionId":{"nullable":false,"type":{"codecId":"pg/int8@1","kind":"scalar"}},"stage":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"timestamp":{"nullable":false,"type":{"codecId":"pg/timestamptz-temporal@1","kind":"scalar"}}},"relations":{"session":{"cardinality":"N:1","nullable":false,"on":{"localFields":["sessionId"],"targetFields":["id"]},"to":{"model":"Session","namespace":"public"}}},"storage":{"fields":{"command":{"column":"command"},"error":{"column":"error"},"id":{"column":"id"},"output":{"column":"output"},"pwd":{"column":"pwd"},"sessionId":{"column":"sessionId"},"stage":{"column":"stage"},"timestamp":{"column":"timestamp"}},"namespaceId":"public","table":"Command"}},"LoginAttempt":{"fields":{"id":{"nullable":false,"type":{"codecId":"pg/int8@1","kind":"scalar"}},"ip":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"loginMethod":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"},"valueSet":{"entityKind":"enum","entityName":"LoginMethod","namespaceId":"public","plane":"domain"}},"message":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"success":{"nullable":false,"type":{"codecId":"pg/bool@1","kind":"scalar"}},"time":{"nullable":false,"type":{"codecId":"pg/timestamptz-temporal@1","kind":"scalar"}},"userAgent":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"userId":{"nullable":true,"type":{"codecId":"pg/int8@1","kind":"scalar"}},"username":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}}},"relations":{"user":{"cardinality":"N:1","nullable":true,"on":{"localFields":["userId"],"targetFields":["id"]},"to":{"model":"User","namespace":"public"}}},"storage":{"fields":{"id":{"column":"id"},"ip":{"column":"ip"},"loginMethod":{"column":"loginMethod"},"message":{"column":"message"},"success":{"column":"success"},"time":{"column":"time"},"userAgent":{"column":"userAgent"},"userId":{"column":"userId"},"username":{"column":"username"}},"namespaceId":"public","table":"LoginAttempt"}},"Session":{"fields":{"completedEvents":{"many":{"elementNullable":false},"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"containerId":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"containerName":{"nullable":true,"type":{"codecId":"pg/text@1","kind":"scalar"}},"createdAt":{"nullable":false,"type":{"codecId":"pg/timestamptz-temporal@1","kind":"scalar"}},"finishedAt":{"nullable":true,"type":{"codecId":"pg/timestamptz-temporal@1","kind":"scalar"}},"graph":{"nullable":false,"type":{"codecId":"pg/jsonb@1","kind":"scalar"}},"id":{"nullable":false,"type":{"codecId":"pg/int8@1","kind":"scalar"}},"lastActivityAt":{"nullable":false,"type":{"codecId":"pg/timestamptz-temporal@1","kind":"scalar"}},"locale":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"quest":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"}},"status":{"nullable":false,"type":{"codecId":"pg/text@1","kind":"scalar"},"valueSet":{"entityKind":"enum","entityName":"SessionStatus","namespaceId":"public","plane":"domain"}},"userId":{"nullable":false,"type":{"codecId":"pg/int8@1","kind":"scalar"}}},"relations":{"commands":{"cardinality":"1:N","on":{"localFields":["id"],"targetFields":["sessionId"]},"to":{"model":"Command","namespace":"public"}},"user":{"cardinality":"N:1","nullable":false,"on":{"localFields":["userId"],"targetFields":["id"]},"to":{"model":"User","namespace":"public"}}},"storage":{"fields":{"completedEvents":{"column":"completedEvents"},"containerId":{"column":"containerId"},"containerName":{"column":"containerName"},"createdAt":{Line truncated
+2
View File
@@ -1 +1,3 @@
export { db } from './prisma/db'
console.log('Hello via Bun!')
+1076 -144
View File
File diff suppressed because it is too large. Load diff
+1101 -107
View File
File diff suppressed because it is too large. Load diff
+97 -16
View File
@@ -1,21 +1,102 @@
// use prisma-8
model User {
id Int @id @default(autoincrement())
email String @unique
username String?
name String?
posts Post[]
createdAt TimestamptzString @default(now())
updatedAt temporal.updatedAtString()
id BigInt @id @default(autoincrement())
email String @unique
username String @unique
name String?
createdAt DateTime
updatedAt DateTime
isGuest Boolean
loginMethods UserLoginMethod[]
progress UserProgress[]
sessions Session[]
loginAttempts LoginAttempt[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt TimestamptzString @default(now())
updatedAt temporal.updatedAtString()
enum LoginMethod {
@@type("pg/text@1")
Password = "password"
Google = "google"
GitHub = "github"
}
// User login using one of the login method
model UserLoginMethod {
type LoginMethod
userId BigInt
createdAt DateTime
updatedAt DateTime
hashedPassword String?
oauthId String?
displayName String?
@@id([userId, type])
@@unique([type, oauthId])
user User @relation(fields: [userId], references: [id])
}
// Store what quest a user has completed
model UserProgress {
userId BigInt
quest String
startedAt DateTime
finishedAt DateTime?
user User @relation(fields: [userId], references: [id])
@@id([userId, quest])
}
enum SessionStatus {
@@type("pg/text@1")
Active = "active"
Finished = "finished"
Inactive = "inactive"
}
model Session {
id BigInt @id @default(autoincrement())
userId BigInt
quest String
locale String
containerId String?
containerName String?
status SessionStatus
createdAt DateTime
lastActivityAt DateTime
finishedAt DateTime?
completedEvents String[]
graph Jsonb
user User @relation(fields: [userId], references: [id])
commands Command[]
@@index([userId, quest])
@@index([userId, status])
}
model Command {
id BigInt @id @default(autoincrement())
sessionId BigInt
timestamp DateTime
pwd String
command String
output String?
error String?
stage String?
session Session @relation(fields: [sessionId], references: [id])
@@index([sessionId])
}
model LoginAttempt {
id BigInt @id @default(autoincrement())
username String
userId BigInt?
ip String
loginMethod LoginMethod
userAgent String
time DateTime
success Boolean
message String?
user User? @relation(fields: [userId], references: [id])
}
+5 -5
View File
@@ -1,9 +1,9 @@
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };
import 'dotenv/config'
import postgres from '@prisma/orm-postgres/runtime'
import type { Contract } from './contract.d'
import contractJson from './contract.json' with { type: 'json' }
export const db = postgres<Contract>({
contractJson,
url: process.env['DATABASE_URL']!,
});
})
+1
View File
@@ -15,6 +15,7 @@
"@odyssey/game": "workspace:*",
"@odyssey/models": "workspace:*",
"@odyssey/utils": "workspace:*",
"@odyssey/database": "workspace:*",
"@trpc/server": "^11.8.0",
"bcrypt": "^5.1.1",
"commander": "^11.0.0",
+2
View File
@@ -6,6 +6,7 @@ import swaggerUI from 'swagger-ui-express'
import passport from 'passport'
import * as trpcExpress from '@trpc/server/adapters/express'
import { connectDB } from '@odyssey/models'
import { db } from '@odyssey/database'
import './auth/passport.js'
import socketServer from './api/socket.js'
@@ -22,6 +23,7 @@ import { appRouter } from './routers/index.js'
import { createContext } from './trpc.js'
async function main() {
console.log(db)
if (!config.secret) {
logger.error(
'No SECRET_KEY found in .env! To set up a persistent key, please run `bun run setup`:'