@chidchanun/bcp 0.1.24 → 0.1.26

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.
@@ -0,0 +1,236 @@
1
+ // packages/client/src/database.ts
2
+ var MYSQL_MODULE_SPECIFIER = "mysql2/promise";
3
+ var BcpDatabase = class {
4
+ options;
5
+ poolPromise = null;
6
+ constructor(options = {}) {
7
+ this.options = {
8
+ ...options
9
+ };
10
+ }
11
+ async query(sql, parameters) {
12
+ assertSql(sql);
13
+ const pool = await this.getPool();
14
+ const [rows] = await pool.query(
15
+ sql,
16
+ parameters
17
+ );
18
+ return rows;
19
+ }
20
+ async execute(sql, parameters) {
21
+ assertSql(sql);
22
+ const pool = await this.getPool();
23
+ const [result] = await pool.execute(
24
+ sql,
25
+ parameters
26
+ );
27
+ return result;
28
+ }
29
+ async transaction(callback) {
30
+ if (typeof callback !== "function") {
31
+ throw new TypeError(
32
+ "BCP Database: transaction callback must be a function."
33
+ );
34
+ }
35
+ const pool = await this.getPool();
36
+ const connection = await pool.getConnection();
37
+ await connection.beginTransaction();
38
+ const transactionDatabase = {
39
+ query: async (sql, parameters) => {
40
+ assertSql(sql);
41
+ const [rows] = await connection.query(
42
+ sql,
43
+ parameters
44
+ );
45
+ return rows;
46
+ },
47
+ execute: async (sql, parameters) => {
48
+ assertSql(sql);
49
+ const [result] = await connection.execute(
50
+ sql,
51
+ parameters
52
+ );
53
+ return result;
54
+ }
55
+ };
56
+ try {
57
+ const result = await callback(
58
+ transactionDatabase
59
+ );
60
+ await connection.commit();
61
+ return result;
62
+ } catch (error) {
63
+ try {
64
+ await connection.rollback();
65
+ } catch {
66
+ }
67
+ throw error;
68
+ } finally {
69
+ connection.release();
70
+ }
71
+ }
72
+ async close() {
73
+ const pendingPool = this.poolPromise;
74
+ this.poolPromise = null;
75
+ if (!pendingPool) {
76
+ return;
77
+ }
78
+ const pool = await pendingPool;
79
+ await pool.end();
80
+ }
81
+ getPool() {
82
+ if (!this.poolPromise) {
83
+ this.poolPromise = createMysqlPool(
84
+ resolveDatabaseOptions(
85
+ this.options
86
+ )
87
+ );
88
+ }
89
+ return this.poolPromise;
90
+ }
91
+ };
92
+ function createDatabase(options = {}) {
93
+ return new BcpDatabase(
94
+ options
95
+ );
96
+ }
97
+ function resolveDatabaseOptions(options = {}, environment = process.env) {
98
+ const driver = options.driver ?? normalizeDriver(
99
+ environment.DB_DRIVER ?? "mysql"
100
+ );
101
+ if (driver !== "mysql") {
102
+ throw new Error(
103
+ `BCP Database: unsupported database driver "${driver}".`
104
+ );
105
+ }
106
+ return {
107
+ driver,
108
+ host: nonEmpty(
109
+ options.host ?? environment.DB_HOST
110
+ ) ?? "localhost",
111
+ port: resolvePositiveInteger(
112
+ options.port ?? environment.DB_PORT,
113
+ 3306,
114
+ "DB_PORT"
115
+ ),
116
+ user: nonEmpty(
117
+ options.user ?? environment.DB_USER
118
+ ) ?? "root",
119
+ password: String(
120
+ options.password ?? environment.DB_PASSWORD ?? ""
121
+ ),
122
+ database: nonEmpty(
123
+ options.database ?? environment.DB_NAME
124
+ ) ?? "bcp_app",
125
+ connectionLimit: resolvePositiveInteger(
126
+ options.connectionLimit ?? environment.DB_CONNECTION_LIMIT,
127
+ 10,
128
+ "DB_CONNECTION_LIMIT"
129
+ ),
130
+ waitForConnections: options.waitForConnections ?? resolveBoolean(
131
+ environment.DB_WAIT_FOR_CONNECTIONS,
132
+ true,
133
+ "DB_WAIT_FOR_CONNECTIONS"
134
+ ),
135
+ queueLimit: resolveNonNegativeInteger(
136
+ options.queueLimit ?? environment.DB_QUEUE_LIMIT,
137
+ 0,
138
+ "DB_QUEUE_LIMIT"
139
+ ),
140
+ charset: nonEmpty(
141
+ options.charset ?? environment.DB_CHARSET
142
+ ) ?? "utf8mb4"
143
+ };
144
+ }
145
+ var db = createDatabase();
146
+ async function createMysqlPool(options) {
147
+ let mysqlModule;
148
+ try {
149
+ mysqlModule = await import(MYSQL_MODULE_SPECIFIER);
150
+ } catch (error) {
151
+ throw new Error(
152
+ "BCP Database: MySQL requires the optional dependency mysql2. Install it with `npm install mysql2` or create the app with the MySQL preset.",
153
+ {
154
+ cause: error
155
+ }
156
+ );
157
+ }
158
+ return mysqlModule.createPool({
159
+ host: options.host,
160
+ port: options.port,
161
+ user: options.user,
162
+ password: options.password,
163
+ database: options.database,
164
+ waitForConnections: options.waitForConnections,
165
+ connectionLimit: options.connectionLimit,
166
+ queueLimit: options.queueLimit,
167
+ charset: options.charset
168
+ });
169
+ }
170
+ function normalizeDriver(value) {
171
+ const normalized = value.trim().toLowerCase();
172
+ if (normalized === "mysql") {
173
+ return "mysql";
174
+ }
175
+ throw new Error(
176
+ `BCP Database: unsupported database driver "${value}".`
177
+ );
178
+ }
179
+ function nonEmpty(value) {
180
+ if (typeof value !== "string") {
181
+ return null;
182
+ }
183
+ const normalized = value.trim();
184
+ return normalized || null;
185
+ }
186
+ function resolvePositiveInteger(value, fallback, label) {
187
+ if (value === void 0 || value === null || value === "") {
188
+ return fallback;
189
+ }
190
+ const parsed = Number(value);
191
+ if (!Number.isInteger(parsed) || parsed <= 0) {
192
+ throw new Error(
193
+ `BCP Database: ${label} must be a positive integer.`
194
+ );
195
+ }
196
+ return parsed;
197
+ }
198
+ function resolveNonNegativeInteger(value, fallback, label) {
199
+ if (value === void 0 || value === null || value === "") {
200
+ return fallback;
201
+ }
202
+ const parsed = Number(value);
203
+ if (!Number.isInteger(parsed) || parsed < 0) {
204
+ throw new Error(
205
+ `BCP Database: ${label} must be a non-negative integer.`
206
+ );
207
+ }
208
+ return parsed;
209
+ }
210
+ function resolveBoolean(value, fallback, label) {
211
+ if (value === void 0 || value === null || value === "") {
212
+ return fallback;
213
+ }
214
+ if (value === true || value === "1" || value === "true") {
215
+ return true;
216
+ }
217
+ if (value === false || value === "0" || value === "false") {
218
+ return false;
219
+ }
220
+ throw new Error(
221
+ `BCP Database: ${label} must be true/false or 1/0.`
222
+ );
223
+ }
224
+ function assertSql(sql) {
225
+ if (typeof sql !== "string" || sql.trim() === "") {
226
+ throw new TypeError(
227
+ "BCP Database: SQL must be a non-empty string."
228
+ );
229
+ }
230
+ }
231
+ export {
232
+ BcpDatabase,
233
+ createDatabase,
234
+ db,
235
+ resolveDatabaseOptions
236
+ };
@@ -46,6 +46,52 @@ export {
46
46
  type UploadErrorCode,
47
47
  } from "../../server/src/upload.js";
