@wrelik/storage 0.1.0 → 0.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.
@@ -0,0 +1,26 @@
1
+
2
+ > @wrelik/storage@0.2.0 build /home/runner/work/wrelik-kit/wrelik-kit/packages/storage
3
+ > tsup src/index.ts src/react-native.ts --format cjs,esm --dts --clean
4
+
5
+ CLI Building entry: src/index.ts, src/react-native.ts
6
+ CLI Using tsconfig: tsconfig.json
7
+ CLI tsup v8.5.1
8
+ CLI Target: es2022
9
+ CLI Cleaning output folder
10
+ CJS Build start
11
+ ESM Build start
12
+ ESM dist/index.mjs 1.46 KB
13
+ ESM dist/react-native.mjs 701.00 B
14
+ ESM dist/chunk-6VKCOC6I.mjs 421.00 B
15
+ ESM ⚡️ Build success in 61ms
16
+ CJS dist/index.js 3.10 KB
17
+ CJS dist/react-native.js 2.17 KB
18
+ CJS ⚡️ Build success in 63ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 4031ms
21
+ DTS dist/index.d.ts 815.00 B
22
+ DTS dist/react-native.d.ts 457.00 B
23
+ DTS dist/shared-DqbBUqiW.d.ts 201.00 B
24
+ DTS dist/index.d.mts 816.00 B
25
+ DTS dist/react-native.d.mts 458.00 B
26
+ DTS dist/shared-DqbBUqiW.d.mts 201.00 B
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @wrelik/storage
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a38ebcb: Add React Native / Expo support and enforce server-only boundaries.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [a38ebcb]
12
+ - @wrelik/errors@0.2.0
13
+
14
+ ## 0.1.1
15
+
16
+ ### Patch Changes
17
+
18
+ - Update publishConfig to access:public for all packages.
19
+ - Updated dependencies
20
+ - @wrelik/errors@0.1.1
21
+
3
22
  ## 0.1.0
4
23
 
5
24
  ### Minor Changes
