@yayoyunlm/utils_sql_storage 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,93 @@
1
- createDbClient(
2
- PrismaClientConstructor: typeof PrismaClient, // 外部传入的 Prisma 构造函数
3
- connectionString: string // PostgreSQL 连接字符串
4
- ): PrismaClient // 返回配置好的 Prisma 客户端实例
1
+ # @yayoyunlm/utils_sql_storage 简易使用手册
2
+ 这个工具包只有 **2个核心功能**:
3
+ 1. 快速连接 PostgreSQL 数据库
4
+ 2. 上传文件到 T3/S3 云存储
5
+ **Monorepo 直接用,不用打包编译!**
5
6
 
7
+ ---
6
8
 
7
- // 1. 获取数据库连接字符串(环境变量)
8
- const DATABASE_URL = process.env.DATABASE_URL!;
9
- PrismaClient=schema.prismaoutput
9
+ ## 一、数据库工具(createDbClient)
10
+ ### 作用
11
+ 帮你快速创建 Prisma + PostgreSQL 数据库连接,不用写重复代码。
10
12
 
11
- // 2. 传入 PrismaClient + 连接串,创建实例
12
- const db = createDbClient(PrismaClient, DATABASE_URL);
13
+ ### 使用步骤
14
+ 1. 项目安装依赖
15
+ ```bash
16
+ pnpm add @prisma/client pg @prisma/adapter-pg
17
+ ```
13
18
 
14
- // 3. 导出供全局使用
15
- export default db;
19
+ 2. 直接复制代码使用
20
+ ```ts
21
+ // 引入工具和类型
22
+ import { createDbClient } from '@yayoyunlm/utils_sql_storage';
23
+ import { PrismaClient } from '@prisma/client';
24
+
25
+ // 创建数据库客户端(替换成你的数据库链接)
26
+ const db = createDbClient(PrismaClient, "postgresql://你的数据库连接字符串");
27
+
28
+ // 使用示例(接口/服务中直接用)
29
+ async function getList() {
30
+ return await db.表名.findMany();
31
+ }
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 二、文件上传工具(S3Uploader)
37
+ ### 作用
38
+ 上传文件到 T3 Storage / AWS S3,**适配 Next.js 接口**,region 默认自动配置,不用管。
39
+
40
+ ### 1. 安装依赖
41
+ ```bash
42
+ pnpm add @aws-sdk/client-s3
43
+ ```
44
+
45
+ ### 2. 完整使用示例(Next.js 上传接口)
46
+ 直接复制就能用,改下密钥即可:
47
+ ```ts
48
+ import { NextRequest, NextResponse } from 'next/server';
49
+ import { S3Uploader } from '@yayoyunlm/utils_sql_storage';
50
+
51
+ // 配置你的存储信息
52
+ const s3Config = {
53
+ endpoint: '',
54
+ bucket: '',
55
+ accessKeyId: '你的密钥ID',
56
+ secretAccessKey: '你的密钥',
57
+ };
58
+
59
+ // 上传接口
60
+ export async function POST(req: NextRequest) {
61
+ try {
62
+ const formData = await req.formData();
63
+ const file = formData.get('file') as File;
64
+
65
+ if (!file) {
66
+ return NextResponse.json({ error: '请选择文件' }, { status: 400 });
67
+ }
68
+
69
+ // 创建上传实例
70
+ const uploader = new S3Uploader(s3Config);
71
+ const buffer = Buffer.from(await file.arrayBuffer());
72
+
73
+ // 执行上传
74
+ const result = await uploader.upload(buffer, file.name, file.type);
75
+
76
+ return NextResponse.json(result);
77
+ } catch (error) {
78
+ return NextResponse.json({ error: '上传失败' }, { status: 500 });
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### 3. 重要默认配置(不用改)
84
+ `region` 自动默认为 `auto`,适配 T3 Storage,**不需要手动填写**。
85
+
86
+ ---
87
+
88
+ ## 三、使用小提示
89
+ 1. **Monorepo 专属**:修改工具包源码后,**重启 Next.js 服务** 就生效,不用执行 `build`
90
+ 2. 报错排查:
91
+ - 配置缺失:检查 endpoint、bucket、密钥是否正确
92
+ - 上传失败:检查云存储权限/密钥
93
+ 3. 所有代码复制粘贴即可使用,无需额外配置
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ S3Uploader: () => S3Uploader,
23
34
  createDbClient: () => createDbClient
24
35
  });