48
48
 
49
+ export {
50
+ storeMultipartFile,
51
+
52
+ type MultipartStorageFileInfo,
53
+ type MultipartStorageUploadOptions,
54
+ type StoredMultipartFile,
55
+ } from "../../server/src/upload-stream.js";
56
+
57
+ export {
58
+ createLocalStorage,
59
+ getStorageCapabilities,
60
+ normalizeStorageKey,
61
+ putStorageStream,
62
+ readStorageStream,
63
+ StorageError,
64
+ storeUploadedFile,
65
+
66
+ type LocalStorageOptions,
67
+ type StorageAdapter,
68
+ type StorageAdapterCapabilities,
69
+ type StorageErrorCode,
70
+ type StorageObjectMetadata,
71
+ type StoragePutOptions,
72
+ type StoragePutStreamOptions,
73
+ type StorageReadableStream,
74
+ type StorageReadOptions,
75
+ type StorageWriteValue,
76
+ type StoredUploadedObject,
77
+ type StoreUploadedFileOptions,
78
+ } from "../../server/src/storage.js";
79
+
80
+ export {
81
+ createS3Storage,
82
+
83
+ type S3StorageAdapter,
84
+ type S3StorageMultipartOptions,
85
+ type S3StorageOptions,
86
+ } from "../../server/src/storage-s3.js";
87
+
88
+ export {
89
+ createStorageResponse,
90
+ isStorageRangeError,
91
+
92
+ type StorageResponseOptions,
93
+ } from "../../server/src/file-delivery.js";
94
+
49
95
  export {
50
96
  json,
51
97
  redirect,