diff --git a/apps/backend/package.json b/apps/backend/package.json index 5990c6a..c673a2d 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -17,16 +17,19 @@ "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" + "test:e2e": "jest --config ./test/jest-e2e.json", + "migrate:latest": "ts-node src/migrate.ts" }, "dependencies": { "@my-monorepo/common": "workspace:*", "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", "@nestjs/platform-express": "^11.0.1", + "kysely": "^0.28.3", + "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", - "zod": "^3.22.3" + "zod": "^3.25.76" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -39,6 +42,7 @@ "@types/express": "^5.0.0", "@types/jest": "^29.5.14", "@types/node": "^22.10.7", + "@types/pg": "^8.15.4", "@types/supertest": "^6.0.2", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts index cce879e..70a8b55 100644 --- a/apps/backend/src/app.controller.ts +++ b/apps/backend/src/app.controller.ts @@ -5,7 +5,7 @@ import { AppService } from './app.service'; export class AppController { constructor(private readonly appService: AppService) {} - @Get() + @Get('hello') getHello(): string { return this.appService.getHello(); } diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 63dae58..81a90d3 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { HelloController } from './hello/hello.controller'; +import { AuthController } from './controllers/auth/auth.controller'; @Module({ imports: [], - controllers: [AppController, HelloController], + controllers: [AppController, AuthController], providers: [AppService], }) export class AppModule {} diff --git a/apps/backend/src/hello/hello.controller.spec.ts b/apps/backend/src/controllers/auth/auth.controller.spec.ts similarity index 53% rename from apps/backend/src/hello/hello.controller.spec.ts rename to apps/backend/src/controllers/auth/auth.controller.spec.ts index 2f9179a..27a31e6 100644 --- a/apps/backend/src/hello/hello.controller.spec.ts +++ b/apps/backend/src/controllers/auth/auth.controller.spec.ts @@ -1,15 +1,15 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { HelloController } from './hello.controller'; +import { AuthController } from './auth.controller'; -describe('HelloController', () => { - let controller: HelloController; +describe('AuthController', () => { + let controller: AuthController; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - controllers: [HelloController], + controllers: [AuthController], }).compile(); - controller = module.get(HelloController); + controller = module.get(AuthController); }); it('should be defined', () => { diff --git a/apps/backend/src/controllers/auth/auth.controller.ts b/apps/backend/src/controllers/auth/auth.controller.ts new file mode 100644 index 0000000..6e0461b --- /dev/null +++ b/apps/backend/src/controllers/auth/auth.controller.ts @@ -0,0 +1,12 @@ +import { AuthApiService } from '@my-monorepo/common'; +import { Controller, Post } from '@nestjs/common'; + +@Controller(AuthApiService.baseUrl) +export class AuthController implements AuthApiService { + // eslint-disable-next-line @typescript-eslint/no-misused-promises + @Post(AuthApiService.postCredentials) + // eslint-disable-next-line @typescript-eslint/require-await + async postCredentials() { + return 'hello'; + } +} diff --git a/apps/backend/src/database/kysely-config.ts b/apps/backend/src/database/kysely-config.ts new file mode 100644 index 0000000..886bf48 --- /dev/null +++ b/apps/backend/src/database/kysely-config.ts @@ -0,0 +1,22 @@ +import { Pool } from 'pg'; +import { Kysely, PostgresDialect } from 'kysely'; + +const dialect = new PostgresDialect({ + // TODO : temporary data, make to .env + pool: new Pool({ + database: 'cowsi', + host: 'localhost', + user: 'postgres', + password: 'postgres', + port: 5432, + max: 10, + }), +}); + +// Database interface is passed to Kysely's constructor, and from now on, Kysely +// knows your database structure. +// Dialect is passed to Kysely's constructor, and from now on, Kysely knows how +// to communicate with your database. +export const db = new Kysely({ + dialect, +}); diff --git a/apps/backend/src/hello/hello.controller.ts b/apps/backend/src/hello/hello.controller.ts deleted file mode 100644 index 4fa6f1b..0000000 --- a/apps/backend/src/hello/hello.controller.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Controller } from '@nestjs/common'; - -@Controller() -export class HelloController {} diff --git a/apps/backend/src/migrate.ts b/apps/backend/src/migrate.ts new file mode 100644 index 0000000..709abd3 --- /dev/null +++ b/apps/backend/src/migrate.ts @@ -0,0 +1,56 @@ +import * as path from 'path'; +import { Pool } from 'pg'; +import { promises as fs } from 'fs'; +import { + Kysely, + Migrator, + PostgresDialect, + FileMigrationProvider, +} from 'kysely'; +import { ZodUnknownDef } from 'zod'; + +async function migrateToLatest() { + const db = new Kysely({ + dialect: new PostgresDialect({ + pool: new Pool({ + database: 'cowsi', + host: 'localhost', + user: 'postgres', + password: 'postgres', + port: 5432, + }), + }), + }); + + const migrator = new Migrator({ + db, + provider: new FileMigrationProvider({ + fs, + path, + // This needs to be an absolute path. + migrationFolder: path.join(__dirname, './migrations'), + }), + }); + + const { error, results } = await migrator.migrateToLatest(); + + results?.forEach((it) => { + if (it.status === 'Success') { + console.log(`migration "${it.migrationName}" was executed successfully`); + } else if (it.status === 'Error') { + console.error(`failed to execute migration "${it.migrationName}"`); + } + }); + + if (error) { + console.error('failed to migrate'); + console.error(error); + process.exit(1); + } else { + console.log('Done migrating'); + } + + await db.destroy(); +} + +void migrateToLatest(); diff --git a/apps/backend/src/migrations/2023-07-28_07-38-38_init_db.ts b/apps/backend/src/migrations/2023-07-28_07-38-38_init_db.ts new file mode 100644 index 0000000..91f97aa --- /dev/null +++ b/apps/backend/src/migrations/2023-07-28_07-38-38_init_db.ts @@ -0,0 +1,30 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await db.schema + .createTable('users') + .addColumn('id', 'bigserial', (col) => col.primaryKey()) + .addColumn('first_name', 'varchar(255)', (col) => col.notNull()) + .addColumn('last_name', 'varchar(255)', (col) => col.notNull()) + .addColumn('email', 'varchar(255)', (col) => col.notNull().unique()) + .addColumn('hash', 'text') + .addColumn('created_at', 'timestamptz', (col) => + col.notNull().defaultTo(sql`now()`), + ) + .addColumn('updated_at', 'timestamptz', (col) => + col.notNull().defaultTo(sql`now()`), + ) + .addColumn('deleted_at', 'timestamptz') + .execute(); + + // You can also add indexes, foreign keys, etc. here + await db.schema + .createIndex('users_email_index') + .on('users') + .column('email') + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema.dropTable('users').execute(); +} diff --git a/documentation/bruno-rest-api/LocalAPI/auth/credentials.bru b/documentation/bruno-rest-api/LocalAPI/auth/credentials.bru new file mode 100644 index 0000000..633b37d --- /dev/null +++ b/documentation/bruno-rest-api/LocalAPI/auth/credentials.bru @@ -0,0 +1,15 @@ +meta { + name: credentials + type: http + seq: 1 +} + +post { + url: {{BASE_URL}}/auth/credentials + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/documentation/bruno-rest-api/LocalAPI/auth/folder.bru b/documentation/bruno-rest-api/LocalAPI/auth/folder.bru new file mode 100644 index 0000000..8fe9662 --- /dev/null +++ b/documentation/bruno-rest-api/LocalAPI/auth/folder.bru @@ -0,0 +1,8 @@ +meta { + name: auth + seq: 1 +} + +auth { + mode: inherit +} diff --git a/documentation/bruno-rest-api/LocalAPI/bruno.json b/documentation/bruno-rest-api/LocalAPI/bruno.json new file mode 100644 index 0000000..94641a4 --- /dev/null +++ b/documentation/bruno-rest-api/LocalAPI/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "LocalAPI", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/documentation/bruno-rest-api/LocalAPI/environments/Local-Localhost.bru b/documentation/bruno-rest-api/LocalAPI/environments/Local-Localhost.bru new file mode 100644 index 0000000..fa6654a --- /dev/null +++ b/documentation/bruno-rest-api/LocalAPI/environments/Local-Localhost.bru @@ -0,0 +1,3 @@ +vars { + BASE_URL: http://localhost:3000 +} diff --git a/documentation/bruno-rest-api/LocalAPI/hello.bru b/documentation/bruno-rest-api/LocalAPI/hello.bru new file mode 100644 index 0000000..a2c6941 --- /dev/null +++ b/documentation/bruno-rest-api/LocalAPI/hello.bru @@ -0,0 +1,15 @@ +meta { + name: hello + type: http + seq: 2 +} + +get { + url: {{BASE_URL}}/hello + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/packages/common/package.json b/packages/common/package.json index 9fab838..c64c99c 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -5,12 +5,12 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "build": "tsc" + "build": "tsc --watch" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { - "zod": "^3.22.3" + "zod": "^3.25.76" } } \ No newline at end of file diff --git a/packages/common/src/api-services/auth/auth-api-service.ts b/packages/common/src/api-services/auth/auth-api-service.ts new file mode 100644 index 0000000..0e54765 --- /dev/null +++ b/packages/common/src/api-services/auth/auth-api-service.ts @@ -0,0 +1,10 @@ +export interface AuthApiService { + postCredentials(): Promise; +} + +export const AuthApiService: Record & { + baseUrl: string; +} = { + baseUrl: "auth", + postCredentials: "credentials", +}; diff --git a/packages/common/src/api-services/auth/index.ts b/packages/common/src/api-services/auth/index.ts new file mode 100644 index 0000000..107910a --- /dev/null +++ b/packages/common/src/api-services/auth/index.ts @@ -0,0 +1 @@ +export * from "./auth-api-service"; diff --git a/packages/common/src/api-services/index.ts b/packages/common/src/api-services/index.ts new file mode 100644 index 0000000..97ccf76 --- /dev/null +++ b/packages/common/src/api-services/index.ts @@ -0,0 +1 @@ +export * from "./auth"; diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index d4802ed..ec3cb0f 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1 +1,2 @@ -export * from "./contracts/index"; +export * from "./api-services"; +export * from "./models"; diff --git a/packages/common/src/models/auth/credential-auth.ts b/packages/common/src/models/auth/credential-auth.ts new file mode 100644 index 0000000..5d956ec --- /dev/null +++ b/packages/common/src/models/auth/credential-auth.ts @@ -0,0 +1,14 @@ +import z from "zod"; + +export const credentialAuthParser = z.object({ + email: z.string().email({ message: "invalid email" }), + password: z.string({ message: "invalid password" }), +}); + +export const credentialAuthResponse = z.object({ + accessToken: z.string({ message: "invalid access tokens" }), +}); + +export type CredentialAuth = z.infer; + +export type CredentialAuthResponse = z.infer; diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts new file mode 100644 index 0000000..ddf77b4 --- /dev/null +++ b/packages/common/src/models/index.ts @@ -0,0 +1 @@ +export * from "./users"; diff --git a/packages/common/src/models/users/index.ts b/packages/common/src/models/users/index.ts new file mode 100644 index 0000000..7616f9e --- /dev/null +++ b/packages/common/src/models/users/index.ts @@ -0,0 +1 @@ +export * from "./user"; diff --git a/packages/common/src/models/users/user.ts b/packages/common/src/models/users/user.ts new file mode 100644 index 0000000..b4e7eb6 --- /dev/null +++ b/packages/common/src/models/users/user.ts @@ -0,0 +1,16 @@ +import z from "zod"; + +export enum UserTypeEnum { + Customer = "customer", + Professional = "professional", +} + +export const userParser = z.object({ + id: z.string({ message: "inavlid user id" }), + firstName: z.string({ message: "invalid user first name" }), + lastName: z.string({ message: "invalid last name" }), + email: z.string().email({ message: "invalid email" }), + type: z.nativeEnum(UserTypeEnum, { message: "invalid user type" }), +}); + +export type User = z.infer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4056ae9..c625af3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,12 @@ importers: '@nestjs/platform-express': specifier: ^11.0.1 version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3) + kysely: + specifier: ^0.28.3 + version: 0.28.3 + pg: + specifier: ^8.16.3 + version: 8.16.3 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -29,7 +35,7 @@ importers: specifier: ^7.8.1 version: 7.8.2 zod: - specifier: ^3.22.3 + specifier: ^3.25.76 version: 3.25.76 devDependencies: '@eslint/eslintrc': @@ -62,6 +68,9 @@ importers: '@types/node': specifier: ^22.10.7 version: 22.16.3 + '@types/pg': + specifier: ^8.15.4 + version: 8.15.4 '@types/supertest': specifier: ^6.0.2 version: 6.0.3 @@ -91,7 +100,7 @@ importers: version: 7.1.3 ts-jest: specifier: ^29.2.5 - version: 29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.3)(ts-node@10.9.2(@swc/core@1.12.11)(@types/node@22.16.3)(typescript@5.7.3)))(typescript@5.7.3) + version: 29.4.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.3)(ts-node@10.9.2(@swc/core@1.12.11)(@types/node@22.16.3)(typescript@5.7.3)))(typescript@5.7.3) ts-loader: specifier: ^9.5.2 version: 9.5.2(typescript@5.7.3)(webpack@5.99.6(@swc/core@1.12.11)) @@ -111,7 +120,7 @@ importers: packages/common: dependencies: zod: - specifier: ^3.22.3 + specifier: ^3.25.76 version: 3.25.76 packages: @@ -1019,6 +1028,9 @@ packages: '@types/node@22.16.3': resolution: {integrity: sha512-sr4Xz74KOUeYadexo1r8imhRtlVXcs+j3XK3TcoiYk7B1t3YRVJgtaD3cwX73NYb71pmVuMLNRhJ9XKdoDB74g==} + '@types/pg@8.15.4': + resolution: {integrity: sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==} + '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} @@ -2399,6 +2411,10 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kysely@0.28.3: + resolution: {integrity: sha512-svKnkSH72APRdjfVCCOknxaC9Eb3nA2StHG9d5/sKOqRvHRp2Dtf1XwDvc92b4B5v6LV+EAGWXQbZ5jMOvHaDw==} + engines: {node: '>=20.0.0'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -2706,6 +2722,40 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + pg-cloudflare@1.2.7: + resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + + pg-connection-string@2.9.1: + resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.10.1: + resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.10.3: + resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.16.3: + resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2732,6 +2782,22 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2975,6 +3041,10 @@ packages: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -3561,36 +3631,78 @@ snapshots: dependencies: '@babel/types': 7.28.1 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -3601,41 +3713,89 @@ snapshots: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.10)': + dependencies: + '@babel/core': 7.26.10 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -4462,6 +4622,12 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/pg@8.15.4': + dependencies: + '@types/node': 22.16.3 + pg-protocol: 1.10.3 + pg-types: 2.2.0 + '@types/qs@6.14.0': {} '@types/range-parser@1.2.7': {} @@ -4830,6 +4996,20 @@ snapshots: b4a@1.6.7: {} + babel-jest@29.7.0(@babel/core@7.26.10): + dependencies: + '@babel/core': 7.26.10 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.10) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + optional: true + babel-jest@29.7.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -4860,6 +5040,26 @@ snapshots: '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.7 + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.10): + dependencies: + '@babel/core': 7.26.10 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.10) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.10) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.10) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.26.10) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.10) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.10) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.10) + optional: true + babel-preset-current-node-syntax@1.1.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -4879,6 +5079,13 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.0) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.0) + babel-preset-jest@29.6.3(@babel/core@7.26.10): + dependencies: + '@babel/core': 7.26.10 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.10) + optional: true + babel-preset-jest@29.6.3(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -6152,6 +6359,8 @@ snapshots: kleur@3.0.3: {} + kysely@0.28.3: {} + leven@3.1.0: {} levn@0.4.1: @@ -6406,6 +6615,41 @@ snapshots: pend@1.2.0: {} + pg-cloudflare@1.2.7: + optional: true + + pg-connection-string@2.9.1: {} + + pg-int8@1.0.1: {} + + pg-pool@3.10.1(pg@8.16.3): + dependencies: + pg: 8.16.3 + + pg-protocol@1.10.3: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.16.3: + dependencies: + pg-connection-string: 2.9.1 + pg-pool: 3.10.1(pg@8.16.3) + pg-protocol: 1.10.3 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.2.7 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -6424,6 +6668,16 @@ snapshots: pluralize@8.0.0: {} + postgres-array@2.0.0: {} + + postgres-bytea@1.0.0: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -6670,6 +6924,8 @@ snapshots: source-map@0.7.4: {} + split2@4.2.0: {} + sprintf-js@1.0.3: {} stack-utils@2.0.6: @@ -6838,7 +7094,7 @@ snapshots: dependencies: typescript: 5.7.3 - ts-jest@29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.3)(ts-node@10.9.2(@swc/core@1.12.11)(@types/node@22.16.3)(typescript@5.7.3)))(typescript@5.7.3): + ts-jest@29.4.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.3)(ts-node@10.9.2(@swc/core@1.12.11)(@types/node@22.16.3)(typescript@5.7.3)))(typescript@5.7.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -6852,10 +7108,10 @@ snapshots: typescript: 5.7.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.0 + '@babel/core': 7.26.10 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.0) + babel-jest: 29.7.0(@babel/core@7.26.10) jest-util: 29.7.0 ts-loader@9.5.2(typescript@5.7.3)(webpack@5.99.6(@swc/core@1.12.11)):