@wrelik/storage 0.1.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 ADDED
@@ -0,0 +1,12 @@
1
+ # @wrelik/storage
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ad849e3: Initial release of all wrelik-kit packages.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [ad849e3]
12
+ - @wrelik/errors@0.1.0
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@wrelik/storage",
3
+ "version": "0.1.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "dependencies": {
7
+ "@aws-sdk/client-s3": "^3.500.0",
8
+ "@aws-sdk/s3-request-presigner": "^3.500.0",
9
+ "@wrelik/errors": "0.1.0"
10
+ },
11
+ "devDependencies": {
12
+ "@types/node": "^25.2.0",
13
+ "tsup": "^8.0.1",
14
+ "vitest": "^1.2.2",
15
+ "@wrelik/eslint-config": "0.1.0",
16
+ "@wrelik/tsconfig": "0.1.0"
17
+ },
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
20
+ "lint": "eslint src/",
21
+ "test": "vitest run --passWithNoTests"
22
+ }
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
2
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
+ import { ValidationError } from '@wrelik/errors';
4
+
5
+ export interface StorageConfig {
6
+ accountId: string;
7
+ accessKeyId: string;
8
+ secretAccessKey: string;
9
+ bucketName: string;
10
+ region?: string;
11
+ }
12
+
13
+ let client: S3Client;
14
+ let bucket: string;
15
+
16
+ export function initStorage(config: StorageConfig) {
17
+ // For R2, endpoint: https://<accountid>.r2.cloudflarestorage.com
18
+ const endpoint = `https://${config.accountId}.r2.cloudflarestorage.com`;
19
+
20
+ client = new S3Client({
21
+ region: config.region || 'auto',
22
+ endpoint,
23
+ credentials: {
24
+ accessKeyId: config.accessKeyId,
25
+ secretAccessKey: config.secretAccessKey,
26
+ },
27
+ });
28
+
29
+ bucket = config.bucketName;
30
+ }
31
+
32
+ function getClient() {
33
+ if (!client) throw new Error('Storage not initialized. Call initStorage first.');
34
+ return client;
35
+ }
36
+
37
+ export async function putObject(
38
+ body: Buffer | Uint8Array | Blob | string,
39
+ key: string,
40
+ contentType: string,
41
+ metadata?: Record<string, string>,
42
+ ) {
43
+ const command = new PutObjectCommand({
44
+ Bucket: bucket,
45
+ Key: key,
46
+ Body: body,
47
+ ContentType: contentType,
48
+ Metadata: metadata,
49
+ });
50
+
51
+ return getClient().send(command);
52
+ }
53
+
54
+ export async function getSignedUploadUrl(key: string, contentType: string, expiresIn = 3600) {
55
+ const command = new PutObjectCommand({
56
+ Bucket: bucket,
57
+ Key: key,
58
+ ContentType: contentType,
59
+ });
60
+
61
+ return getSignedUrl(getClient(), command, { expiresIn });
62
+ }
63
+
64
+ export async function getSignedDownloadUrl(key: string, expiresIn = 3600) {
65
+ const command = new GetObjectCommand({
66
+ Bucket: bucket,
67
+ Key: key,
68
+ });
69
+
70
+ return getSignedUrl(getClient(), command, { expiresIn });
71
+ }
72
+
73
+ export function validateUpload(
74
+ file: { contentType: string; sizeBytes: number },
75
+ policy: { maxSizeBytes: number; allowedTypes: string[] },
76
+ ) {
77
+ if (file.sizeBytes > policy.maxSizeBytes) {
78
+ throw new ValidationError(`File too large. Max ${policy.maxSizeBytes} bytes.`);
79
+ }
80
+ if (!policy.allowedTypes.includes(file.contentType)) {
81
+ throw new ValidationError(`Invalid file type ${file.contentType}`);
82
+ }
83
+ return true;
84
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@wrelik/tsconfig/node.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist"
5
+ },
6
+ "include": ["src"]
7
+ }