@@ -0,0 +1,15 @@
1
+ // src/shared.ts
2
+ import { ValidationError } from "@wrelik/errors";
3
+ function validateUpload(file, policy) {
4
+ if (file.sizeBytes > policy.maxSizeBytes) {
5
+ throw new ValidationError(`File too large. Max ${policy.maxSizeBytes} bytes.`);
6
+ }
7
+ if (!policy.allowedTypes.includes(file.contentType)) {
8
+ throw new ValidationError(`Invalid file type ${file.contentType}`);
9
+ }
10
+ return true;
11
+ }
12
+
13
+ export {
14
+ validateUpload
15
+ };
@@ -0,0 +1,16 @@
1
+ import * as _aws_sdk_client_s3 from '@aws-sdk/client-s3';
2
+ export { v as validateUpload } from './shared-DqbBUqiW.mjs';
3
+
4
+ interface StorageConfig {
5
+ accountId: string;
6
+ accessKeyId: string;
7
+ secretAccessKey: string;
8
+ bucketName: string;
9
+ region?: string;
10
+ }
11
+ declare function initStorage(config: StorageConfig): void;
12
+ declare function putObject(body: Buffer | Uint8Array | Blob | string, key: string, contentType: string, metadata?: Record<string, string>): Promise<_aws_sdk_client_s3.PutObjectCommandOutput>;
13
+ declare function getSignedUploadUrl(key: string, contentType: string, expiresIn?: number): Promise<string>;
14
+ declare function getSignedDownloadUrl(key: string, expiresIn?: number): Promise<string>;
15
+
16
+ export { type StorageConfig, getSignedDownloadUrl, getSignedUploadUrl, initStorage, putObject };
@@ -0,0 +1,16 @@
1
+ import * as _aws_sdk_client_s3 from '@aws-sdk/client-s3';
2
+ export { v as validateUpload } from './shared-DqbBUqiW.js';
3
+
4
+ interface StorageConfig {
5
+ accountId: string;
6
+ accessKeyId: string;
7
+ secretAccessKey: string;
8
+ bucketName: string;
9
+ region?: string;
10
+ }
11
+ declare function initStorage(config: StorageConfig): void;
12
+ declare function putObject(body: Buffer | Uint8Array | Blob | string, key: string, contentType: string, metadata?: Record<string, string>): Promise<_aws_sdk_client_s3.PutObjectCommandOutput>;
13
+ declare function getSignedUploadUrl(key: string, contentType: string, expiresIn?: number): Promise<string>;
14
+ declare function getSignedDownloadUrl(key: string, expiresIn?: number): Promise<string>;
15
+
16
+ export { type StorageConfig, getSignedDownloadUrl, getSignedUploadUrl, initStorage, putObject };
package/dist/index.js ADDED
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ getSignedDownloadUrl: () => getSignedDownloadUrl,
24
+ getSignedUploadUrl: () => getSignedUploadUrl,
25
+ initStorage: () => initStorage,
26
+ putObject: () => putObject,
27
+ validateUpload: () => validateUpload
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_client_s3 = require("@aws-sdk/client-s3");
31
+ var import_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
32
+
33
+ // src/shared.ts
34
+ var import_errors = require("@wrelik/errors");
35
+ function validateUpload(file, policy) {
36
+ if (file.sizeBytes > policy.maxSizeBytes) {
37
+ throw new import_errors.ValidationError(`File too large. Max ${policy.maxSizeBytes} bytes.`);
38
+ }
39
+ if (!policy.allowedTypes.includes(file.contentType)) {
40
+ throw new import_errors.ValidationError(`Invalid file type ${file.contentType}`);
41
+ }
42
+ return true;
43
+ }
44
+
45
+ // src/index.ts
46
+ var client;
47
+ var bucket;
48
+ function initStorage(config) {
49
+ const endpoint = `https://${config.accountId}.r2.cloudflarestorage.com`;
50
+ client = new import_client_s3.S3Client({
51
+ region: config.region || "auto",
52
+ endpoint,
53
+ credentials: {
54
+ accessKeyId: config.accessKeyId,
55
+ secretAccessKey: config.secretAccessKey
56
+ }
57
+ });
58
+ bucket = config.bucketName;
59
+ }
60
+ function getClient() {
61
+ if (!client) throw new Error("Storage not initialized. Call initStorage first.");
62
+ return client;
63
+ }
64
+ async function putObject(body, key, contentType, metadata) {
65
+ const command = new import_client_s3.PutObjectCommand({
66
+ Bucket: bucket,
67
+ Key: key,
68
+ Body: body,
69
+ ContentType: contentType,
70
+ Metadata: metadata
71
+ });
72
+ return getClient().send(command);
73
+ }
74
+ async function getSignedUploadUrl(key, contentType, expiresIn = 3600) {
75
+ const command = new import_client_s3.PutObjectCommand({
76
+ Bucket: bucket,
77
+ Key: key,
78
+ ContentType: contentType
79
+ });
80
+ return (0, import_s3_request_presigner.getSignedUrl)(getClient(), command, { expiresIn });
81
+ }
82
+ async function getSignedDownloadUrl(key, expiresIn = 3600) {
83
+ const command = new import_client_s3.GetObjectCommand({
84
+ Bucket: bucket,
85
+ Key: key
86
+ });
87
+ return (0, import_s3_request_presigner.getSignedUrl)(getClient(), command, { expiresIn });
88
+ }
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ getSignedDownloadUrl,
92
+ getSignedUploadUrl,
93
+ initStorage,
94
+ putObject,
95
+ validateUpload
96
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,57 @@
1
+ import {
2
+ validateUpload
3
+ } from "./chunk-6VKCOC6I.mjs";
4
+
5
+ // src/index.ts
6
+ import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
7
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
8
+ var client;
9
+ var bucket;
10
+ function initStorage(config) {
11
+ const endpoint = `https://${config.accountId}.r2.cloudflarestorage.com`;
12
+ client = new S3Client({
13
+ region: config.region || "auto",
14
+ endpoint,
15
+ credentials: {
16
+ accessKeyId: config.accessKeyId,
17
+ secretAccessKey: config.secretAccessKey
18
+ }
19
+ });
20
+ bucket = config.bucketName;
21
+ }
22
+ function getClient() {
23
+ if (!client) throw new Error("Storage not initialized. Call initStorage first.");
24
+ return client;
25
+ }
26
+ async function putObject(body, key, contentType, metadata) {
27
+ const command = new PutObjectCommand({
28
+ Bucket: bucket,
29
+ Key: key,
30
+ Body: body,
31
+ ContentType: contentType,
32
+ Metadata: metadata
33
+ });
34
+ return getClient().send(command);
35
+ }
36
+ async function getSignedUploadUrl(key, contentType, expiresIn = 3600) {
37
+ const command = new PutObjectCommand({
38
+ Bucket: bucket,
39
+ Key: key,
40
+ ContentType: contentType
41
+ });
42
+ return getSignedUrl(getClient(), command, { expiresIn });
43
+ }
44
+ async function getSignedDownloadUrl(key, expiresIn = 3600) {
45
+ const command = new GetObjectCommand({
46
+ Bucket: bucket,
47
+ Key: key
48
+ });
49
+ return getSignedUrl(getClient(), command, { expiresIn });
50
+ }
51
+ export {
52
+ getSignedDownloadUrl,
53
+ getSignedUploadUrl,
54
+ initStorage,
55
+ putObject,
56
+ validateUpload
57
+ };
@@ -0,0 +1,14 @@
1
+ import * as node_buffer from 'node:buffer';
2
+ export { v as validateUpload } from './shared-DqbBUqiW.mjs';
3
+
4
+ declare function uploadToSignedUrl({ url, file, contentType, headers, }: {
5
+ url: string;
6
+ file: File | Blob;
7
+ contentType: string;
8
+ headers?: Record<string, string>;
9
+ }): Promise<boolean>;
10
+ declare function downloadFromSignedUrl({ url }: {
11
+ url: string;
12
+ }): Promise<node_buffer.Blob>;
13
+
14
+ export { downloadFromSignedUrl, uploadToSignedUrl };
@@ -0,0 +1,14 @@
1
+ import * as node_buffer from 'node:buffer';
2
+ export { v as validateUpload } from './shared-DqbBUqiW.js';
3
+
4
+ declare function uploadToSignedUrl({ url, file, contentType, headers, }: {
5
+ url: string;
6
+ file: File | Blob;
7
+ contentType: string;
8
+ headers?: Record<string, string>;
9
+ }): Promise<boolean>;
10
+ declare function downloadFromSignedUrl({ url }: {
11
+ url: string;
12
+ }): Promise<node_buffer.Blob>;
13
+
14
+ export { downloadFromSignedUrl, uploadToSignedUrl };
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react-native.ts
21
+ var react_native_exports = {};
22
+ __export(react_native_exports, {
23
+ downloadFromSignedUrl: () => downloadFromSignedUrl,
24
+ uploadToSignedUrl: () => uploadToSignedUrl,
25
+ validateUpload: () => validateUpload
26
+ });
27
+ module.exports = __toCommonJS(react_native_exports);
28
+
29
+ // src/shared.ts
30
+ var import_errors = require("@wrelik/errors");
31
+ function validateUpload(file, policy) {
32
+ if (file.sizeBytes > policy.maxSizeBytes) {
33
+ throw new import_errors.ValidationError(`File too large. Max ${policy.maxSizeBytes} bytes.`);
34
+ }
35
+ if (!policy.allowedTypes.includes(file.contentType)) {
36
+ throw new import_errors.ValidationError(`Invalid file type ${file.contentType}`);
37
+ }
38
+ return true;
39
+ }
40
+
41
+ // src/react-native.ts
42
+ async function uploadToSignedUrl({
43
+ url,
44
+ file,
45
+ contentType,
46
+ headers = {}
47
+ }) {
48
+ const result = await fetch(url, {
49
+ method: "PUT",
50
+ body: file,
51
+ headers: {
52
+ "Content-Type": contentType,
53
+ ...headers
54
+ }
55
+ });
56
+ if (!result.ok) {
57
+ throw new Error(`Upload failed with status ${result.status}`);
58
+ }
59
+ return true;
60
+ }
61
+ async function downloadFromSignedUrl({ url }) {
62
+ const result = await fetch(url);
63
+ if (!result.ok) {
64
+ throw new Error(`Download failed with status ${result.status}`);
65
+ }
66
+ return result.blob();
67
+ }
68
+ // Annotate the CommonJS export names for ESM import in node:
69
+ 0 && (module.exports = {
70
+ downloadFromSignedUrl,
71
+ uploadToSignedUrl,
72
+ validateUpload
73
+ });
@@ -0,0 +1,36 @@
1
+ import {
2
+ validateUpload
3
+ } from "./chunk-6VKCOC6I.mjs";
4
+
5
+ // src/react-native.ts
6
+ async function uploadToSignedUrl({
7
+ url,
8
+ file,
9
+ contentType,
10
+ headers = {}
11
+ }) {
12
+ const result = await fetch(url, {
13
+ method: "PUT",
14
+ body: file,
15
+ headers: {
16
+ "Content-Type": contentType,
17
+ ...headers
18
+ }
19
+ });
20
+ if (!result.ok) {
21
+ throw new Error(`Upload failed with status ${result.status}`);
22
+ }
23
+ return true;
24
+ }
25
+ async function downloadFromSignedUrl({ url }) {
26
+ const result = await fetch(url);
27
+ if (!result.ok) {
28
+ throw new Error(`Download failed with status ${result.status}`);
29
+ }
30
+ return result.blob();
31
+ }
32
+ export {
33
+ downloadFromSignedUrl,
34
+ uploadToSignedUrl,
35
+ validateUpload
36
+ };
@@ -0,0 +1,9 @@
1
+ declare function validateUpload(file: {
2
+ contentType: string;
3
+ sizeBytes: number;
4
+ }, policy: {
5
+ maxSizeBytes: number;
6
+ allowedTypes: string[];
7
+ }): boolean;
8
+
9
+ export { validateUpload as v };
@@ -0,0 +1,9 @@
1
+ declare function validateUpload(file: {
2
+ contentType: string;
3
+ sizeBytes: number;
4
+ }, policy: {
5
+ maxSizeBytes: number;
6
+ allowedTypes: string[];
7
+ }): boolean;
8
+
9
+ export { validateUpload as v };
package/package.json CHANGED
@@ -1,22 +1,32 @@
1
1
  {
2
2
  "name": "@wrelik/storage",
3
- "version": "0.1.0",
4
- "main": "./dist/index.js",
5
- "types": "./dist/index.d.ts",
3
+ "version": "0.2.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/lwhite702/wrelik-kit.git",
10
+ "directory": "packages/storage"
11
+ },
12
+ "exports": {
13
+ ".": "./dist/index.js",
14
+ "./react-native": "./dist/react-native.js"
15
+ },
6
16
  "dependencies": {
7
17
  "@aws-sdk/client-s3": "^3.500.0",
8
18
  "@aws-sdk/s3-request-presigner": "^3.500.0",
9
- "@wrelik/errors": "0.1.0"
19
+ "@wrelik/errors": "0.2.0"
10
20
  },
