feat: Prisma 用户落库、迁移与启动环境加载

- Prisma 7 + adapter-pg;prisma.config 与 users 初始迁移\n- AppModule 挂载 PrismaModule;PrismaService 仅依赖 DATABASE_URL\n- main 入口 dotenv/config,避免 Prisma 早于 Config 读 env\n- 短信登录 upsert User;默认昵称 Chat+手机号后四位\n- README / project-solution:目录、迁移规范、用户 avatar_url 说明\n- 依赖:dotenv、@prisma/adapter-pg、pg

Made-with: Cursor
This commit is contained in:
2026-04-22 01:21:11 +08:00
parent 6cc89062e1
commit bc13417efd
12 changed files with 325 additions and 21 deletions

View File

@@ -15,6 +15,22 @@ ChatOne 服务端:基于 **NestJS 11** + **Fastify**,整合多厂商大模
更完整的架构说明见:`docs/project-solution.md`。JWT 最小示例见:`docs/jwt-minimal-nestjs.md` 更完整的架构说明见:`docs/project-solution.md`。JWT 最小示例见:`docs/jwt-minimal-nestjs.md`
## 目录
- [TODO当前迭代](#todo当前迭代)
- [技术栈](#技术栈)
- [目录结构(概要)](#目录结构概要)
- [环境要求](#环境要求)
- [安装依赖](#安装依赖)
- [环境变量](#环境变量)
- [常用脚本](#常用脚本)
- [数据库迁移规范Prisma](#数据库迁移规范prisma)
- [启动](#启动)
- [API 说明](#api-说明)
- [数据库与 Prisma](#数据库与-prisma)
- [安全提示](#安全提示)
- [许可证](#许可证)
--- ---
## 技术栈 ## 技术栈
@@ -120,6 +136,69 @@ yarn install
| `yarn start` | 运行已编译产物 `dist/main.js` | | `yarn start` | 运行已编译产物 `dist/main.js` |
| `yarn lint` | ESLint需本地配置规则时生效 | | `yarn lint` | ESLint需本地配置规则时生效 |
## 数据库迁移规范Prisma
### 开发环境变更流程
1. 修改 `prisma/schema.prisma`(新增表/字段/索引等)
1. 生成并执行迁移:
```bash
npx prisma migrate dev --name <migration_name>
```
1. 如需手动更新 Prisma Client
```bash
npx prisma generate
```
1. 本地验证接口与核心流程
1. 提交代码时必须包含:
- `prisma/schema.prisma`
- `prisma/migrations/**`
### 生产环境发布流程
生产环境禁止使用 `migrate dev`,仅执行:
```bash
npx prisma migrate deploy
```
### 迁移命名规范
迁移名统一使用:`动词_对象_说明`
例如:
- `init_users`
- `add_users_avatar_url`
- `add_chat_sessions`
- `alter_chat_messages_token_count_type`
### 风险控制建议
- 涉及删列、改类型、重命名时,先在测试库验证
- 可能影响历史数据的迁移,先做备份
- 大改动拆分为多次小迁移,避免一次性高风险变更
### 常用命令速查
```bash
# 生成并执行开发迁移
npx prisma migrate dev --name <name>
# 仅更新 Prisma Client
npx prisma generate
# 查看数据库状态
npx prisma migrate status
# 生产环境应用迁移
npx prisma migrate deploy
```
--- ---
## 启动 ## 启动

View File

@@ -8,6 +8,23 @@
- 对外提供统一调用接口(自动路由)和指定平台调用接口; - 对外提供统一调用接口(自动路由)和指定平台调用接口;
- 提供用户管理、平台管理、用量统计。 - 提供用户管理、平台管理、用量统计。
## 目录
- [1. 技术选型(主流且简洁)](#1-技术选型主流且简洁)
- [2. 项目结构(推荐:按用户端/管理端强隔离)](#2-项目结构推荐按用户端管理端强隔离)
- [3. 模块职责](#3-模块职责)
- [4. API 设计(示例)](#4-api-设计示例)
- [5. 自动路由与统一格式方案](#5-自动路由与统一格式方案)
- [6. 依赖清单(核心)](#6-依赖清单核心)
- [7. 配置文件示例](#7-配置文件示例)
- [8. 数据库设计PostgreSQL](#8-数据库设计postgresql)
- [9. 缓存方案Redis](#9-缓存方案redis)
- [10. 登录与鉴权方案](#10-登录与鉴权方案)
- [11. 拆分演进路线(低成本)](#11-拆分演进路线低成本)
- [12. 最小可用开发流程MVP](#12-最小可用开发流程mvp)
- [13. 非功能建议(上线前)](#13-非功能建议上线前)
- [14. 一句话总结](#14-一句话总结)
--- ---
## 1. 技术选型(主流且简洁) ## 1. 技术选型(主流且简洁)
@@ -171,7 +188,7 @@ chat-one-service/
- `POST /api/client/v1/auth/sms/login` - `POST /api/client/v1/auth/sms/login`
- 入参:`{ phone, code }` - 入参:`{ phone, code }`
- 出参:`{ accessToken, refreshToken, user }` - 出参:`{ accessToken, refreshToken, user }``user``users` 表对齐,建议含 `id``phone``nickname``avatarUrl` 等;未落库前可为占位结构)
- `POST /api/client/v1/auth/refresh` - `POST /api/client/v1/auth/refresh`
- 入参:`{ refreshToken }` - 入参:`{ refreshToken }`
@@ -380,6 +397,7 @@ REDIS_KEY_PREFIX_ADMIN=chatone:admin
- `id` (bigserial pk) - `id` (bigserial pk)
- `phone` (varchar unique) - `phone` (varchar unique)
- `nickname` (varchar) - `nickname` (varchar)
- `avatar_url` (varchar, nullable) — 头像地址HTTPS 对象存储或 CDN URL为空时客户端展示默认头像
- `status` (smallint, 1正常 0禁用) - `status` (smallint, 1正常 0禁用)
- `created_at`, `updated_at` - `created_at`, `updated_at`

View File

@@ -12,7 +12,8 @@
"start": "node dist/main.js", "start": "node dist/main.js",
"start:dev": "tsx watch src/main.ts", "start:dev": "tsx watch src/main.ts",
"start:debug": "node --inspect=0.0.0.0:9229 dist/main.js", "start:debug": "node --inspect=0.0.0.0:9229 dist/main.js",
"lint": "eslint \"src/**/*.ts\"" "lint": "eslint \"src/**/*.ts\"",
"postinstall": "prisma generate"
}, },
"dependencies": { "dependencies": {
"@fastify/static": "^9.1.1", "@fastify/static": "^9.1.1",
@@ -25,15 +26,18 @@
"@nestjs/schedule": "^6.1.3", "@nestjs/schedule": "^6.1.3",
"@nestjs/swagger": "^11.3.0", "@nestjs/swagger": "^11.3.0",
"@nestjs/throttler": "^6.5.0", "@nestjs/throttler": "^6.5.0",
"@prisma/adapter-pg": "^7.7.0",
"@prisma/client": "^7.7.0", "@prisma/client": "^7.7.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.15.1", "class-validator": "^0.15.1",
"dayjs": "^1.11.20", "dayjs": "^1.11.20",
"dotenv": "^17.4.2",
"helmet": "^8.1.0", "helmet": "^8.1.0",
"ioredis": "^5.10.1", "ioredis": "^5.10.1",
"nestjs-pino": "^4.6.1", "nestjs-pino": "^4.6.1",
"passport": "^0.7.0", "passport": "^0.7.0",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"pg": "^8.20.0",
"pino-http": "^11.0.0", "pino-http": "^11.0.0",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",

12
prisma.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import 'dotenv/config';
import { defineConfig } from 'prisma/config';
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: process.env.DATABASE_URL || '',
},
});

View File

@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "users" (
"id" BIGSERIAL NOT NULL,
"phone" VARCHAR(32) NOT NULL,
"nickname" VARCHAR(100),
"avatar_url" VARCHAR(512),
"status" SMALLINT NOT NULL DEFAULT 1,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "users_phone_key" ON "users"("phone");

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"

19
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,19 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
model User {
id BigInt @id @default(autoincrement())
phone String @unique @db.VarChar(32)
nickname String? @db.VarChar(100)
avatarUrl String? @map("avatar_url") @db.VarChar(512)
status Int @default(1) @db.SmallInt
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("users")
}

View File

@@ -4,6 +4,7 @@ import { LoggerModule } from 'nestjs-pino';
import { ClientAppModule } from './apps/client-app/client-app.module'; import { ClientAppModule } from './apps/client-app/client-app.module';
import { AdminAppModule } from './apps/admin-app/admin-app.module'; import { AdminAppModule } from './apps/admin-app/admin-app.module';
import { RedisModule } from './apps/shared-domain/cache/redis.module'; import { RedisModule } from './apps/shared-domain/cache/redis.module';
import { PrismaModule } from './prisma/prisma.module';
import configuration from './config/configuration'; import configuration from './config/configuration';
import { validateEnv } from './config/validation'; import { validateEnv } from './config/validation';
@@ -25,6 +26,7 @@ import { validateEnv } from './config/validation';
: undefined, : undefined,
}, },
}), }),
PrismaModule,
RedisModule, RedisModule,
ClientAppModule, ClientAppModule,
AdminAppModule, AdminAppModule,

View File

@@ -9,6 +9,7 @@ import { JwtService } from '@nestjs/jwt';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { SmsService } from '@shared/sms/sms.service'; import { SmsService } from '@shared/sms/sms.service';
import { RedisService } from '@shared/cache/redis.service'; import { RedisService } from '@shared/cache/redis.service';
import { PrismaService } from '@prisma/prisma.service';
interface AccessPayload { interface AccessPayload {
sub: string; sub: string;
@@ -41,6 +42,8 @@ export class ClientAuthService {
private readonly smsService: SmsService, private readonly smsService: SmsService,
@Inject(RedisService) @Inject(RedisService)
private readonly redisService: RedisService, private readonly redisService: RedisService,
@Inject(PrismaService)
private readonly prisma: PrismaService,
) {} ) {}
async sendSmsCode(phone: string, scene: string) { async sendSmsCode(phone: string, scene: string) {
@@ -89,7 +92,21 @@ export class ClientAuthService {
} }
await this.redisService.del(key); await this.redisService.del(key);
const userId = `u_${phone}`; const user = await this.prisma.user.upsert({
where: { phone },
update: {
updatedAt: new Date(),
},
create: {
phone,
nickname: `Chat${phone.slice(-4)}`,
},
});
if (user.status !== 1) {
throw new UnauthorizedException('用户已被禁用');
}
const userId = String(user.id);
const accessToken = await this.signAccessToken({ const accessToken = await this.signAccessToken({
sub: userId, sub: userId,
phone, phone,
@@ -108,6 +125,8 @@ export class ClientAuthService {
user: { user: {
id: userId, id: userId,
phone, phone,
nickname: user.nickname ?? '',
avatarUrl: user.avatarUrl ?? '',
}, },
}; };
} }
@@ -126,9 +145,23 @@ export class ClientAuthService {
throw new UnauthorizedException('token 类型错误'); throw new UnauthorizedException('token 类型错误');
} }
let userId: bigint;
try {
userId = BigInt(payload.sub);
} catch {
throw new UnauthorizedException('refreshToken 用户标识无效');
}
const user = await this.prisma.user.findUnique({
where: { id: userId },
select: { id: true, phone: true, status: true },
});
if (!user || user.status !== 1) {
throw new UnauthorizedException('用户不存在或已禁用');
}
const accessToken = await this.signAccessToken({ const accessToken = await this.signAccessToken({
sub: payload.sub, sub: String(user.id),
phone: payload.sub.replace('u_', ''), phone: user.phone,
role: 'client', role: 'client',
type: 'access', type: 'access',
}); });

View File

@@ -1,3 +1,4 @@
import 'dotenv/config';
import 'reflect-metadata'; import 'reflect-metadata';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';

View File

@@ -1,18 +1,23 @@
import { import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
INestApplication, import { PrismaClient } from '@prisma/client';
Injectable, import { PrismaPg } from '@prisma/adapter-pg';
OnModuleDestroy,
OnModuleInit,
} from '@nestjs/common';
// Prisma v7 默认导出 PrismaClient
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { PrismaClient } = require('@prisma/client');
@Injectable() @Injectable()
export class PrismaService export class PrismaService
extends PrismaClient extends PrismaClient
implements OnModuleInit, OnModuleDestroy implements OnModuleInit, OnModuleDestroy
{ {
constructor() {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error('DATABASE_URL 未配置Prisma 无法初始化');
}
const adapter = new PrismaPg({ connectionString: databaseUrl });
super({
adapter,
});
}
async onModuleInit() { async onModuleInit() {
await this.$connect(); await this.$connect();
} }
@@ -20,11 +25,5 @@ export class PrismaService
async onModuleDestroy() { async onModuleDestroy() {
await this.$disconnect(); await this.$disconnect();
} }
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
} }

121
yarn.lock
View File

@@ -465,6 +465,16 @@
resolved "https://registry.npmmirror.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6" resolved "https://registry.npmmirror.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6"
integrity sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg== integrity sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==
"@prisma/adapter-pg@^7.7.0":
version "7.7.0"
resolved "https://registry.npmmirror.com/@prisma/adapter-pg/-/adapter-pg-7.7.0.tgz#6a40a98b78b47cfac22467d6ffbbed7248625269"
integrity sha512-q33Ta8sKbgzEpAy0lx45tAq//yMv0qcb+8nj+TCA3P4wiAY+OBFEFk/NDkZncAfHaNJeGo5WJpJdpbL+ijYx8g==
dependencies:
"@prisma/driver-adapter-utils" "7.7.0"
"@types/pg" "^8.16.0"
pg "^8.16.3"
postgres-array "3.0.4"
"@prisma/client-runtime-utils@7.7.0": "@prisma/client-runtime-utils@7.7.0":
version "7.7.0" version "7.7.0"
resolved "https://registry.npmmirror.com/@prisma/client-runtime-utils/-/client-runtime-utils-7.7.0.tgz#7d45c5754358e9d4d006a137818ebdb5f0c4dcb6" resolved "https://registry.npmmirror.com/@prisma/client-runtime-utils/-/client-runtime-utils-7.7.0.tgz#7d45c5754358e9d4d006a137818ebdb5f0c4dcb6"
@@ -520,6 +530,13 @@
valibot "1.2.0" valibot "1.2.0"
zeptomatch "2.1.0" zeptomatch "2.1.0"
"@prisma/driver-adapter-utils@7.7.0":
version "7.7.0"
resolved "https://registry.npmmirror.com/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.7.0.tgz#0c0cda6840de84c88e314ec3de414c29d53dc6dc"
integrity sha512-gZXREeu6mOk7zXfGFJgh86p7Vhj0sXNKp+4Cg1tWYo7V2dfncP2qxS2BiTmbIIha8xPqItkl0WSw38RuSq1HoQ==
dependencies:
"@prisma/debug" "7.7.0"
"@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711": "@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711":
version "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711" version "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711"
resolved "https://registry.npmmirror.com/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz#2bdc8c2a9b2b1612f484a9e50c988655b69bbe89" resolved "https://registry.npmmirror.com/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz#2bdc8c2a9b2b1612f484a9e50c988655b69bbe89"
@@ -717,6 +734,15 @@
dependencies: dependencies:
undici-types "~7.19.0" undici-types "~7.19.0"
"@types/pg@^8.16.0":
version "8.20.0"
resolved "https://registry.npmmirror.com/@types/pg/-/pg-8.20.0.tgz#8bd03d3ac6b19143a8de7d66a9d13da32cd91526"
integrity sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==
dependencies:
"@types/node" "*"
pg-protocol "*"
pg-types "^2.2.0"
"@types/validator@^13.15.3": "@types/validator@^13.15.3":
version "13.15.10" version "13.15.10"
resolved "https://registry.npmmirror.com/@types/validator/-/validator-13.15.10.tgz#742b77ec34d58554b94a76a14cef30d59e3c16b9" resolved "https://registry.npmmirror.com/@types/validator/-/validator-13.15.10.tgz#742b77ec34d58554b94a76a14cef30d59e3c16b9"
@@ -1005,6 +1031,11 @@ dotenv@^16.4.5, dotenv@^16.6.1:
resolved "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" resolved "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020"
integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==
dotenv@^17.4.2:
version "17.4.2"
resolved "https://registry.npmmirror.com/dotenv/-/dotenv-17.4.2.tgz#c07e54a746e11eba021dd9e1047ced5afdc1c034"
integrity sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==
ecdsa-sig-formatter@1.0.11: ecdsa-sig-formatter@1.0.11:
version "1.0.11" version "1.0.11"
resolved "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" resolved "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
@@ -1868,6 +1899,62 @@ perfect-debounce@^1.0.0:
resolved "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a" resolved "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a"
integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==
pg-cloudflare@^1.3.0:
version "1.3.0"
resolved "https://registry.npmmirror.com/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz#386035d4bfcf1a7045b026f8b21acf5353f14d65"
integrity sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==
pg-connection-string@^2.12.0:
version "2.12.0"
resolved "https://registry.npmmirror.com/pg-connection-string/-/pg-connection-string-2.12.0.tgz#4084f917902bb2daae3dc1376fe24ac7b4eaccf2"
integrity sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==
pg-int8@1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
pg-pool@^3.13.0:
version "3.13.0"
resolved "https://registry.npmmirror.com/pg-pool/-/pg-pool-3.13.0.tgz#416482e9700e8f80c685a6ae5681697a413c13a3"
integrity sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==
pg-protocol@*, pg-protocol@^1.13.0:
version "1.13.0"
resolved "https://registry.npmmirror.com/pg-protocol/-/pg-protocol-1.13.0.tgz#fdaf6d020bca590d58bb991b4b16fc448efe0511"
integrity sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==
pg-types@2.2.0, pg-types@^2.2.0:
version "2.2.0"
resolved "https://registry.npmmirror.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
dependencies:
pg-int8 "1.0.1"
postgres-array "~2.0.0"
postgres-bytea "~1.0.0"
postgres-date "~1.0.4"
postgres-interval "^1.1.0"
pg@^8.16.3, pg@^8.20.0:
version "8.20.0"
resolved "https://registry.npmmirror.com/pg/-/pg-8.20.0.tgz#1a274de944cb329fd6dd77a6d371a005ba6b136d"
integrity sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==
dependencies:
pg-connection-string "^2.12.0"
pg-pool "^3.13.0"
pg-protocol "^1.13.0"
pg-types "2.2.0"
pgpass "1.0.5"
optionalDependencies:
pg-cloudflare "^1.3.0"
pgpass@1.0.5:
version "1.0.5"
resolved "https://registry.npmmirror.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
dependencies:
split2 "^4.1.0"
pino-abstract-transport@^3.0.0: pino-abstract-transport@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmmirror.com/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz#b21e5f33a297e8c4c915c62b3ce5dd4a87a52c23" resolved "https://registry.npmmirror.com/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz#b21e5f33a297e8c4c915c62b3ce5dd4a87a52c23"
@@ -1935,6 +2022,33 @@ pkg-types@^2.2.0:
exsolve "^1.0.7" exsolve "^1.0.7"
pathe "^2.0.3" pathe "^2.0.3"
postgres-array@3.0.4:
version "3.0.4"
resolved "https://registry.npmmirror.com/postgres-array/-/postgres-array-3.0.4.tgz#4efcaf4d2c688d8bcaa8620ed13f35f299f7528c"
integrity sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==
postgres-array@~2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
postgres-bytea@~1.0.0:
version "1.0.1"
resolved "https://registry.npmmirror.com/postgres-bytea/-/postgres-bytea-1.0.1.tgz#c40b3da0222c500ff1e51c5d7014b60b79697c7a"
integrity sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==
postgres-date@~1.0.4:
version "1.0.7"
resolved "https://registry.npmmirror.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
postgres-interval@^1.1.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
dependencies:
xtend "^4.0.0"
postgres@3.4.7: postgres@3.4.7:
version "3.4.7" version "3.4.7"
resolved "https://registry.npmmirror.com/postgres/-/postgres-3.4.7.tgz#122f460a808fe300cae53f592108b9906e625345" resolved "https://registry.npmmirror.com/postgres/-/postgres-3.4.7.tgz#122f460a808fe300cae53f592108b9906e625345"
@@ -2157,7 +2271,7 @@ sonic-boom@^4.0.1:
dependencies: dependencies:
atomic-sleep "^1.0.0" atomic-sleep "^1.0.0"
split2@^4.0.0: split2@^4.0.0, split2@^4.1.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" resolved "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
@@ -2344,6 +2458,11 @@ wrappy@1:
resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
yn@3.1.1: yn@3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"