feature: db agnostic + base tables

This commit is contained in:
jubnl
2026-04-26 23:22:06 +02:00
parent 499097fa3c
commit 249ab217f8
235 changed files with 190331 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
# compiled output
/dist
/node_modules
/build
# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# temp directory
.temp
.tmp
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+4
View File
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}
+98
View File
@@ -0,0 +1,98 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Project setup
```bash
$ npm install
```
## Compile and run the project
```bash
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
```
## Run tests
```bash
# unit tests
$ npm run test
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
```
## Deployment
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
```bash
$ npm install -g @nestjs/mau
$ mau deploy
```
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
## Resources
Check out a few resources that may come in handy when working with NestJS:
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## Stay in touch
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
## License
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
+35
View File
@@ -0,0 +1,35 @@
// @ts-check
import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
eslintPluginPrettierRecommended,
{
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
sourceType: 'commonjs',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
},
);
+8
View File
@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
+11956
View File
File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
{
"name": "server-nest-2",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@better-auth/oauth-provider": "^1.6.9",
"@better-auth/passkey": "^1.6.9",
"@hedystia/better-auth-typeorm": "^0.8.2",
"@nestjs/common": "^11.1.19",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^11.1.19",
"@nestjs/platform-express": "^11.1.19",
"@nestjs/platform-socket.io": "^11.1.19",
"@nestjs/throttler": "^6.5.0",
"@nestjs/typeorm": "^11.0.1",
"@nestjs/websockets": "^11.1.19",
"@thallesp/nestjs-better-auth": "^2.6.0",
"better-auth": "^1.6.9",
"better-sqlite3": "^12.9.0",
"csrf-csrf": "^4.0.3",
"helmet": "^8.1.0",
"mysql2": "^3.22.2",
"pg": "^8.20.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"typeorm": "^0.3.28"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^24.0.0",
"@types/supertest": "^7.0.0",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^17.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
+46
View File
@@ -0,0 +1,46 @@
import authConfig from './config/auth.config.js';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module.js';
type SupportedDbType = 'mysql' | 'mariadb' | 'postgres' | 'sqlite';
function resolveDriver(type: SupportedDbType) {
switch (type) {
case 'mysql':
case 'mariadb':
return require('mysql2');
case 'postgres':
return require('pg');
case 'sqlite':
return require('better-sqlite3');
}
}
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, load: [authConfig] }),
AuthModule,
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => {
const type = config.get<SupportedDbType>('DB_TYPE', 'sqlite');
return {
type,
driver: resolveDriver(type),
host: config.get<string>('DB_HOST', 'localhost'),
port: config.get<number>('DB_PORT', 5432),
username: config.get<string>('DB_USER', 'usr'),
password: config.get<string>('DB_PASS', 'pwd'),
database: config.get<string>('DB_NAME', 'data/travel.db'),
autoLoadEntities: true,
synchronize: config.get<string>('NODE_ENV') !== 'production',
};
},
inject: [ConfigService],
}),
],
})
export class AppModule {}
+20
View File
@@ -0,0 +1,20 @@
import { betterAuth } from 'better-auth';
import { typeormAdapter } from '@hedystia/better-auth-typeorm';
import { DataSource } from 'typeorm';
import { AuthConfig } from '../config/auth.config.js';
export function createAuth(dataSource: DataSource, cfg: AuthConfig) {
return betterAuth({
database: typeormAdapter(dataSource, { debugLogs: cfg.debugLogs }),
secret: cfg.secret,
baseURL: cfg.baseURL,
basePath: '/api/auth',
trustedOrigins: cfg.frontendUrl ? [cfg.frontendUrl] : [],
advanced: {
cookies: { session_token: { name: 'trek_session' } },
useSecureCookies: cfg.cookieSecure,
},
emailAndPassword: { enabled: true },
plugins: [],
});
}
+39
View File
@@ -0,0 +1,39 @@
import { betterAuth } from 'better-auth';
import { typeormAdapter } from '@hedystia/better-auth-typeorm';
import { magicLink } from 'better-auth/plugins/magic-link';
import { genericOAuth } from 'better-auth/plugins/generic-oauth';
import { jwt } from 'better-auth/plugins/jwt';
import { oauthProvider } from '@better-auth/oauth-provider';
import { passkey } from '@better-auth/passkey';
import { DataSource } from 'typeorm';
// Used only by `npx @better-auth/cli generate`.
// Not imported at runtime — auth.factory.ts uses the DI DataSource.
const dataSource = new DataSource({
type: 'better-sqlite3',
database: ':memory:',
});
export const auth = betterAuth({
baseURL: 'http://localhost:3000',
database: typeormAdapter(dataSource, {
entitiesDir: './src/models/entities/auth',
migrationsDir: './src/database/migrations',
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
sendVerificationEmail: async () => {},
sendResetPassword: async () => {},
},
emailVerification: {
sendVerificationEmail: async () => {},
},
plugins: [
jwt(),
magicLink({ sendMagicLink: async () => {} }),
genericOAuth({ config: [] }),
oauthProvider({ loginPage: '/login' }),
passkey(),
],
});
+43
View File
@@ -0,0 +1,43 @@
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule as BetterAuthNestModule } from '@thallesp/nestjs-better-auth';
import { DataSource } from 'typeorm';
import { createAuth } from './auth.factory.js';
import { AuthConfig } from '../config/auth.config.js';
import { User } from '../models/entities/auth/User.js';
import { Account } from '../models/entities/auth/Account.js';
import { Session } from '../models/entities/auth/Session.js';
import { Verification } from '../models/entities/auth/Verification.js';
import { Passkey } from '../models/entities/auth/Passkey.js';
import { Jwks } from '../models/entities/auth/Jwks.js';
import { OauthClient } from '../models/entities/auth/OauthClient.js';
import { OauthAccessToken } from '../models/entities/auth/OauthAccessToken.js';
import { OauthRefreshToken } from '../models/entities/auth/OauthRefreshToken.js';
import { OauthConsent } from '../models/entities/auth/OauthConsent.js';
@Module({
imports: [
TypeOrmModule.forFeature([
User,
Account,
Session,
Verification,
Passkey,
Jwks,
OauthClient,
OauthAccessToken,
OauthRefreshToken,
OauthConsent,
]),
BetterAuthNestModule.forRootAsync({
imports: [ConfigModule],
inject: [DataSource, ConfigService],
useFactory: (ds: DataSource, config: ConfigService) => ({
auth: createAuth(ds, config.get<AuthConfig>('auth')!),
}),
}),
],
exports: [BetterAuthNestModule],
})
export class AuthModule {}
+26
View File
@@ -0,0 +1,26 @@
import { registerAs } from '@nestjs/config';
import { boolean } from 'better-auth';
export interface AuthConfig {
secret: string;
baseURL: string;
frontendUrl: string | undefined;
cookieSecure: boolean;
debugLogs: boolean;
}
export default registerAs(
'auth',
(): AuthConfig => ({
secret: process.env.BETTER_AUTH_SECRET ?? 'changeme',
baseURL: process.env.BETTER_AUTH_URL ?? 'http://localhost:3000',
frontendUrl: process.env.BASE_URL,
cookieSecure:
process.env.COOKIE_SECURE === 'true' &&
process.env.NODE_ENV === 'production' &&
process.env.BASE_URL?.startsWith('https') === true,
debugLogs:
process.env.BETTER_AUTH_DEBUG_LOGS === 'true' ||
process.env.NODE_ENV === 'development',
}),
);
@@ -0,0 +1,103 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -0,0 +1,79 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -0,0 +1,58 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -0,0 +1,59 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -0,0 +1,103 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -0,0 +1,112 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthAccessToken',
new TableIndex({
name: 'oauthAccessToken_clientId_idx',
columnNames: ['clientId'],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthApplication',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'oauthAccessToken',
new TableIndex({
name: 'oauthAccessToken_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -0,0 +1,104 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthApplication1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthApplication',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'redirectUrls',
type: 'text',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthApplication',
new TableIndex({
name: 'oauthApplication_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthApplication',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthApplication');
}
}
@@ -0,0 +1,95 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'consentGiven',
type: 'boolean',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthConsent',
new TableIndex({
name: 'oauthConsent_clientId_idx',
columnNames: ['clientId'],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthApplication',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'oauthConsent',
new TableIndex({
name: 'oauthConsent_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -0,0 +1,99 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -0,0 +1,79 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -0,0 +1,58 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -0,0 +1,59 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -0,0 +1,103 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -0,0 +1,113 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -0,0 +1,184 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -0,0 +1,77 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -0,0 +1,106 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -0,0 +1,99 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -0,0 +1,79 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -0,0 +1,58 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -0,0 +1,59 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -0,0 +1,103 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -0,0 +1,46 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateJwks1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'jwks',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'privateKey',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('jwks');
}
}
@@ -0,0 +1,113 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -0,0 +1,184 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -0,0 +1,77 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -0,0 +1,106 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -0,0 +1,99 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -0,0 +1,79 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -0,0 +1,58 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -0,0 +1,59 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -0,0 +1,103 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -0,0 +1,46 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateJwks1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'jwks',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'privateKey',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('jwks');
}
}
@@ -0,0 +1,113 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -0,0 +1,184 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -0,0 +1,77 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -0,0 +1,106 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -0,0 +1,99 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -0,0 +1,79 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -0,0 +1,58 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -0,0 +1,59 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
+8
View File
@@ -0,0 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bodyParser: false });
await app.listen(process.env.PORT ?? 3001);
}
bootstrap();
@@ -0,0 +1,34 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('bucket_list')
export class BucketList extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'lat', nullable: true })
lat: number | null;
@Column({ name: 'lng', nullable: true })
lng: number | null;
@Column({ name: 'country_code', nullable: true })
countryCode: string | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column({
name: 'target_date',
nullable: true,
default: null,
})
targetDate: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.bucketLists, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,15 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('visited_countries')
export class VisitedCountries extends IntBaseEntity {
@Column('text', { name: 'country_code' })
countryCode: string;
@ManyToOne(() => SqliteUsers, (users) => users.visitedCountries, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,22 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_visited_regions_country', ['countryCode'], {})
@Entity('visited_regions')
export class VisitedRegions extends IntBaseEntity {
@Column({ name: 'region_code' })
regionCode: string;
@Column({ name: 'region_name' })
regionName: string;
@Column({ name: 'country_code' })
countryCode: string;
@ManyToOne(() => SqliteUsers, (users) => users.visitedRegions, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,59 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('account')
export class Account {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'accountId' })
accountId: string;
@Column('text', { name: 'providerId' })
providerId: string;
@Index('account_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Column('text', { name: 'accessToken', nullable: true })
accessToken: string | null;
@Column('text', { name: 'refreshToken', nullable: true })
refreshToken: string | null;
@Column('text', { name: 'idToken', nullable: true })
idToken: string | null;
@Column({ type: 'timestamp', name: 'accessTokenExpiresAt', nullable: true })
accessTokenExpiresAt: Date | null;
@Column({ type: 'timestamp', name: 'refreshTokenExpiresAt', nullable: true })
refreshTokenExpiresAt: Date | null;
@Column('text', { name: 'scope', nullable: true })
scope: string | null;
@Column('text', { name: 'password', nullable: true })
password: string | null;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -0,0 +1,22 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('jwks')
export class Jwks {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'publicKey' })
publicKey: string;
@Column('text', { name: 'privateKey' })
privateKey: string;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
}
@@ -0,0 +1,57 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { OauthRefreshToken } from './OauthRefreshToken';
import { Session } from './Session';
import { User } from './User';
@Entity('oauthAccessToken')
export class OauthAccessToken {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'token', nullable: true, unique: true })
token: string | null;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'sessionId', nullable: true })
sessionId: string | null;
@ManyToOne(() => Session, { onDelete: 'SET NULL', nullable: true })
@JoinColumn({ name: 'sessionId', referencedColumnName: 'id' })
session?: Session;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'refreshId', nullable: true })
refreshId: string | null;
@ManyToOne(() => OauthRefreshToken, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'refreshId', referencedColumnName: 'id' })
refresh?: OauthRefreshToken;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column('text', { name: 'scopes' })
scopes: string;
}
@@ -0,0 +1,56 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('oauthApplication')
export class OauthApplication {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'icon', nullable: true })
icon: string | null;
@Column('text', { name: 'metadata', nullable: true })
metadata: string | null;
@Column('text', { name: 'clientId', nullable: true, unique: true })
clientId: string | null;
@Column('text', { name: 'clientSecret', nullable: true })
clientSecret: string | null;
@Column('text', { name: 'redirectUrls', nullable: true })
redirectUrls: string | null;
@Column('text', { name: 'type', nullable: true })
type: string | null;
@Column('boolean', { name: 'disabled', nullable: true, default: false })
disabled: boolean | null;
@Index('oauthApplication_userId_idx')
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
}
@@ -0,0 +1,102 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { User } from './User';
@Entity('oauthClient')
export class OauthClient {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'clientId', unique: true })
clientId: string;
@Column('text', { name: 'clientSecret', nullable: true })
clientSecret: string | null;
@Column('boolean', { name: 'disabled', nullable: true, default: false })
disabled: boolean | null;
@Column('boolean', { name: 'skipConsent', nullable: true })
skipConsent: boolean | null;
@Column('boolean', { name: 'enableEndSession', nullable: true })
enableEndSession: boolean | null;
@Column('text', { name: 'subjectType', nullable: true })
subjectType: string | null;
@Column('text', { name: 'scopes', nullable: true })
scopes: string | null;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'uri', nullable: true })
uri: string | null;
@Column('text', { name: 'icon', nullable: true })
icon: string | null;
@Column('text', { name: 'contacts', nullable: true })
contacts: string | null;
@Column('text', { name: 'tos', nullable: true })
tos: string | null;
@Column('text', { name: 'policy', nullable: true })
policy: string | null;
@Column('text', { name: 'softwareId', nullable: true })
softwareId: string | null;
@Column('text', { name: 'softwareVersion', nullable: true })
softwareVersion: string | null;
@Column('text', { name: 'softwareStatement', nullable: true })
softwareStatement: string | null;
@Column('text', { name: 'redirectUris' })
redirectUris: string;
@Column('text', { name: 'postLogoutRedirectUris', nullable: true })
postLogoutRedirectUris: string | null;
@Column('text', { name: 'tokenEndpointAuthMethod', nullable: true })
tokenEndpointAuthMethod: string | null;
@Column('text', { name: 'grantTypes', nullable: true })
grantTypes: string | null;
@Column('text', { name: 'responseTypes', nullable: true })
responseTypes: string | null;
@Column('boolean', { name: 'public', nullable: true })
public: boolean | null;
@Column('text', { name: 'type', nullable: true })
type: string | null;
@Column('boolean', { name: 'requirePKCE', nullable: true })
requirePKCE: boolean | null;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'metadata', nullable: true })
metadata: string | null;
}
@@ -0,0 +1,38 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { User } from './User';
@Entity('oauthConsent')
export class OauthConsent {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'scopes' })
scopes: string;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
}
@@ -0,0 +1,55 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { Session } from './Session';
import { User } from './User';
@Entity('oauthRefreshToken')
export class OauthRefreshToken {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'token', unique: true })
token: string;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'sessionId', nullable: true })
sessionId: string | null;
@ManyToOne(() => Session, { onDelete: 'SET NULL', nullable: true })
@JoinColumn({ name: 'sessionId', referencedColumnName: 'id' })
session?: Session;
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'revoked', nullable: true })
revoked: Date | null;
@Column({ type: 'timestamp', name: 'authTime', nullable: true })
authTime: Date | null;
@Column('text', { name: 'scopes' })
scopes: string;
}
@@ -0,0 +1,54 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('passkey')
export class Passkey {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'publicKey' })
publicKey: string;
@Index('passkey_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Index('passkey_credentialID_idx')
@Column('text', { name: 'credentialID' })
credentialID: string;
@Column('integer', { name: 'counter' })
counter: number;
@Column('text', { name: 'deviceType' })
deviceType: string;
@Column('boolean', { name: 'backedUp' })
backedUp: boolean;
@Column('text', { name: 'transports', nullable: true })
transports: string | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column('text', { name: 'aaguid', nullable: true })
aaguid: string | null;
}
@@ -0,0 +1,44 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('session')
export class Session {
@PrimaryColumn('text')
id: string;
@Column({ type: 'timestamp', name: 'expiresAt' })
expiresAt: Date;
@Column('text', { name: 'token', unique: true })
token: string;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
@Column('text', { name: 'ipAddress', nullable: true })
ipAddress: string | null;
@Column('text', { name: 'userAgent', nullable: true })
userAgent: string | null;
@Index('session_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
}
@@ -0,0 +1,28 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('user')
export class User {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name' })
name: string;
@Column('text', { name: 'email', unique: true })
email: string;
@Column('boolean', { name: 'emailVerified', default: false })
emailVerified: boolean;
@Column('text', { name: 'image', nullable: true })
image: string | null;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -0,0 +1,26 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
@Entity('verification')
export class Verification {
@PrimaryColumn('text')
id: string;
@Index('verification_identifier_idx')
@Column('text', { name: 'identifier' })
identifier: string;
@Column('text', { name: 'value' })
value: string;
@Column({ type: 'timestamp', name: 'expiresAt' })
expiresAt: Date;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -0,0 +1,62 @@
import {
Column,
CreateDateColumn,
DeleteDateColumn,
PrimaryColumn,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
// Layer 1 — timestamps only, always present
export abstract class TimestampedEntity {
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
export abstract class TimestampedSortableEntity extends TimestampedEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 2 — adds soft delete
export abstract class SoftDeletableEntity extends TimestampedEntity {
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt: Date | null;
}
// Layer 3a — adds integer PK to timestamped entity
export abstract class IntBaseEntity extends TimestampedEntity {
@PrimaryGeneratedColumn()
id: number;
}
export abstract class IntSortableBaseEntity extends IntBaseEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 3b — adds integer PK + soft delete
export abstract class SoftDeletableIntBaseEntity extends SoftDeletableEntity {
@PrimaryGeneratedColumn()
id: number;
}
// Layer 3c — natural/business string PK (e.g. country code, slug)
export abstract class StringBaseEntity extends TimestampedEntity {
@PrimaryColumn({ name: 'id' })
id: string;
}
export abstract class StringSortableBaseEntity extends StringBaseEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 3d — natural string PK + soft delete
export abstract class SoftDeletableStringBaseEntity extends SoftDeletableEntity {
@PrimaryColumn({ name: 'id' })
id: string;
}
@@ -0,0 +1,25 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_mcp_tokens_hash', ['tokenHash'], { unique: true })
@Entity('mcp_tokens')
export class McpTokens extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'token_hash', unique: true })
tokenHash: string;
@Column({ name: 'token_prefix' })
tokenPrefix: string;
@Column({ name: 'last_used_at', nullable: true })
lastUsedAt: Date | null;
@ManyToOne(() => SqliteUsers, (users) => users.mcpTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,35 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_ncp_user', ['userId'], {})
@Entity('notification_channel_preferences')
export class NotificationChannelPreferences {
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'event_type' })
eventType: string;
@PrimaryColumn({ name: 'channel' })
channel: string;
@Column({ name: 'enabled', default: true })
enabled: boolean;
@ManyToOne(
() => SqliteUsers,
(users) => users.notificationChannelPreferences,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,81 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_notifications_target_scope', ['target', 'scope'], {})
@Index('idx_notifications_recipient_created', ['recipientId', 'createdAt'], {})
@Index(
'idx_notifications_recipient',
['recipientId', 'isRead', 'createdAt'],
{},
)
@Entity('notifications')
export class Notifications extends IntBaseEntity {
@Column({ name: 'type' })
type: string;
@Column({ name: 'scope' })
scope: string;
@Column('int', { name: 'target' })
target: number;
@Column('int', { name: 'recipient_id' })
recipientId: number;
@Column({ name: 'title_key' })
titleKey: string;
@Column('simple-json', {
name: 'title_params',
nullable: true,
default: {},
})
titleParams: Record<string, unknown> | null;
@Column({ name: 'text_key' })
textKey: string;
@Column('simple-json', {
name: 'text_params',
nullable: true,
default: {},
})
textParams: Record<string, unknown> | null;
@Column({ name: 'positive_text_key', nullable: true })
positiveTextKey: string | null;
@Column({ name: 'negative_text_key', nullable: true })
negativeTextKey: string | null;
@Column({ name: 'positive_callback', nullable: true })
positiveCallback: string | null;
@Column({ name: 'negative_callback', nullable: true })
negativeCallback: string | null;
@Column({ name: 'response', nullable: true })
response: string | null;
@Column({ name: 'navigate_text_key', nullable: true })
navigateTextKey: string | null;
@Column({ name: 'navigate_target', nullable: true })
navigateTarget: string | null;
@Column({ name: 'is_read', nullable: true, default: false })
isRead: boolean | null;
@ManyToOne(() => SqliteUsers, (users) => users.notifications, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'recipient_id', referencedColumnName: 'id' }])
recipient: SqliteUsers;
@ManyToOne(() => SqliteUsers, (users) => users.notifications2, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'sender_id', referencedColumnName: 'id' }])
sender: SqliteUsers;
}
@@ -0,0 +1,53 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { OldOauthConsents } from './OldOauthConsents';
import { OldOauthTokens } from './OldOauthTokens';
import { SqliteUsers } from './SqliteUsers';
import { StringBaseEntity } from '../base/BaseEntity';
@Index('idx_oauth_clients_client_id', ['clientId'], { unique: true })
@Index('idx_oauth_clients_user', ['userId'], {})
@Entity('oauth_clients')
export class OldOauthClients extends StringBaseEntity {
@Column('int', { name: 'user_id', nullable: true })
userId: number | null;
@Column({ name: 'name' })
name: string;
@Column({ name: 'client_id', unique: true })
clientId: string;
@Column({ name: 'client_secret_hash' })
clientSecretHash: string;
@Column('simple-array', { name: 'redirect_uris', default: [] })
redirectUris: string[];
@Column('simple-array', { name: 'allowed_scopes', default: [] })
allowedScopes: string[];
@Column({ name: 'is_public', default: false })
isPublic: boolean;
@Column({ name: 'created_via', default: 'settings_ui' })
createdVia: string;
@OneToMany(() => OldOauthConsents, (oauthConsents) => oauthConsents.client)
oauthConsents: OldOauthConsents[];
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.client)
oauthTokens: OldOauthTokens[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthClients, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,26 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { OldOauthClients } from './OldOauthClients';
import { IntBaseEntity } from '../base/BaseEntity';
@Entity('oauth_consents')
export class OldOauthConsents extends IntBaseEntity {
@Column('simple-array', { name: 'scopes', default: [] })
scopes: string[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthConsents, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => OldOauthClients,
(oauthClients) => oauthClients.oauthConsents,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'client_id', referencedColumnName: 'clientId' }])
client: OldOauthClients;
}
@@ -0,0 +1,68 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { OldOauthClients } from './OldOauthClients';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_oauth_tokens_parent', ['parentTokenId'], {})
@Index('idx_oauth_tokens_refresh', ['refreshTokenHash'], { unique: true })
@Index('idx_oauth_tokens_access', ['accessTokenHash'], { unique: true })
@Index('idx_oauth_tokens_user', ['userId'], {})
@Entity('oauth_tokens')
export class OldOauthTokens extends IntBaseEntity {
@Column('int', { name: 'user_id' })
userId: number;
@Column({ name: 'access_token_hash', unique: true })
accessTokenHash: string;
@Column({ name: 'refresh_token_hash', unique: true })
refreshTokenHash: string;
@Column('simple-array', { name: 'scopes', default: [] })
scopes: string[];
@Column('datetime', { name: 'access_token_expires_at' })
accessTokenExpiresAt: Date;
@Column('datetime', { name: 'refresh_token_expires_at' })
refreshTokenExpiresAt: Date;
@Column('datetime', { name: 'revoked_at', nullable: true })
revokedAt: Date | null;
@Column('int', { name: 'parent_token_id', nullable: true })
parentTokenId: number | null;
@Column({ name: 'audience', nullable: true })
audience: string | null;
@ManyToOne(() => OldOauthTokens, (oauthTokens) => oauthTokens.oauthTokens)
@JoinColumn([{ name: 'parent_token_id', referencedColumnName: 'id' }])
parentToken: OldOauthTokens;
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.parentToken)
oauthTokens: OldOauthTokens[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => OldOauthClients,
(oauthClients) => oauthClients.oauthTokens,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'client_id', referencedColumnName: 'clientId' }])
client: OldOauthClients;
}
@@ -0,0 +1,29 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_prt_hash', ['tokenHash'], {})
@Index('idx_prt_user', ['userId'], {})
@Entity('password_reset_tokens')
export class OldPasswordResetTokens extends IntBaseEntity {
@Column('int', { name: 'user_id' })
userId: number;
@Column({ name: 'token_hash', unique: true })
tokenHash: string;
@Column({ name: 'expires_at' })
expiresAt: Date;
@Column({ name: 'consumed_at', nullable: true })
consumedAt: Date | null;
@Column({ name: 'created_ip', nullable: true })
createdIp: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.passwordResetTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,341 @@
import {
Column,
Entity,
Index,
JoinTable,
ManyToMany,
OneToMany,
OneToOne,
} from 'typeorm';
import { OldPasswordResetTokens } from './OldPasswordResetTokens';
import { IntBaseEntity } from '../base/BaseEntity';
import { Settings } from '../system/Settings';
import { Trips } from '../trip/Trips';
import { Categories } from '../trip/Categories';
import { Tags } from '../trip/Tags';
import { TripFiles } from '../trip/files/TripFiles';
import { BudgetItems } from '../trip/budget/BudgetItems';
import { VacayPlans } from '../vacay/VacayPlans';
import { TripMembers } from '../trip/TripMembers';
import { VacayPlanMembers } from '../vacay/VacayPlanMembers';
import { VacayUserColors } from '../vacay/VacayUserColors';
import { VacayUserYears } from '../vacay/VacayUserYears';
import { VacayEntries } from '../vacay/VacayEntries';
import { CollabNotes } from '../trip/collab/CollabNotes';
import { CollabPolls } from '../trip/collab/CollabPolls';
import { CollabPollVotes } from '../trip/collab/CollabPollVotes';
import { CollabMessages } from '../trip/collab/CollabMessages';
import { AssignmentParticipants } from '../trip/AssignmentParticipants';
import { AuditLog } from '../system/AuditLog';
import { Notifications } from '../notification/Notifications';
import { NotificationChannelPreferences } from '../notification/NotificationChannelPreferences';
import { BudgetItemMembers } from '../trip/budget/BudgetItemMembers';
import { CollabMessageReactions } from '../trip/collab/CollabMessageReactions';
import { InviteTokens } from '../system/InviteTokens';
import { PackingCategoryAssignees } from '../trip/lists/PackingCategoryAssignees';
import { PackingTemplates } from '../trip/lists/PackingTemplates';
import { PackingBags } from '../trip/lists/PackingBags';
import { VisitedCountries } from '../atlas/VisitedCountries';
import { BucketList } from '../atlas/BucketList';
import { ShareTokens } from '../trip/ShareTokens';
import { McpTokens } from '../mcp/McpTokens';
import { TripAlbumLinks } from '../trip/journey/TripAlbumLinks';
import { TodoItems } from '../trip/lists/TodoItems';
import { TodoCategoryAssignees } from '../trip/lists/TodoCategoryAssignees';
import { VisitedRegions } from '../atlas/VisitedRegions';
import { OldOauthConsents } from './OldOauthConsents';
import { OldOauthTokens } from './OldOauthTokens';
import { Journeys } from '../trip/journey/Journeys';
import { JourneyEntries } from '../trip/journey/JourneyEntries';
import { JourneyContributors } from '../trip/journey/JourneyContributors';
import { JourneyShareTokens } from '../trip/journey/JourneyShareTokens';
import { TrekPhotos } from '../trip/journey/TrekPhotos';
import { TripPhotos } from '../trip/TripPhotos';
import { UserNoticeDismissals } from '../system/UserNoticeDismissals';
import { IdempotencyKeys } from '../system/IdempotencyKeys';
import { OldOauthClients } from './OldOauthClients';
@Index('idx_users_email', ['email'], {})
@Entity('users')
export class SqliteUsers extends IntBaseEntity {
@Column({ name: 'username', unique: true })
username: string;
@Column({ name: 'email', unique: true })
email: string;
@Column({ name: 'password_hash' })
passwordHash: string;
@Column({ name: 'role', default: 'user' })
role: string;
@Column({ name: 'maps_api_key', nullable: true })
mapsApiKey: string | null;
@Column({ name: 'unsplash_api_key', nullable: true })
unsplashApiKey: string | null;
@Column({ name: 'openweather_api_key', nullable: true })
openweatherApiKey: string | null;
@Column({ name: 'avatar', nullable: true })
avatar: string | null;
@Column({ name: 'oidc_sub', nullable: true })
oidcSub: string | null;
@Column({ name: 'oidc_issuer', nullable: true })
oidcIssuer: string | null;
@Column({ name: 'last_login', nullable: true })
lastLogin: Date | null;
@Column({
name: 'mfa_enabled',
default: false,
})
mfaEnabled: boolean;
@Column({ name: 'mfa_secret', nullable: true })
mfaSecret: string | null;
@Column({ name: 'mfa_backup_codes', nullable: true })
mfaBackupCodes: string | null;
@Column({ name: 'immich_url', nullable: true })
immichUrl: string | null;
@Column({ name: 'immich_access_token', nullable: true })
immichAccessToken: string | null;
@Column({ name: 'synology_url', nullable: true })
synologyUrl: string | null;
@Column({ name: 'synology_username', nullable: true })
synologyUsername: string | null;
@Column({ name: 'synology_password', nullable: true })
synologyPassword: string | null;
@Column({ name: 'synology_sid', nullable: true })
synologySid: string | null;
@Column({
name: 'must_change_password',
default: false,
})
mustChangePassword: boolean;
@Column('int', { name: 'password_version', default: 0 })
passwordVersion: number;
@Column({ name: 'immich_api_key', nullable: true })
immichApiKey: string | null;
@Column({ name: 'synology_skip_ssl', default: false })
synologySkipSsl: boolean;
@Column({ name: 'synology_did', nullable: true })
synologyDid: string | null;
@Column('text', { name: 'first_seen_version', default: '0.0.0' })
firstSeenVersion: string;
@Column('int', { name: 'login_count', default: 0 })
loginCount: number;
@Column({ name: 'immich_auto_upload', default: false })
immichAutoUpload: boolean;
@OneToMany(
() => OldPasswordResetTokens,
(passwordResetTokens) => passwordResetTokens.user,
)
passwordResetTokens: OldPasswordResetTokens[];
@OneToMany(() => Settings, (settings) => settings.user)
settings: Settings[];
@OneToMany(() => Trips, (trips) => trips.user)
trips: Trips[];
@OneToMany(() => Categories, (categories) => categories.user)
categories: Categories[];
@OneToMany(() => Tags, (tags) => tags.user)
tags: Tags[];
@OneToMany(() => TripFiles, (tripFiles) => tripFiles.uploadedBy)
tripFiles: TripFiles[];
@OneToMany(() => TripMembers, (tripMembers) => tripMembers.invitedBy)
tripMembers: TripMembers[];
@OneToMany(() => TripMembers, (tripMembers) => tripMembers.user)
tripMembers2: TripMembers[];
@OneToMany(() => BudgetItems, (budgetItems) => budgetItems.paidByUser)
budgetItems: BudgetItems[];
@OneToOne(() => VacayPlans, (vacayPlans) => vacayPlans.owner)
vacayPlans: VacayPlans;
@OneToMany(
() => VacayPlanMembers,
(vacayPlanMembers) => vacayPlanMembers.user,
)
vacayPlanMembers: VacayPlanMembers[];
@OneToMany(() => VacayUserColors, (vacayUserColors) => vacayUserColors.user)
vacayUserColors: VacayUserColors[];
@OneToMany(() => VacayUserYears, (vacayUserYears) => vacayUserYears.user)
vacayUserYears: VacayUserYears[];
@OneToMany(() => VacayEntries, (vacayEntries) => vacayEntries.user)
vacayEntries: VacayEntries[];
@OneToMany(() => CollabNotes, (collabNotes) => collabNotes.user)
collabNotes: CollabNotes[];
@OneToMany(() => CollabPolls, (collabPolls) => collabPolls.user)
collabPolls: CollabPolls[];
@OneToMany(() => CollabPollVotes, (collabPollVotes) => collabPollVotes.user)
collabPollVotes: CollabPollVotes[];
@OneToMany(() => CollabMessages, (collabMessages) => collabMessages.user)
collabMessages: CollabMessages[];
@OneToMany(
() => AssignmentParticipants,
(assignmentParticipants) => assignmentParticipants.user,
)
assignmentParticipants: AssignmentParticipants[];
@OneToMany(() => AuditLog, (auditLog) => auditLog.user)
auditLogs: AuditLog[];
@OneToMany(() => Notifications, (notifications) => notifications.recipient)
notifications: Notifications[];
@OneToMany(() => Notifications, (notifications) => notifications.sender)
notifications2: Notifications[];
@OneToMany(
() => NotificationChannelPreferences,
(notificationChannelPreferences) => notificationChannelPreferences.user,
)
notificationChannelPreferences: NotificationChannelPreferences[];
@OneToMany(
() => BudgetItemMembers,
(budgetItemMembers) => budgetItemMembers.user,
)
budgetItemMembers: BudgetItemMembers[];
@OneToMany(
() => CollabMessageReactions,
(collabMessageReactions) => collabMessageReactions.user,
)
collabMessageReactions: CollabMessageReactions[];
@OneToMany(() => InviteTokens, (inviteTokens) => inviteTokens.createdBy)
inviteTokens: InviteTokens[];
@OneToMany(
() => PackingCategoryAssignees,
(packingCategoryAssignees) => packingCategoryAssignees.user,
)
packingCategoryAssignees: PackingCategoryAssignees[];
@OneToMany(
() => PackingTemplates,
(packingTemplates) => packingTemplates.createdBy,
)
packingTemplates: PackingTemplates[];
@OneToMany(() => PackingBags, (packingBags) => packingBags.user)
packingBags: PackingBags[];
@OneToMany(
() => VisitedCountries,
(visitedCountries) => visitedCountries.user,
)
visitedCountries: VisitedCountries[];
@OneToMany(() => BucketList, (bucketList) => bucketList.user)
bucketLists: BucketList[];
@OneToMany(() => ShareTokens, (shareTokens) => shareTokens.createdBy)
shareTokens: ShareTokens[];
@OneToMany(() => McpTokens, (mcpTokens) => mcpTokens.user)
mcpTokens: McpTokens[];
@OneToMany(() => TripAlbumLinks, (tripAlbumLinks) => tripAlbumLinks.user)
tripAlbumLinks: TripAlbumLinks[];
@OneToMany(() => TodoItems, (todoItems) => todoItems.assignedUser)
todoItems: TodoItems[];
@OneToMany(
() => TodoCategoryAssignees,
(todoCategoryAssignees) => todoCategoryAssignees.user,
)
todoCategoryAssignees: TodoCategoryAssignees[];
@OneToMany(() => VisitedRegions, (visitedRegions) => visitedRegions.user)
visitedRegions: VisitedRegions[];
@ManyToMany(() => PackingBags, (packingBags) => packingBags.users)
@JoinTable({
name: 'packing_bag_members',
joinColumns: [{ name: 'user_id', referencedColumnName: 'id' }],
inverseJoinColumns: [{ name: 'bag_id', referencedColumnName: 'id' }],
})
packingBags2: PackingBags[];
@OneToMany(() => OldOauthConsents, (oauthConsents) => oauthConsents.user)
oauthConsents: OldOauthConsents[];
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.user)
oauthTokens: OldOauthTokens[];
@OneToMany(() => Journeys, (journeys) => journeys.user)
journeys: Journeys[];
@OneToMany(() => JourneyEntries, (journeyEntries) => journeyEntries.author)
journeyEntries: JourneyEntries[];
@OneToMany(
() => JourneyContributors,
(journeyContributors) => journeyContributors.user,
)
journeyContributors: JourneyContributors[];
@OneToMany(
() => JourneyShareTokens,
(journeyShareTokens) => journeyShareTokens.createdBy,
)
journeyShareTokens: JourneyShareTokens[];
@OneToMany(() => TrekPhotos, (trekPhotos) => trekPhotos.owner)
trekPhotos: TrekPhotos[];
@OneToMany(() => TripPhotos, (tripPhotos) => tripPhotos.user)
tripPhotos: TripPhotos[];
@OneToMany(
() => UserNoticeDismissals,
(userNoticeDismissals) => userNoticeDismissals.user,
)
userNoticeDismissals: UserNoticeDismissals[];
@OneToMany(() => IdempotencyKeys, (idempotencyKeys) => idempotencyKeys.user)
idempotencyKeys: IdempotencyKeys[];
@OneToMany(() => OldOauthClients, (oauthClients) => oauthClients.user)
oauthClients: OldOauthClients[];
}
@@ -0,0 +1,23 @@
import { Column, Entity } from 'typeorm';
import { StringSortableBaseEntity } from '../base/BaseEntity';
@Entity('addons')
export class Addons extends StringSortableBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'description', nullable: true })
description: string | null;
@Column({ name: 'type', default: 'global' })
type: string;
@Column({ name: 'icon', default: 'Puzzle' })
icon: string | null;
@Column('int', { name: 'enabled', default: 0 })
enabled: number;
@Column('simple-json', { name: 'config', nullable: true, default: null })
config: Record<string, unknown> | null;
}
@@ -0,0 +1,10 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('app_settings')
export class AppSettings {
@PrimaryColumn({ name: 'key' })
declare id: string;
@Column({ name: 'value', nullable: true })
value: string | null;
}
@@ -0,0 +1,25 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_audit_log_created', ['createdAt'], {})
@Entity('audit_log')
export class AuditLog extends IntBaseEntity {
@Column({ name: 'action' })
action: string;
@Column({ name: 'resource', nullable: true })
resource: string | null;
@Column('simple-json', { name: 'details', nullable: true })
details: Record<string, unknown> | null;
@Column({ name: 'ip', nullable: true })
ip: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.auditLogs, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,35 @@
import { Entity, JoinColumn, ManyToOne } from 'typeorm';
import { Places } from '../trip/Places';
import { Reservations } from '../trip/reservation/Reservations';
import { TripFiles } from '../trip/files/TripFiles';
import { IntBaseEntity } from '../base/BaseEntity';
import { DayAssignments } from '../trip/DayAssignments';
@Entity('file_links')
export class FileLinks extends IntBaseEntity {
@ManyToOne(() => Places, (places) => places.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(
() => DayAssignments,
(dayAssignments) => dayAssignments.fileLinks,
{ onDelete: 'CASCADE' },
)
@JoinColumn([{ name: 'assignment_id', referencedColumnName: 'id' }])
assignment: DayAssignments;
@ManyToOne(() => Reservations, (reservations) => reservations.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'reservation_id', referencedColumnName: 'id' }])
reservation: Reservations;
@ManyToOne(() => TripFiles, (tripFiles) => tripFiles.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'file_id', referencedColumnName: 'id' }])
file: TripFiles;
}
@@ -0,0 +1,38 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_idempotency_keys_created', ['createdAt'], {})
@Entity('idempotency_keys')
export class IdempotencyKeys extends TimestampedEntity {
@PrimaryColumn({ name: 'key' })
key: string;
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'method' })
method: string;
@PrimaryColumn('text', { name: 'path' })
path: string;
@Column('int', { name: 'status_code' })
statusCode: number;
@Column('text', { name: 'response_body' })
responseBody: string;
@ManyToOne(() => SqliteUsers, (users) => users.idempotencyKeys, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,24 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('invite_tokens')
export class InviteTokens extends IntBaseEntity {
@Column({ name: 'token', unique: true })
token: string;
@Column('int', { name: 'max_uses', default: 1 })
maxUses: number;
@Column('int', { name: 'used_count', default: 0 })
usedCount: number;
@Column({ name: 'expires_at', nullable: true })
expiresAt: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.inviteTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'created_by', referencedColumnName: 'id' }])
createdBy: SqliteUsers;
}
@@ -0,0 +1,10 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('schema_version')
export class SchemaVersion {
@PrimaryColumn('int', { name: 'id' })
id: number | null;
@Column('int', { name: 'version' })
version: number;
}
@@ -0,0 +1,18 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('settings')
export class Settings extends IntBaseEntity {
@Column({ name: 'key' })
key: string;
@Column({ name: 'value', nullable: true })
value: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.settings, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,21 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('user_notice_dismissals')
export class UserNoticeDismissals extends TimestampedEntity {
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'notice_id' })
noticeId: string;
@Column('int', { name: 'dismissed_at' })
dismissedAt: number;
@ManyToOne(() => SqliteUsers, (users) => users.userNoticeDismissals, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -0,0 +1,25 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { DayAssignments } from './DayAssignments';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_assignment_participants_assignment', ['assignmentId'], {})
@Entity('assignment_participants')
export class AssignmentParticipants extends IntBaseEntity {
@Column('int', { name: 'assignment_id' })
assignmentId: number;
@ManyToOne(() => SqliteUsers, (users) => users.assignmentParticipants, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => DayAssignments,
(dayAssignments) => dayAssignments.assignmentParticipants,
{ onDelete: 'CASCADE' },
)
@JoinColumn([{ name: 'assignment_id', referencedColumnName: 'id' }])
assignment: DayAssignments;
}
@@ -0,0 +1,25 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { Places } from './Places';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('categories')
export class Categories extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'color', nullable: true, default: '#6366f1' })
color: string | null;
@Column({ name: 'icon', nullable: true, default: '📍' })
icon: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.categories, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@OneToMany(() => Places, (places) => places.category)
places: Places[];
}
@@ -0,0 +1,59 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Days } from './Days';
import { Places } from './Places';
import { Trips } from './Trips';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_day_accommodations_end_day_id', ['endDayId'], {})
@Index('idx_day_accommodations_start_day_id', ['startDayId'], {})
@Index('idx_day_accommodations_trip_id', ['tripId'], {})
@Entity('day_accommodations')
export class DayAccommodations extends IntBaseEntity {
@Column('int', { name: 'trip_id' })
tripId: number;
@Column('int', { name: 'start_day_id' })
startDayId: number;
@Column('int', { name: 'end_day_id' })
endDayId: number;
@Column({ name: 'check_in', nullable: true })
checkIn: string | null;
@Column({ name: 'check_in_end', nullable: true })
checkInEnd: string | null;
@Column({ name: 'check_out', nullable: true })
checkOut: string | null;
@Column({ name: 'confirmation', nullable: true })
confirmation: string | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@ManyToOne(() => Days, (days) => days.dayAccommodations, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'end_day_id', referencedColumnName: 'id' }])
endDay: Days;
@ManyToOne(() => Days, (days) => days.dayAccommodations2, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'start_day_id', referencedColumnName: 'id' }])
startDay: Days;
@ManyToOne(() => Places, (places) => places.dayAccommodations, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(() => Trips, (trips) => trips.dayAccommodations, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
}
@@ -0,0 +1,76 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { Places } from './Places';
import { Days } from './Days';
import { AssignmentParticipants } from './AssignmentParticipants';
import { IntBaseEntity } from '../base/BaseEntity';
import { Reservations } from './reservation/Reservations';
import { FileLinks } from '../system/FileLinks';
@Index('idx_day_assignments_place_id', ['placeId'], {})
@Index('idx_day_assignments_day_id', ['dayId'], {})
@Entity('day_assignments')
export class DayAssignments extends IntBaseEntity {
@Column('int', { name: 'day_id' })
dayId: number;
@Column('int', { name: 'place_id' })
placeId: number;
@Column('int', {
name: 'order_index',
nullable: true,
default: 0,
})
orderIndex: number | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column({
name: 'reservation_status',
nullable: true,
default: 'none',
})
reservationStatus: string | null;
@Column('text', { name: 'reservation_notes', nullable: true })
reservationNotes: string | null;
@Column({ name: 'reservation_datetime', nullable: true })
reservationDatetime: string | null;
@Column({ name: 'assignment_time', nullable: true })
assignmentTime: string | null;
@Column({ name: 'assignment_end_time', nullable: true })
assignmentEndTime: string | null;
@ManyToOne(() => Places, (places) => places.dayAssignments, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(() => Days, (days) => days.dayAssignments, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'day_id', referencedColumnName: 'id' }])
day: Days;
@OneToMany(() => Reservations, (reservations) => reservations.assignment)
reservations: Reservations[];
@OneToMany(
() => AssignmentParticipants,
(assignmentParticipants) => assignmentParticipants.assignment,
)
assignmentParticipants: AssignmentParticipants[];
@OneToMany(() => FileLinks, (fileLinks) => fileLinks.assignment)
fileLinks: FileLinks[];
}
@@ -0,0 +1,28 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Trips } from './Trips';
import { Days } from './Days';
import { IntSortableBaseEntity } from '../base/BaseEntity';
@Index('idx_day_notes_day_id', ['dayId'], {})
@Entity('day_notes')
export class DayNotes extends IntSortableBaseEntity {
@Column('int', { name: 'day_id' })
dayId: number;
@Column('text', { name: 'text' })
text: string;
@Column({ name: 'time', nullable: true })
time: string | null;
@Column({ name: 'icon', nullable: true, default: '📝' })
icon: string | null;
@ManyToOne(() => Trips, (trips) => trips.dayNotes, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
@ManyToOne(() => Days, (days) => days.dayNotes, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'day_id', referencedColumnName: 'id' }])
day: Days;
}
@@ -0,0 +1,72 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { Trips } from './Trips';
import { DayAssignments } from './DayAssignments';
import { DayNotes } from './DayNotes';
import { DayAccommodations } from './DayAccommodations';
import { IntBaseEntity } from '../base/BaseEntity';
import { Photos } from './journey/Photos';
import { Reservations } from './reservation/Reservations';
import { ReservationDayPositions } from './reservation/ReservationDayPositions';
@Index('idx_days_trip_id', ['tripId'], {})
@Entity('days')
export class Days extends IntBaseEntity {
@Column('int', { name: 'trip_id' })
tripId: number;
@Column('int', { name: 'day_number' })
dayNumber: number;
@Column({ name: 'date', nullable: true })
date: string | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column({ name: 'title', nullable: true })
title: string | null;
@ManyToOne(() => Trips, (trips) => trips.days, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
@OneToMany(() => DayAssignments, (dayAssignments) => dayAssignments.day)
dayAssignments: DayAssignments[];
@OneToMany(() => Photos, (photos) => photos.day)
photos: Photos[];
@OneToMany(() => Reservations, (reservations) => reservations.endDay)
reservations: Reservations[];
@OneToMany(() => Reservations, (reservations) => reservations.day)
reservations2: Reservations[];
@OneToMany(() => DayNotes, (dayNotes) => dayNotes.day)
dayNotes: DayNotes[];
@OneToMany(
() => ReservationDayPositions,
(reservationDayPositions) => reservationDayPositions.day,
)
reservationDayPositions: ReservationDayPositions[];
@OneToMany(
() => DayAccommodations,
(dayAccommodations) => dayAccommodations.endDay,
)
dayAccommodations: DayAccommodations[];
@OneToMany(
() => DayAccommodations,
(dayAccommodations) => dayAccommodations.startDay,
)
dayAccommodations2: DayAccommodations[];
}
@@ -0,0 +1,17 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
@Entity('google_place_photo_meta')
export class GooglePlacePhotoMeta extends TimestampedEntity {
@PrimaryColumn({ name: 'place_id' })
placeId: string;
@Column({ name: 'attribution', nullable: true })
attribution: string | null;
@Column('int', { name: 'fetched_at' })
fetchedAt: number;
@Column('int', { name: 'error_at', nullable: true })
errorAt: number | null;
}
@@ -0,0 +1,20 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
@Entity('place_details_cache')
export class PlaceDetailsCache extends TimestampedEntity {
@PrimaryColumn({ name: 'place_id' })
placeId: string;
@PrimaryColumn({ name: 'lang', default: '' })
lang: string;
@PrimaryColumn('int', { name: 'expanded', default: 0 })
expanded: number;
@Column('simple-json', { name: 'payload_json' })
payloadJson: Record<string, unknown>;
@Column('int', { name: 'fetched_at' })
fetchedAt: number;
}
@@ -0,0 +1,23 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Places } from './Places';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_place_regions_region', ['regionCode'], {})
@Index('idx_place_regions_country', ['countryCode'], {})
@Entity('place_regions')
export class PlaceRegions extends IntBaseEntity {
@Column({ name: 'country_code' })
countryCode: string;
@Column({ name: 'region_code' })
regionCode: string;
@Column({ name: 'region_name' })
regionName: string;
@ManyToOne(() => Places, (places) => places.placeRegions, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
}
@@ -0,0 +1,150 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToMany,
ManyToOne,
OneToMany,
} from 'typeorm';
import { Categories } from './Categories';
import { Trips } from './Trips';
import { Tags } from './Tags';
import { DayAssignments } from './DayAssignments';
import { Photos } from './journey/Photos';
import { TripFiles } from './files/TripFiles';
import { Reservations } from './reservation/Reservations';
import { FileLinks } from '../system/FileLinks';
import { PlaceRegions } from './PlaceRegions';
import { JourneyEntries } from './journey/JourneyEntries';
import { DayAccommodations } from './DayAccommodations';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_places_category_id', ['categoryId'], {})
@Index('idx_places_trip_id', ['tripId'], {})
@Entity('places')
export class Places extends IntBaseEntity {
@Column('int', { name: 'trip_id' })
tripId: number;
@Column({ name: 'name' })
name: string;
@Column('text', { name: 'description', nullable: true })
description: string | null;
@Column({ name: 'lat', nullable: true })
lat: number | null;
@Column({ name: 'lng', nullable: true })
lng: number | null;
@Column({ name: 'address', nullable: true })
address: string | null;
@Column('int', { name: 'category_id', nullable: true })
categoryId: number | null;
@Column({ name: 'price', nullable: true })
price: number | null;
@Column({ name: 'currency', nullable: true })
currency: string | null;
@Column({
name: 'reservation_status',
nullable: true,
default: 'none',
})
reservationStatus: string | null;
@Column('text', { name: 'reservation_notes', nullable: true })
reservationNotes: string | null;
@Column({ name: 'reservation_datetime', nullable: true })
reservationDatetime: string | null;
@Column({ name: 'place_time', nullable: true })
placeTime: string | null;
@Column({ name: 'end_time', nullable: true })
endTime: string | null;
@Column('int', {
name: 'duration_minutes',
nullable: true,
default: 60,
})
durationMinutes: number | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column('text', { name: 'image_url', nullable: true })
imageUrl: string | null;
@Column({ name: 'google_place_id', nullable: true })
googlePlaceId: string | null;
@Column({ name: 'website', nullable: true })
website: string | null;
@Column('text', { name: 'phone', nullable: true })
phone: string | null;
@Column({
name: 'transport_mode',
nullable: true,
default: 'walking',
})
transportMode: string | null;
@Column({ name: 'osm_id', nullable: true })
osmId: string | null;
@Column('text', { name: 'route_geometry', nullable: true })
routeGeometry: string | null;
@ManyToOne(() => Categories, (categories) => categories.places, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'category_id', referencedColumnName: 'id' }])
category: Categories;
@ManyToOne(() => Trips, (trips) => trips.places, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
@ManyToMany(() => Tags, (tags) => tags.places)
tags: Tags[];
@OneToMany(() => DayAssignments, (dayAssignments) => dayAssignments.place)
dayAssignments: DayAssignments[];
@OneToMany(() => Photos, (photos) => photos.place)
photos: Photos[];
@OneToMany(() => TripFiles, (tripFiles) => tripFiles.place)
tripFiles: TripFiles[];
@OneToMany(() => Reservations, (reservations) => reservations.place)
reservations: Reservations[];
@OneToMany(() => FileLinks, (fileLinks) => fileLinks.place)
fileLinks: FileLinks[];
@OneToMany(() => PlaceRegions, (placeRegions) => placeRegions.place)
placeRegions: PlaceRegions[];
@OneToMany(
() => JourneyEntries,
(journeyEntries) => journeyEntries.sourcePlace,
)
journeyEntries: JourneyEntries[];
@OneToMany(
() => DayAccommodations,
(dayAccommodations) => dayAccommodations.place,
)
dayAccommodations: DayAccommodations[];
}
@@ -0,0 +1,49 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Trips } from './Trips';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_share_tokens_token', ['token'], {})
@Entity('share_tokens')
export class ShareTokens extends IntBaseEntity {
@Column({ name: 'token', unique: true })
token: string;
@Column({ name: 'share_map', default: true })
shareMap: boolean;
@Column({
name: 'share_bookings',
default: true,
})
shareBookings: boolean;
@Column({
name: 'share_packing',
default: false,
})
sharePacking: boolean;
@Column({
name: 'share_budget',
default: false,
})
shareBudget: boolean;
@Column({
name: 'share_collab',
default: false,
})
shareCollab: boolean;
@Column({ name: 'expires_at', nullable: true })
expiresAt: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.shareTokens)
@JoinColumn([{ name: 'created_by', referencedColumnName: 'id' }])
createdBy: SqliteUsers;
@ManyToOne(() => Trips, (trips) => trips.shareTokens, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
}
@@ -0,0 +1,32 @@
import {
Column,
Entity,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
} from 'typeorm';
import { Places } from './Places';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('tags')
export class Tags extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'color', nullable: true, default: () => "'#10b981'" })
color: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.tags, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToMany(() => Places, (places) => places.tags)
@JoinTable({
name: 'place_tags',
joinColumns: [{ name: 'tag_id', referencedColumnName: 'id' }],
inverseJoinColumns: [{ name: 'place_id', referencedColumnName: 'id' }],
})
places: Places[];
}
@@ -0,0 +1,29 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Trips } from './Trips';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_trip_members_user_id', ['userId'], {})
@Index('idx_trip_members_trip_id', ['tripId'], {})
@Entity('trip_members')
export class TripMembers extends IntBaseEntity {
@Column('int', { name: 'trip_id' })
tripId: number;
@Column('int', { name: 'user_id' })
userId: number;
@ManyToOne(() => SqliteUsers, (users) => users.tripMembers)
@JoinColumn([{ name: 'invited_by', referencedColumnName: 'id' }])
invitedBy: SqliteUsers;
@ManyToOne(() => SqliteUsers, (users) => users.tripMembers2, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(() => Trips, (trips) => trips.tripMembers, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
}

Some files were not shown because too many files have changed in this diff Show More