11
21
  "devDependencies": {
12
22
  "@types/node": "^25.2.0",
13
23
  "tsup": "^8.0.1",
14
24
  "vitest": "^1.2.2",
15
- "@wrelik/eslint-config": "0.1.0",
16
- "@wrelik/tsconfig": "0.1.0"
25
+ "@wrelik/eslint-config": "0.1.1",
26
+ "@wrelik/tsconfig": "0.1.1"
17
27
  },
18
28
  "scripts": {
19
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
29
+ "build": "tsup src/index.ts src/react-native.ts --format cjs,esm --dts --clean",
20
30
  "lint": "eslint src/",
21
31
  "test": "vitest run --passWithNoTests"
22
32
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
+ /* eslint-disable no-restricted-imports */
1
2
  import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
2
3
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
- import { ValidationError } from '@wrelik/errors';
4
4
 
5
5
  export interface StorageConfig {
6
6
  accountId: string;
@@ -70,15 +70,4 @@ export async function getSignedDownloadUrl(key: string, expiresIn = 3600) {
70
70
  return getSignedUrl(getClient(), command, { expiresIn });
71
71
  }
72
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
- }
73
+ export * from './shared';
@@ -0,0 +1,36 @@
1
+ export * from './shared';
2
+
3
+ export async function uploadToSignedUrl({
4
+ url,
5
+ file,
6
+ contentType,
7
+ headers = {},
8
+ }: {
9
+ url: string;
10
+ file: File | Blob;
11
+ contentType: string;
12
+ headers?: Record<string, string>;
13
+ }) {
14
+ const result = await fetch(url, {
15
+ method: 'PUT',
16
+ body: file,
17
+ headers: {
18
+ 'Content-Type': contentType,
19
+ ...headers,
20
+ },
21
+ });
22
+
23
+ if (!result.ok) {
24
+ throw new Error(`Upload failed with status ${result.status}`);
25
+ }
26
+
27
+ return true;
28
+ }
29
+
30
+ export async function downloadFromSignedUrl({ url }: { url: string }) {
31
+ const result = await fetch(url);
32
+ if (!result.ok) {
33
+ throw new Error(`Download failed with status ${result.status}`);
34
+ }
35
+ return result.blob();
36
+ }
@@ -0,0 +1,17 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateUpload } from './shared';
3
+
4
+ describe('Storage Shared', () => {
5
+ it('validates upload policy', () => {
6
+ const policy = { maxSizeBytes: 100, allowedTypes: ['image/png'] };
7
+
8
+ expect(() => validateUpload({ contentType: 'image/png', sizeBytes: 50 }, policy)).not.toThrow();
9
+
10
+ expect(() => validateUpload({ contentType: 'image/jpeg', sizeBytes: 50 }, policy)).toThrow(
11
+ /Invalid file type/,
12
+ );
13
+ expect(() => validateUpload({ contentType: 'image/png', sizeBytes: 150 }, policy)).toThrow(
14
+ /File too large/,
15
+ );
16
+ });
17
+ });
package/src/shared.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { ValidationError } from '@wrelik/errors';
2
+
3
+ export function validateUpload(
4
+ file: { contentType: string; sizeBytes: number },
5
+ policy: { maxSizeBytes: number; allowedTypes: string[] },
6
+ ) {
7
+ if (file.sizeBytes > policy.maxSizeBytes) {
8
+ throw new ValidationError(`File too large. Max ${policy.maxSizeBytes} bytes.`);
9
+ }
10
+ if (!policy.allowedTypes.includes(file.contentType)) {
11
+ throw new ValidationError(`Invalid file type ${file.contentType}`);
12
+ }
13
+ return true;
14
+ }
package/tsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "extends": "@wrelik/tsconfig/node.json",
3
3
  "compilerOptions": {
4
- "outDir": "dist"
4
+ "outDir": "dist", "skipLibCheck": true
5
5
  },
6
6
  "include": ["src"]
7
7
  }