From bc13417efde5eefc1cf5f7a07491807d31f8ad1e Mon Sep 17 00:00:00 2001 From: alboped Date: Wed, 22 Apr 2026 01:21:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Prisma=20=E7=94=A8=E6=88=B7=E8=90=BD?= =?UTF-8?q?=E5=BA=93=E3=80=81=E8=BF=81=E7=A7=BB=E4=B8=8E=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- README.md | 79 ++++++++++++ docs/project-solution.md | 20 ++- package.json | 6 +- prisma.config.ts | 12 ++ .../20260421164244_init_users/migration.sql | 15 +++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 19 +++ src/app.module.ts | 2 + .../client-app/auth/client-auth.service.ts | 39 +++++- src/main.ts | 1 + src/prisma/prisma.service.ts | 29 ++--- yarn.lock | 121 +++++++++++++++++- 12 files changed, 325 insertions(+), 21 deletions(-) create mode 100644 prisma.config.ts create mode 100644 prisma/migrations/20260421164244_init_users/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma diff --git a/README.md b/README.md index 03d9a8e..2cc7660 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,22 @@ ChatOne 服务端:基于 **NestJS 11** + **Fastify**,整合多厂商大模 更完整的架构说明见:`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 lint` | ESLint(需本地配置规则时生效) | +## 数据库迁移规范(Prisma) + +### 开发环境变更流程 + +1. 修改 `prisma/schema.prisma`(新增表/字段/索引等) +1. 生成并执行迁移: + +```bash +npx prisma migrate dev --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 + +# 仅更新 Prisma Client +npx prisma generate + +# 查看数据库状态 +npx prisma migrate status + +# 生产环境应用迁移 +npx prisma migrate deploy +``` + --- ## 启动 diff --git a/docs/project-solution.md b/docs/project-solution.md index 37849d0..ab82faa 100644 --- a/docs/project-solution.md +++ b/docs/project-solution.md @@ -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. 技术选型(主流且简洁) @@ -171,7 +188,7 @@ chat-one-service/ - `POST /api/client/v1/auth/sms/login` - 入参:`{ phone, code }` - - 出参:`{ accessToken, refreshToken, user }` + - 出参:`{ accessToken, refreshToken, user }`(`user` 与 `users` 表对齐,建议含 `id`、`phone`、`nickname`、`avatarUrl` 等;未落库前可为占位结构) - `POST /api/client/v1/auth/refresh` - 入参:`{ refreshToken }` @@ -380,6 +397,7 @@ REDIS_KEY_PREFIX_ADMIN=chatone:admin - `id` (bigserial pk) - `phone` (varchar unique) - `nickname` (varchar) + - `avatar_url` (varchar, nullable) — 头像地址(HTTPS 对象存储或 CDN URL);为空时客户端展示默认头像 - `status` (smallint, 1正常 0禁用) - `created_at`, `updated_at` diff --git a/package.json b/package.json index 35ab5bf..bbd05d1 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "start": "node dist/main.js", "start:dev": "tsx watch src/main.ts", "start:debug": "node --inspect=0.0.0.0:9229 dist/main.js", - "lint": "eslint \"src/**/*.ts\"" + "lint": "eslint \"src/**/*.ts\"", + "postinstall": "prisma generate" }, "dependencies": { "@fastify/static": "^9.1.1", @@ -25,15 +26,18 @@ "@nestjs/schedule": "^6.1.3", "@nestjs/swagger": "^11.3.0", "@nestjs/throttler": "^6.5.0", + "@prisma/adapter-pg": "^7.7.0", "@prisma/client": "^7.7.0", "class-transformer": "^0.5.1", "class-validator": "^0.15.1", "dayjs": "^1.11.20", + "dotenv": "^17.4.2", "helmet": "^8.1.0", "ioredis": "^5.10.1", "nestjs-pino": "^4.6.1", "passport": "^0.7.0", "passport-jwt": "^4.0.1", + "pg": "^8.20.0", "pino-http": "^11.0.0", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2", diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000..4cf3d4f --- /dev/null +++ b/prisma.config.ts @@ -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 || '', + }, +}); diff --git a/prisma/migrations/20260421164244_init_users/migration.sql b/prisma/migrations/20260421164244_init_users/migration.sql new file mode 100644 index 0000000..2446280 --- /dev/null +++ b/prisma/migrations/20260421164244_init_users/migration.sql @@ -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"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -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" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..780dac8 --- /dev/null +++ b/prisma/schema.prisma @@ -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") +} diff --git a/src/app.module.ts b/src/app.module.ts index 1122812..01b757b 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,6 +4,7 @@ import { LoggerModule } from 'nestjs-pino'; import { ClientAppModule } from './apps/client-app/client-app.module'; import { AdminAppModule } from './apps/admin-app/admin-app.module'; import { RedisModule } from './apps/shared-domain/cache/redis.module'; +import { PrismaModule } from './prisma/prisma.module'; import configuration from './config/configuration'; import { validateEnv } from './config/validation'; @@ -25,6 +26,7 @@ import { validateEnv } from './config/validation'; : undefined, }, }), + PrismaModule, RedisModule, ClientAppModule, AdminAppModule, diff --git a/src/apps/client-app/auth/client-auth.service.ts b/src/apps/client-app/auth/client-auth.service.ts index c4cc97e..5ee3592 100644 --- a/src/apps/client-app/auth/client-auth.service.ts +++ b/src/apps/client-app/auth/client-auth.service.ts @@ -9,6 +9,7 @@ import { JwtService } from '@nestjs/jwt'; import { randomUUID } from 'crypto'; import { SmsService } from '@shared/sms/sms.service'; import { RedisService } from '@shared/cache/redis.service'; +import { PrismaService } from '@prisma/prisma.service'; interface AccessPayload { sub: string; @@ -41,6 +42,8 @@ export class ClientAuthService { private readonly smsService: SmsService, @Inject(RedisService) private readonly redisService: RedisService, + @Inject(PrismaService) + private readonly prisma: PrismaService, ) {} async sendSmsCode(phone: string, scene: string) { @@ -89,7 +92,21 @@ export class ClientAuthService { } 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({ sub: userId, phone, @@ -108,6 +125,8 @@ export class ClientAuthService { user: { id: userId, phone, + nickname: user.nickname ?? '', + avatarUrl: user.avatarUrl ?? '', }, }; } @@ -126,9 +145,23 @@ export class ClientAuthService { 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({ - sub: payload.sub, - phone: payload.sub.replace('u_', ''), + sub: String(user.id), + phone: user.phone, role: 'client', type: 'access', }); diff --git a/src/main.ts b/src/main.ts index 69eb6c7..d0332f0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import 'reflect-metadata'; import { Logger } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts index 9e079d8..3f34afa 100644 --- a/src/prisma/prisma.service.ts +++ b/src/prisma/prisma.service.ts @@ -1,18 +1,23 @@ -import { - INestApplication, - Injectable, - OnModuleDestroy, - OnModuleInit, -} from '@nestjs/common'; -// Prisma v7 默认导出 PrismaClient -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { PrismaClient } = require('@prisma/client'); +import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; +import { PrismaPg } from '@prisma/adapter-pg'; @Injectable() export class PrismaService extends PrismaClient 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() { await this.$connect(); } @@ -20,11 +25,5 @@ export class PrismaService async onModuleDestroy() { await this.$disconnect(); } - - async enableShutdownHooks(app: INestApplication) { - this.$on('beforeExit', async () => { - await app.close(); - }); - } } diff --git a/yarn.lock b/yarn.lock index 1139fd8..d6fffc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -465,6 +465,16 @@ resolved "https://registry.npmmirror.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6" 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": version "7.7.0" 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" 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": version "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711" resolved "https://registry.npmmirror.com/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz#2bdc8c2a9b2b1612f484a9e50c988655b69bbe89" @@ -717,6 +734,15 @@ dependencies: 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": version "13.15.10" 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" 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: version "1.0.11" 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" 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: version "3.0.0" 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" 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: version "3.4.7" resolved "https://registry.npmmirror.com/postgres/-/postgres-3.4.7.tgz#122f460a808fe300cae53f592108b9906e625345" @@ -2157,7 +2271,7 @@ sonic-boom@^4.0.1: dependencies: atomic-sleep "^1.0.0" -split2@^4.0.0: +split2@^4.0.0, split2@^4.1.0: version "4.2.0" resolved "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== @@ -2344,6 +2458,11 @@ wrappy@1: resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 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: version "3.1.1" resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"