25
36
  module.exports = __toCommonJS(index_exports);
@@ -32,7 +43,95 @@ function createDbClient(PrismaClientConstructor, connectionString) {
32
43
  const adapter = new import_adapter_pg.PrismaPg(pool);
33
44
  return new PrismaClientConstructor({ adapter });
34
45
  }
46
+
47
+ // linkstorage.ts
48
+ var import_fs = __toESM(require("fs"), 1);
49
+ var import_client_s3 = require("@aws-sdk/client-s3");
50
+ var S3Uploader = class _S3Uploader {
51
+ // 1. 静态属性:初始化为 undefined,支持“不传”
52
+ static endpoint = void 0;
53
+ static bucket = void 0;
54
+ static region = void 0;
55
+ static accessKeyId = void 0;
56
+ static secretAccessKey = void 0;
57
+ // 2. 实例属性:定义为 string,确保实例化后一定是字符串(哪怕是空的)
58
+ bucket;
59
+ endpoint;
60
+ region;
61
+ s3Client;
62
+ constructor(config) {
63
+ this.endpoint = config?.endpoint ?? _S3Uploader.endpoint ?? "";
64
+ this.bucket = config?.bucket ?? _S3Uploader.bucket ?? "";
65
+ this.region = config?.region ?? _S3Uploader.region ?? "auto";
66
+ const accessKeyId = config?.accessKeyId ?? _S3Uploader.accessKeyId ?? "";
67
+ const secretAccessKey = config?.secretAccessKey ?? _S3Uploader.secretAccessKey ?? "";
68
+ if (!this.endpoint || !this.bucket || !accessKeyId || !secretAccessKey) {
69
+ throw new Error(
70
+ "S3\u914D\u7F6E\u7F3A\u5931\uFF1A\u8BF7\u786E\u4FDD\u8BBE\u7F6E\u4E86\u9759\u6001\u5C5E\u6027\uFF0C\u6216\u5728 new \u65F6\u4F20\u5165\u5B8C\u6574\u914D\u7F6E"
71
+ );
72
+ }
73
+ this.s3Client = new import_client_s3.S3Client({
74
+ endpoint: this.endpoint,
75
+ region: this.region,
76
+ // AWS SDK 支持 region 为空字符串或 undefined
77
+ credentials: {
78
+ accessKeyId,
79
+ secretAccessKey
80
+ },
81
+ forcePathStyle: true
82
+ });
83
+ }
84
+ // 5. 核心修复:支持 Buffer | string
85
+ // 这样既支持本地路径,也支持 Next.js 的 file.arrayBuffer()
86
+ async upload(fileContent, s3Path, contentType = "application/octet-stream") {
87
+ try {
88
+ const normalizedKey = s3Path.replace(/^\//, "");
89
+ const body = typeof fileContent === "string" ? import_fs.default.createReadStream(fileContent) : fileContent;
90
+ const command = new import_client_s3.PutObjectCommand({
91
+ Bucket: this.bucket,
92
+ Key: normalizedKey,
93
+ Body: body,
94
+ ContentType: contentType
95
+ });
96
+ await this.s3Client.send(command);
97
+ const baseUrl = this.endpoint.endsWith("/") ? this.endpoint.slice(0, -1) : this.endpoint;
98
+ const url = `${baseUrl}/${this.bucket}/${normalizedKey}`;
99
+ return {
100
+ success: true,
101
+ url,
102
+ s3Path: normalizedKey
103
+ };
104
+ } catch (err) {
105
+ console.error("\u4E0A\u4F20\u5931\u8D25", err);
106
+ return {
107
+ success: false,
108
+ error: err instanceof Error ? err.message : "\u672A\u77E5\u9519\u8BEF"
109
+ };
110
+ }
111
+ }
112
+ async delete(s3Path) {
113
+ try {
114
+ const normalizedKey = s3Path.replace(/^\//, "");
115
+ const command = new import_client_s3.DeleteObjectCommand({
116
+ Bucket: this.bucket,
117
+ Key: normalizedKey
118
+ });
119
+ await this.s3Client.send(command);
120
+ return {
121
+ success: true,
122
+ s3Path: normalizedKey
123
+ };
124
+ } catch (err) {
125
+ console.error("\u5220\u9664\u5931\u8D25", err);
126
+ return {
127
+ success: false,
128
+ error: err instanceof Error ? err.message : "\u672A\u77E5\u9519\u8BEF"
129
+ };
130
+ }
131
+ }
132
+ };
35
133
  // Annotate the CommonJS export names for ESM import in node:
36
134
  0 && (module.exports = {
135
+ S3Uploader,
37
136
  createDbClient
38
137
  });
package/dist/index.d.cts CHANGED
@@ -13,4 +13,38 @@ declare function createDbClient(PrismaClientConstructor: typeof PrismaClient, co
13
13
  adapter: PrismaPg;
14
14
  }, never, _prisma_client_runtime_client.DefaultArgs>;
15
15
 
16
- export { createDbClient };
16
+ interface S3UploaderConfig {
17
+ endpoint?: string;
18
+ bucket?: string;
19
+ region?: string;
20
+ accessKeyId?: string;
21
+ secretAccessKey?: string;
22
+ }
23
+ interface UploadResult {
24
+ success: boolean;
25
+ url?: string;
26
+ s3Path?: string;
27
+ error?: string;
28
+ }
29
+ interface DeleteResult {
30
+ success: boolean;
31
+ s3Path?: string;
32
+ error?: string;
33
+ }
34
+ declare class S3Uploader {
35
+ static endpoint: string | undefined;
36
+ static bucket: string | undefined;
37
+ static region: string | undefined;
38
+ static accessKeyId: string | undefined;
39
+ static secretAccessKey: string | undefined;
40
+ private readonly bucket;
41
+ private readonly endpoint;
42
+ private readonly region;
43
+ private readonly s3Client;
44
+ constructor(config?: S3UploaderConfig);
45
+ upload(fileContent: string | Buffer, // 接收文件路径 或 文件二进制流
46
+ s3Path: string, contentType?: string): Promise<UploadResult>;
47
+ delete(s3Path: string): Promise<DeleteResult>;
48
+ }
49
+
50
+ export { type DeleteResult, S3Uploader, type S3UploaderConfig, type UploadResult, createDbClient };
package/dist/index.d.ts CHANGED
@@ -13,4 +13,38 @@ declare function createDbClient(PrismaClientConstructor: typeof PrismaClient, co
13
13
  adapter: PrismaPg;
14
14
  }, never, _prisma_client_runtime_client.DefaultArgs>;
15
15
 
16
- export { createDbClient };
16
+ interface S3UploaderConfig {
17
+ endpoint?: string;
18
+ bucket?: string;
19
+ region?: string;
20
+ accessKeyId?: string;
21
+ secretAccessKey?: string;
22
+ }
23
+ interface UploadResult {
24
+ success: boolean;
25
+ url?: string;
26
+ s3Path?: string;
27
+ error?: string;
28
+ }
29
+ interface DeleteResult {
30
+ success: boolean;
31
+ s3Path?: string;
32
+ error?: string;
33
+ }
34
+ declare class S3Uploader {
35
+ static endpoint: string | undefined;
36
+ static bucket: string | undefined;
37
+ static region: string | undefined;
38
+ static accessKeyId: string | undefined;
39
+ static secretAccessKey: string | undefined;
40
+ private readonly bucket;
41
+ private readonly endpoint;
42
+ private readonly region;
43
+ private readonly s3Client;
44
+ constructor(config?: S3UploaderConfig);
45
+ upload(fileContent: string | Buffer, // 接收文件路径 或 文件二进制流
46
+ s3Path: string, contentType?: string): Promise<UploadResult>;
47
+ delete(s3Path: string): Promise<DeleteResult>;
48
+ }
49
+
50
+ export { type DeleteResult, S3Uploader, type S3UploaderConfig, type UploadResult, createDbClient };
package/dist/index.js CHANGED
@@ -6,6 +6,94 @@ function createDbClient(PrismaClientConstructor, connectionString) {
6
6
  const adapter = new PrismaPg(pool);
7
7
  return new PrismaClientConstructor({ adapter });
8
8
  }
9
+
10
+ // linkstorage.ts
11
+ import fs from "fs";
12
+ import { S3Client, PutObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
13
+ var S3Uploader = class _S3Uploader {
14
+ // 1. 静态属性:初始化为 undefined,支持“不传”
15
+ static endpoint = void 0;
16
+ static bucket = void 0;
17
+ static region = void 0;
18
+ static accessKeyId = void 0;
19
+ static secretAccessKey = void 0;
20
+ // 2. 实例属性:定义为 string,确保实例化后一定是字符串(哪怕是空的)
21
+ bucket;
22
+ endpoint;
23
+ region;
24
+ s3Client;
25
+ constructor(config) {
26
+ this.endpoint = config?.endpoint ?? _S3Uploader.endpoint ?? "";
27
+ this.bucket = config?.bucket ?? _S3Uploader.bucket ?? "";
28
+ this.region = config?.region ?? _S3Uploader.region ?? "auto";
29
+ const accessKeyId = config?.accessKeyId ?? _S3Uploader.accessKeyId ?? "";
30
+ const secretAccessKey = config?.secretAccessKey ?? _S3Uploader.secretAccessKey ?? "";
31
+ if (!this.endpoint || !this.bucket || !accessKeyId || !secretAccessKey) {
32
+ throw new Error(
33
+ "S3\u914D\u7F6E\u7F3A\u5931\uFF1A\u8BF7\u786E\u4FDD\u8BBE\u7F6E\u4E86\u9759\u6001\u5C5E\u6027\uFF0C\u6216\u5728 new \u65F6\u4F20\u5165\u5B8C\u6574\u914D\u7F6E"
34
+ );
35
+ }
36
+ this.s3Client = new S3Client({
37
+ endpoint: this.endpoint,
38
+ region: this.region,
39
+ // AWS SDK 支持 region 为空字符串或 undefined
40
+ credentials: {
41
+ accessKeyId,
42
+ secretAccessKey
43
+ },
44
+ forcePathStyle: true
45
+ });
46
+ }
47
+ // 5. 核心修复:支持 Buffer | string
48
+ // 这样既支持本地路径,也支持 Next.js 的 file.arrayBuffer()
49
+ async upload(fileContent, s3Path, contentType = "application/octet-stream") {
50
+ try {
51
+ const normalizedKey = s3Path.replace(/^\//, "");
52
+ const body = typeof fileContent === "string" ? fs.createReadStream(fileContent) : fileContent;
53
+ const command = new PutObjectCommand({
54
+ Bucket: this.bucket,
55
+ Key: normalizedKey,
56
+ Body: body,
57
+ ContentType: contentType
58
+ });
59
+ await this.s3Client.send(command);
60
+ const baseUrl = this.endpoint.endsWith("/") ? this.endpoint.slice(0, -1) : this.endpoint;
61
+ const url = `${baseUrl}/${this.bucket}/${normalizedKey}`;
62
+ return {
63
+ success: true,
64
+ url,
65
+ s3Path: normalizedKey
66
+ };
67
+ } catch (err) {
68
+ console.error("\u4E0A\u4F20\u5931\u8D25", err);
69
+ return {
70
+ success: false,
71
+ error: err instanceof Error ? err.message : "\u672A\u77E5\u9519\u8BEF"
72
+ };
73
+ }
74
+ }
75
+ async delete(s3Path) {
76
+ try {
77
+ const normalizedKey = s3Path.replace(/^\//, "");
78
+ const command = new DeleteObjectCommand({
79
+ Bucket: this.bucket,
80
+ Key: normalizedKey
81
+ });
82
+ await this.s3Client.send(command);
83
+ return {
84
+ success: true,
85
+ s3Path: normalizedKey
86
+ };
87
+ } catch (err) {
88
+ console.error("\u5220\u9664\u5931\u8D25", err);
89
+ return {
90
+ success: false,
91
+ error: err instanceof Error ? err.message : "\u672A\u77E5\u9519\u8BEF"
92
+ };
93
+ }
94
+ }
95
+ };
9
96
  export {
97
+ S3Uploader,
10
98
  createDbClient
11
99
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yayoyunlm/utils_sql_storage",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "TypeScript library build with tsup",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -18,13 +18,15 @@
18
18
  "typescript": "^5",
19
19
  "@types/pg": "^8.11.0",
20
20
  "@prisma/client": "^7.8.0",
21
- "@prisma/adapter-pg": "^7.8.0"
21
+ "@prisma/adapter-pg": "^7.8.0",
22
+ "@aws-sdk/client-s3": "^3.1048.0"
22
23
  },
23
24
  "peerDependencies": {
24
25
  "pg": "^8.20.0",
25
26
  "prisma": "^7.8.0",
26
27
  "@prisma/client": "^7.8.0",
27
- "@prisma/adapter-pg": "^7.8.0"
28
+ "@prisma/adapter-pg": "^7.8.0",
29
+ "@aws-sdk/client-s3": "^3.1048.0"
28
30
  },
29
31
  "scripts": {
30
32
  "build": "tsup index.ts --format cjs,esm --dts"