@wowsql/sdk 3.4.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/CHANGELOG.md +296 -0
- package/LICENSE +22 -0
- package/README.md +990 -0
- package/dist/auth.d.ts +160 -0
- package/dist/auth.js +320 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +12 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.js +264 -0
- package/dist/schema.d.ts +58 -0
- package/dist/schema.js +116 -0
- package/dist/storage.d.ts +395 -0
- package/dist/storage.js +404 -0
- package/package.json +65 -0
package/dist/storage.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WowSQL Storage SDK - S3 Storage management with automatic quota validation
|
|
4
|
+
*
|
|
5
|
+
* @version 2.1.0
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.WowSQLStorage = exports.StorageLimitExceededError = exports.StorageError = void 0;
|
|
46
|
+
const axios_1 = __importDefault(require("axios"));
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
class StorageError extends Error {
|
|
49
|
+
constructor(message, statusCode, response) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.statusCode = statusCode;
|
|
52
|
+
this.response = response;
|
|
53
|
+
this.name = 'StorageError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.StorageError = StorageError;
|
|
57
|
+
class StorageLimitExceededError extends StorageError {
|
|
58
|
+
constructor(message, statusCode, response) {
|
|
59
|
+
super(message, statusCode, response);
|
|
60
|
+
this.name = 'StorageLimitExceededError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.StorageLimitExceededError = StorageLimitExceededError;
|
|
64
|
+
// ==================== Storage Client ====================
|
|
65
|
+
/**
|
|
66
|
+
* WowSQL Storage Client - Manage S3 storage with automatic quota validation
|
|
67
|
+
*
|
|
68
|
+
* Features:
|
|
69
|
+
* - Automatic storage limit validation before upload
|
|
70
|
+
* - Real-time quota checking
|
|
71
|
+
* - File upload/download/delete operations
|
|
72
|
+
* - Presigned URL generation
|
|
73
|
+
* - Storage provisioning and management
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const storage = new WowSQLStorage({
|
|
78
|
+
* projectSlug: 'myproject',
|
|
79
|
+
* apiKey: 'your_api_key'
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* // Check quota
|
|
83
|
+
* const quota = await storage.getQuota();
|
|
84
|
+
* console.log(`Available: ${quota.storage_available_gb.toFixed(2)} GB`);
|
|
85
|
+
*
|
|
86
|
+
* // Upload file (auto-validates limits)
|
|
87
|
+
* const fileBuffer = fs.readFileSync('document.pdf');
|
|
88
|
+
* const result = await storage.uploadFile(fileBuffer, 'document.pdf', {
|
|
89
|
+
* folder: 'documents'
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // List files
|
|
93
|
+
* const files = await storage.listFiles({ prefix: 'documents/' });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
class WowSQLStorage {
|
|
97
|
+
constructor(config) {
|
|
98
|
+
this.projectSlug = config.projectSlug;
|
|
99
|
+
this.autoCheckQuota = config.autoCheckQuota !== false;
|
|
100
|
+
const baseUrl = config.baseUrl || 'https://api.wowsql.com';
|
|
101
|
+
// Create axios instance
|
|
102
|
+
this.client = axios_1.default.create({
|
|
103
|
+
baseURL: baseUrl,
|
|
104
|
+
headers: {
|
|
105
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
106
|
+
},
|
|
107
|
+
timeout: config.timeout || 60000, // 60s default for file uploads
|
|
108
|
+
});
|
|
109
|
+
// Add error interceptor
|
|
110
|
+
this.client.interceptors.response.use((response) => response, (error) => {
|
|
111
|
+
if (error.response) {
|
|
112
|
+
const errorData = error.response.data;
|
|
113
|
+
const errorMessage = errorData?.detail || errorData?.message || error.message;
|
|
114
|
+
// Check for storage limit exceeded
|
|
115
|
+
if (error.response.status === 413) {
|
|
116
|
+
throw new StorageLimitExceededError(errorMessage, error.response.status, errorData);
|
|
117
|
+
}
|
|
118
|
+
throw new StorageError(errorMessage, error.response.status, errorData);
|
|
119
|
+
}
|
|
120
|
+
throw new StorageError(error.message);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get storage quota and usage information
|
|
125
|
+
*
|
|
126
|
+
* @param forceRefresh - Force refresh quota from server (default: false)
|
|
127
|
+
* @returns Storage quota details
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const quota = await storage.getQuota();
|
|
132
|
+
* console.log(`Used: ${quota.storage_used_gb} GB`);
|
|
133
|
+
* console.log(`Available: ${quota.storage_available_gb} GB`);
|
|
134
|
+
* console.log(`Usage: ${quota.usage_percentage}%`);
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
async getQuota(forceRefresh = false) {
|
|
138
|
+
if (this.quotaCache && !forceRefresh) {
|
|
139
|
+
return this.quotaCache;
|
|
140
|
+
}
|
|
141
|
+
const response = await this.client.get(`/api/v1/storage/s3/projects/${this.projectSlug}/quota`);
|
|
142
|
+
this.quotaCache = response.data;
|
|
143
|
+
return response.data;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check if file upload is allowed based on storage quota
|
|
147
|
+
*
|
|
148
|
+
* @param fileSizeBytes - Size of file to upload in bytes
|
|
149
|
+
* @returns Object with allowed status and message
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* const fileSize = 1024 * 1024 * 500; // 500 MB
|
|
154
|
+
* const check = await storage.checkUploadAllowed(fileSize);
|
|
155
|
+
* if (!check.allowed) {
|
|
156
|
+
* console.error(check.message);
|
|
157
|
+
* }
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
async checkUploadAllowed(fileSizeBytes) {
|
|
161
|
+
const quota = await this.getQuota(true);
|
|
162
|
+
const fileSizeGB = fileSizeBytes / (1024 ** 3);
|
|
163
|
+
if (fileSizeGB > quota.storage_available_gb) {
|
|
164
|
+
return {
|
|
165
|
+
allowed: false,
|
|
166
|
+
message: `Storage limit exceeded! File size: ${fileSizeGB.toFixed(4)} GB, ` +
|
|
167
|
+
`Available: ${quota.storage_available_gb.toFixed(4)} GB. ` +
|
|
168
|
+
`Upgrade your plan to get more storage.`
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
allowed: true,
|
|
173
|
+
message: `Upload allowed. ${quota.storage_available_gb.toFixed(4)} GB available.`
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Upload a file to S3 storage with automatic quota validation
|
|
178
|
+
*
|
|
179
|
+
* @param fileData - File data as Buffer or Blob
|
|
180
|
+
* @param fileName - File name
|
|
181
|
+
* @param options - Upload options
|
|
182
|
+
* @returns Upload result
|
|
183
|
+
*
|
|
184
|
+
* @throws {StorageLimitExceededError} If storage quota would be exceeded
|
|
185
|
+
* @throws {StorageError} If upload fails
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* // Node.js - from file
|
|
190
|
+
* const fileBuffer = fs.readFileSync('photo.jpg');
|
|
191
|
+
* const result = await storage.uploadFile(fileBuffer, 'photo.jpg', {
|
|
192
|
+
* folder: 'images',
|
|
193
|
+
* contentType: 'image/jpeg'
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* // Browser - from File input
|
|
197
|
+
* const file = document.querySelector('input[type="file"]').files[0];
|
|
198
|
+
* const arrayBuffer = await file.arrayBuffer();
|
|
199
|
+
* const result = await storage.uploadFile(
|
|
200
|
+
* Buffer.from(arrayBuffer),
|
|
201
|
+
* file.name,
|
|
202
|
+
* { folder: 'uploads' }
|
|
203
|
+
* );
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
async uploadFile(fileData, fileName, options) {
|
|
207
|
+
// Get file size
|
|
208
|
+
const fileSize = fileData instanceof Buffer ? fileData.length : fileData.size;
|
|
209
|
+
// Check quota if enabled
|
|
210
|
+
const shouldCheck = options?.checkQuota !== undefined ? options.checkQuota : this.autoCheckQuota;
|
|
211
|
+
if (shouldCheck) {
|
|
212
|
+
const check = await this.checkUploadAllowed(fileSize);
|
|
213
|
+
if (!check.allowed) {
|
|
214
|
+
throw new StorageLimitExceededError(check.message, 413);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Prepare form data
|
|
218
|
+
const formData = new FormData();
|
|
219
|
+
const blob = fileData instanceof Buffer ? new Blob([fileData]) : fileData;
|
|
220
|
+
formData.append('file', blob, fileName);
|
|
221
|
+
// Build URL with query params
|
|
222
|
+
const params = new URLSearchParams();
|
|
223
|
+
if (options?.folder) {
|
|
224
|
+
params.append('folder', options.folder);
|
|
225
|
+
}
|
|
226
|
+
const url = `/api/v1/storage/s3/projects/${this.projectSlug}/upload${params.toString() ? '?' + params.toString() : ''}`;
|
|
227
|
+
// Upload
|
|
228
|
+
const response = await this.client.post(url, formData, {
|
|
229
|
+
headers: {
|
|
230
|
+
'Content-Type': 'multipart/form-data',
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
// Clear quota cache after upload
|
|
234
|
+
this.quotaCache = undefined;
|
|
235
|
+
return response.data;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Upload a file from filesystem path (Node.js only)
|
|
239
|
+
*
|
|
240
|
+
* @param filePath - Path to local file
|
|
241
|
+
* @param fileName - Optional file name in bucket (defaults to filename)
|
|
242
|
+
* @param options - Upload options
|
|
243
|
+
* @returns Upload result
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const result = await storage.uploadFromPath(
|
|
248
|
+
* 'documents/report.pdf',
|
|
249
|
+
* 'report.pdf',
|
|
250
|
+
* { folder: 'reports' }
|
|
251
|
+
* );
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
async uploadFromPath(filePath, fileName, options) {
|
|
255
|
+
if (!fs.existsSync(filePath)) {
|
|
256
|
+
throw new Error(`File not found: ${filePath}`);
|
|
257
|
+
}
|
|
258
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
259
|
+
const name = fileName || filePath.split('/').pop() || 'file';
|
|
260
|
+
return this.uploadFile(fileBuffer, name, options);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* List files in S3 bucket
|
|
264
|
+
*
|
|
265
|
+
* @param options - List options
|
|
266
|
+
* @returns Array of storage files
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const files = await storage.listFiles({ prefix: 'documents/' });
|
|
271
|
+
* for (const file of files) {
|
|
272
|
+
* console.log(`${file.key}: ${(file.size / 1024 / 1024).toFixed(2)} MB`);
|
|
273
|
+
* }
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
async listFiles(options) {
|
|
277
|
+
const params = {};
|
|
278
|
+
if (options?.prefix)
|
|
279
|
+
params.prefix = options.prefix;
|
|
280
|
+
if (options?.maxKeys)
|
|
281
|
+
params.max_keys = options.maxKeys;
|
|
282
|
+
const response = await this.client.get(`/api/v1/storage/s3/projects/${this.projectSlug}/files`, { params });
|
|
283
|
+
return response.data.files || [];
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Delete a file from S3 bucket
|
|
287
|
+
*
|
|
288
|
+
* @param fileKey - Path to file in bucket
|
|
289
|
+
* @returns Deletion result
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```typescript
|
|
293
|
+
* const result = await storage.deleteFile('documents/old-file.pdf');
|
|
294
|
+
* console.log(result.message);
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
async deleteFile(fileKey) {
|
|
298
|
+
const response = await this.client.delete(`/api/v1/storage/s3/projects/${this.projectSlug}/files/${fileKey}`);
|
|
299
|
+
// Clear quota cache after delete
|
|
300
|
+
this.quotaCache = undefined;
|
|
301
|
+
return response.data;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get presigned URL for file access
|
|
305
|
+
*
|
|
306
|
+
* @param fileKey - Path to file in bucket
|
|
307
|
+
* @param expiresIn - URL validity in seconds (default: 3600 = 1 hour)
|
|
308
|
+
* @returns File URL and metadata
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```typescript
|
|
312
|
+
* const urlData = await storage.getFileUrl('photo.jpg', 7200);
|
|
313
|
+
* console.log(urlData.file_url); // Use this for downloads
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
async getFileUrl(fileKey, expiresIn = 3600) {
|
|
317
|
+
const response = await this.client.get(`/api/v1/storage/s3/projects/${this.projectSlug}/files/${fileKey}/url`, { params: { expires_in: expiresIn } });
|
|
318
|
+
return response.data;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Generate presigned URL for file operations
|
|
322
|
+
*
|
|
323
|
+
* @param fileKey - Path to file in bucket
|
|
324
|
+
* @param options - Presigned URL options
|
|
325
|
+
* @returns Presigned URL string
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* // Download URL
|
|
330
|
+
* const downloadUrl = await storage.getPresignedUrl('file.pdf');
|
|
331
|
+
*
|
|
332
|
+
* // Upload URL
|
|
333
|
+
* const uploadUrl = await storage.getPresignedUrl('new-file.pdf', {
|
|
334
|
+
* operation: 'put_object',
|
|
335
|
+
* expiresIn: 1800
|
|
336
|
+
* });
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
async getPresignedUrl(fileKey, options) {
|
|
340
|
+
const response = await this.client.post(`/api/v1/storage/s3/projects/${this.projectSlug}/presigned-url`, {
|
|
341
|
+
file_key: fileKey,
|
|
342
|
+
expires_in: options?.expiresIn || 3600,
|
|
343
|
+
operation: options?.operation || 'get_object',
|
|
344
|
+
});
|
|
345
|
+
return response.data.url;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Get S3 storage information for the project
|
|
349
|
+
*
|
|
350
|
+
* @returns Storage information
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* const info = await storage.getStorageInfo();
|
|
355
|
+
* console.log(`Bucket: ${info.bucket_name}`);
|
|
356
|
+
* console.log(`Region: ${info.region}`);
|
|
357
|
+
* console.log(`Objects: ${info.total_objects}`);
|
|
358
|
+
* console.log(`Size: ${info.total_size_gb.toFixed(2)} GB`);
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
async getStorageInfo() {
|
|
362
|
+
const response = await this.client.get(`/api/v1/storage/s3/projects/${this.projectSlug}/info`);
|
|
363
|
+
return response.data;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Provision S3 storage for the project
|
|
367
|
+
*
|
|
368
|
+
* **IMPORTANT**: Save the credentials returned! They're only shown once.
|
|
369
|
+
*
|
|
370
|
+
* @param region - AWS region (default: 'us-east-1')
|
|
371
|
+
* @returns Provisioning result with credentials
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```typescript
|
|
375
|
+
* const result = await storage.provisionStorage('us-west-2');
|
|
376
|
+
* console.log(`Bucket: ${result.bucket_name}`);
|
|
377
|
+
* console.log(`Access Key: ${result.credentials.access_key_id}`);
|
|
378
|
+
* // SAVE THESE CREDENTIALS SECURELY!
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
async provisionStorage(region = 'us-east-1') {
|
|
382
|
+
const response = await this.client.post(`/api/v1/storage/s3/projects/${this.projectSlug}/provision`, { region });
|
|
383
|
+
return response.data;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Get list of available S3 regions with pricing
|
|
387
|
+
*
|
|
388
|
+
* @returns Array of available regions
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```typescript
|
|
392
|
+
* const regions = await storage.getAvailableRegions();
|
|
393
|
+
* for (const region of regions) {
|
|
394
|
+
* console.log(`${region.name}: $${region.storage_price_gb}/GB/month`);
|
|
395
|
+
* }
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
async getAvailableRegions() {
|
|
399
|
+
const response = await this.client.get('/api/v1/storage/s3/regions');
|
|
400
|
+
return response.data;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
exports.WowSQLStorage = WowSQLStorage;
|
|
404
|
+
exports.default = WowSQLStorage;
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wowsql/sdk",
|
|
3
|
+
"version": "3.4.0",
|
|
4
|
+
"description": "Official TypeScript/JavaScript SDK for WowSQL - MySQL Backend-as-a-Service with S3 Storage, type-safe queries and fluent API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"publish:patch": "npm version patch && npm publish",
|
|
18
|
+
"publish:minor": "npm version minor && npm publish",
|
|
19
|
+
"publish:major": "npm version major && npm publish"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"wowsql",
|
|
23
|
+
"mysql",
|
|
24
|
+
"database",
|
|
25
|
+
"backend-as-a-service",
|
|
26
|
+
"baas",
|
|
27
|
+
"api",
|
|
28
|
+
"rest",
|
|
29
|
+
"typescript",
|
|
30
|
+
"javascript",
|
|
31
|
+
"sdk",
|
|
32
|
+
"client",
|
|
33
|
+
"query-builder",
|
|
34
|
+
"orm",
|
|
35
|
+
"sql",
|
|
36
|
+
"aws-rds",
|
|
37
|
+
"cloud-database",
|
|
38
|
+
"s3",
|
|
39
|
+
"storage",
|
|
40
|
+
"file-upload",
|
|
41
|
+
"object-storage"
|
|
42
|
+
],
|
|
43
|
+
"author": "WowSQL Team <support@wowsql.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/wowsql/wowsql.git"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/wowsql/wowsql/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://wowsql.com",
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=14.0.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"axios": "^1.6.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^20.0.0",
|
|
61
|
+
"typescript": "^5.0.0",
|
|
62
|
+
"jest": "^29.0.0",
|
|
63
|
+
"@types/jest": "^29.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|