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", "version": "0.0.0",
"dependencies": { "dependencies": {
"@odyssey/constants": "workspace:*", "@odyssey/constants": "workspace:*",
"@odyssey/database": "workspace:*",
"@odyssey/game": "workspace:*", "@odyssey/game": "workspace:*",
"@odyssey/models": "workspace:*", "@odyssey/models": "workspace:*",
"@odyssey/utils": "workspace:*", "@odyssey/utils": "workspace:*",
+1 -1
View File
@@ -34,7 +34,7 @@ services:
networks: networks:
- internal - internal
ports: ports:
- 5173:5173 - 5432:5432
volumes: volumes:
- ./postgres-data:/var/lib/postgresql - ./postgres-data:/var/lib/postgresql
environment: 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!') 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 // use prisma-8
model User { model User {
id Int @id @default(autoincrement()) id BigInt @id @default(autoincrement())
email String @unique email String @unique
username String? username String @unique
name String? name String?
posts Post[] createdAt DateTime
createdAt TimestamptzString @default(now()) updatedAt DateTime
updatedAt temporal.updatedAtString() isGuest Boolean
loginMethods UserLoginMethod[]
progress UserProgress[]
sessions Session[]
loginAttempts LoginAttempt[]
} }
model Post { enum LoginMethod {
id Int @id @default(autoincrement()) @@type("pg/text@1")
title String Password = "password"
content String? Google = "google"
author User @relation(fields: [authorId], references: [id]) GitHub = "github"
authorId Int }
createdAt TimestamptzString @default(now())
updatedAt temporal.updatedAtString() // 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 'dotenv/config'
import postgres from '@prisma/orm-postgres/runtime'; import postgres from '@prisma/orm-postgres/runtime'
import type { Contract } from './contract.d'; import type { Contract } from './contract.d'
import contractJson from './contract.json' with { type: 'json' }; import contractJson from './contract.json' with { type: 'json' }
export const db = postgres<Contract>({ export const db = postgres<Contract>({
contractJson, contractJson,
url: process.env['DATABASE_URL']!, url: process.env['DATABASE_URL']!,
}); })
+1
View File
@@ -15,6 +15,7 @@
"@odyssey/game": "workspace:*", "@odyssey/game": "workspace:*",
"@odyssey/models": "workspace:*", "@odyssey/models": "workspace:*",
"@odyssey/utils": "workspace:*", "@odyssey/utils": "workspace:*",
"@odyssey/database": "workspace:*",
"@trpc/server": "^11.8.0", "@trpc/server": "^11.8.0",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"commander": "^11.0.0", "commander": "^11.0.0",
+2
View File
@@ -6,6 +6,7 @@ import swaggerUI from 'swagger-ui-express'
import passport from 'passport' import passport from 'passport'
import * as trpcExpress from '@trpc/server/adapters/express' import * as trpcExpress from '@trpc/server/adapters/express'
import { connectDB } from '@odyssey/models' import { connectDB } from '@odyssey/models'
import { db } from '@odyssey/database'
import './auth/passport.js' import './auth/passport.js'
import socketServer from './api/socket.js' import socketServer from './api/socket.js'
@@ -22,6 +23,7 @@ import { appRouter } from './routers/index.js'
import { createContext } from './trpc.js' import { createContext } from './trpc.js'
async function main() { async function main() {
console.log(db)
if (!config.secret) { if (!config.secret) {
logger.error( logger.error(
'No SECRET_KEY found in .env! To set up a persistent key, please run `bun run setup`:' 'No SECRET_KEY found in .env! To set up a persistent key, please run `bun run setup`:'