@opensaas/stack-storage 0.1.1
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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +11 -0
- package/CLAUDE.md +426 -0
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/config/index.d.ts +19 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +25 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +113 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/fields/index.d.ts +111 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +237 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/local.d.ts +22 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +64 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/runtime/index.d.ts +75 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +157 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/utils/image.d.ts +18 -0
- package/dist/utils/image.d.ts.map +1 -0
- package/dist/utils/image.js +82 -0
- package/dist/utils/image.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/upload.d.ts +56 -0
- package/dist/utils/upload.d.ts.map +1 -0
- package/dist/utils/upload.js +74 -0
- package/dist/utils/upload.js.map +1 -0
- package/package.json +50 -0
- package/src/config/index.ts +30 -0
- package/src/config/types.ts +127 -0
- package/src/fields/index.ts +347 -0
- package/src/index.ts +14 -0
- package/src/providers/index.ts +1 -0
- package/src/providers/local.ts +85 -0
- package/src/runtime/index.ts +243 -0
- package/src/utils/image.ts +111 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/upload.ts +122 -0
- package/tests/image-utils.test.ts +498 -0
- package/tests/local-provider.test.ts +349 -0
- package/tests/upload-utils.test.ts +313 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { BaseFieldConfig } from '@opensaas/stack-core';
|
|
2
|
+
import type { ComponentType } from 'react';
|
|
3
|
+
import type { FileMetadata, ImageMetadata, ImageTransformationConfig } from '../config/types.js';
|
|
4
|
+
import type { FileValidationOptions } from '../utils/upload.js';
|
|
5
|
+
/**
|
|
6
|
+
* File field configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface FileFieldConfig extends BaseFieldConfig<FileMetadata | null, FileMetadata | null> {
|
|
9
|
+
type: 'file';
|
|
10
|
+
/** Name of the storage provider from config.storage */
|
|
11
|
+
storage: string;
|
|
12
|
+
/** File validation options */
|
|
13
|
+
validation?: FileValidationOptions;
|
|
14
|
+
/** Automatically delete file from storage when record is deleted */
|
|
15
|
+
cleanupOnDelete?: boolean;
|
|
16
|
+
/** Automatically delete old file from storage when replaced with new file */
|
|
17
|
+
cleanupOnReplace?: boolean;
|
|
18
|
+
/** UI options */
|
|
19
|
+
ui?: {
|
|
20
|
+
/** Custom component to use for rendering this field */
|
|
21
|
+
component?: ComponentType<unknown>;
|
|
22
|
+
/** Custom field type name for component registry lookup */
|
|
23
|
+
fieldType?: string;
|
|
24
|
+
/** Label for the field */
|
|
25
|
+
label?: string;
|
|
26
|
+
/** Help text shown below the field */
|
|
27
|
+
helpText?: string;
|
|
28
|
+
/** Placeholder text */
|
|
29
|
+
placeholder?: string;
|
|
30
|
+
/** Additional UI options passed through to component */
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Image field configuration
|
|
36
|
+
*/
|
|
37
|
+
export interface ImageFieldConfig extends BaseFieldConfig<ImageMetadata | null, ImageMetadata | null> {
|
|
38
|
+
type: 'image';
|
|
39
|
+
/** Name of the storage provider from config.storage */
|
|
40
|
+
storage: string;
|
|
41
|
+
/** Image transformations to generate on upload */
|
|
42
|
+
transformations?: Record<string, ImageTransformationConfig>;
|
|
43
|
+
/** File validation options */
|
|
44
|
+
validation?: FileValidationOptions;
|
|
45
|
+
/** Automatically delete file from storage when record is deleted */
|
|
46
|
+
cleanupOnDelete?: boolean;
|
|
47
|
+
/** Automatically delete old file from storage when replaced with new file */
|
|
48
|
+
cleanupOnReplace?: boolean;
|
|
49
|
+
/** UI options */
|
|
50
|
+
ui?: {
|
|
51
|
+
/** Custom component to use for rendering this field */
|
|
52
|
+
component?: ComponentType<unknown>;
|
|
53
|
+
/** Custom field type name for component registry lookup */
|
|
54
|
+
fieldType?: string;
|
|
55
|
+
/** Label for the field */
|
|
56
|
+
label?: string;
|
|
57
|
+
/** Help text shown below the field */
|
|
58
|
+
helpText?: string;
|
|
59
|
+
/** Placeholder text */
|
|
60
|
+
placeholder?: string;
|
|
61
|
+
/** Show image preview */
|
|
62
|
+
showPreview?: boolean;
|
|
63
|
+
/** Preview size (width in pixels) */
|
|
64
|
+
previewSize?: number;
|
|
65
|
+
/** Additional UI options passed through to component */
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a file upload field
|
|
71
|
+
*
|
|
72
|
+
* Uses JSON field backing to store file metadata including filename, URL, size, MIME type, etc.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* fields: {
|
|
77
|
+
* resume: file({
|
|
78
|
+
* storage: 'documents',
|
|
79
|
+
* validation: {
|
|
80
|
+
* maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
81
|
+
* acceptedMimeTypes: ['application/pdf']
|
|
82
|
+
* }
|
|
83
|
+
* })
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare function file(options: Omit<FileFieldConfig, 'type'>): FileFieldConfig;
|
|
88
|
+
/**
|
|
89
|
+
* Creates an image upload field with optional transformations
|
|
90
|
+
*
|
|
91
|
+
* Uses JSON field backing to store image metadata including dimensions, transformations, etc.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* fields: {
|
|
96
|
+
* avatar: image({
|
|
97
|
+
* storage: 'avatars',
|
|
98
|
+
* transformations: {
|
|
99
|
+
* thumbnail: { width: 100, height: 100, fit: 'cover' },
|
|
100
|
+
* profile: { width: 400, height: 400, fit: 'cover' }
|
|
101
|
+
* },
|
|
102
|
+
* validation: {
|
|
103
|
+
* maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
104
|
+
* acceptedMimeTypes: ['image/jpeg', 'image/png', 'image/webp']
|
|
105
|
+
* }
|
|
106
|
+
* })
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function image(options: Omit<ImageFieldConfig, 'type'>): ImageFieldConfig;
|
|
111
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fields/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAA;AAChG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE/D;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,eAAe,CAAC,YAAY,GAAG,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAChG,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,iBAAiB;IACjB,EAAE,CAAC,EAAE;QACH,uDAAuD;QACvD,SAAS,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;QAClC,2DAA2D;QAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,0BAA0B;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,sCAAsC;QACtC,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,uBAAuB;QACvB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,wDAAwD;QACxD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,gBACf,SAAQ,eAAe,CAAC,aAAa,GAAG,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IACnE,IAAI,EAAE,OAAO,CAAA;IACb,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAA;IAC3D,8BAA8B;IAC9B,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,iBAAiB;IACjB,EAAE,CAAC,EAAE;QACH,uDAAuD;QACvD,SAAS,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;QAClC,2DAA2D;QAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,0BAA0B;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,sCAAsC;QACtC,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,uBAAuB;QACvB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,yBAAyB;QACzB,WAAW,CAAC,EAAE,OAAO,CAAA;QACrB,qCAAqC;QACrC,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,wDAAwD;QACxD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,GAAG,eAAe,CAuG5E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG,gBAAgB,CAgI/E"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a file upload field
|
|
4
|
+
*
|
|
5
|
+
* Uses JSON field backing to store file metadata including filename, URL, size, MIME type, etc.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* fields: {
|
|
10
|
+
* resume: file({
|
|
11
|
+
* storage: 'documents',
|
|
12
|
+
* validation: {
|
|
13
|
+
* maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
14
|
+
* acceptedMimeTypes: ['application/pdf']
|
|
15
|
+
* }
|
|
16
|
+
* })
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function file(options) {
|
|
21
|
+
const fieldConfig = {
|
|
22
|
+
type: 'file',
|
|
23
|
+
...options,
|
|
24
|
+
hooks: {
|
|
25
|
+
resolveInput: async ({ inputValue, context, item, fieldName }) => {
|
|
26
|
+
// If null/undefined, return as-is (deletion or no change)
|
|
27
|
+
if (inputValue === null || inputValue === undefined) {
|
|
28
|
+
return inputValue;
|
|
29
|
+
}
|
|
30
|
+
// If already FileMetadata, keep existing (edit mode - no new file uploaded)
|
|
31
|
+
if (typeof inputValue === 'object' && 'filename' in inputValue && 'url' in inputValue) {
|
|
32
|
+
return inputValue;
|
|
33
|
+
}
|
|
34
|
+
// If File object, upload it
|
|
35
|
+
// Check if it's a File-like object (has arrayBuffer method)
|
|
36
|
+
if (typeof inputValue === 'object' &&
|
|
37
|
+
'arrayBuffer' in inputValue &&
|
|
38
|
+
typeof inputValue.arrayBuffer === 'function') {
|
|
39
|
+
// Convert File to buffer
|
|
40
|
+
const fileObj = inputValue;
|
|
41
|
+
const arrayBuffer = await fileObj.arrayBuffer();
|
|
42
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
43
|
+
// Upload file using context.storage utilities
|
|
44
|
+
const metadata = (await context.storage.uploadFile(fieldConfig.storage, fileObj, buffer, {
|
|
45
|
+
validation: fieldConfig.validation,
|
|
46
|
+
}));
|
|
47
|
+
// If cleanupOnReplace is enabled and there was an old file, delete it
|
|
48
|
+
if (fieldConfig.cleanupOnReplace && item && fieldName) {
|
|
49
|
+
const oldMetadata = item[fieldName];
|
|
50
|
+
if (oldMetadata && oldMetadata.filename) {
|
|
51
|
+
try {
|
|
52
|
+
await context.storage.deleteFile(oldMetadata.storageProvider, oldMetadata.filename);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Log error but don't fail the operation
|
|
56
|
+
console.error(`Failed to cleanup old file: ${oldMetadata.filename}`, error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return metadata;
|
|
61
|
+
}
|
|
62
|
+
// Unknown type - return as-is and let validation catch it
|
|
63
|
+
return inputValue;
|
|
64
|
+
},
|
|
65
|
+
afterOperation: async ({ operation, item, fieldName, context }) => {
|
|
66
|
+
// Only cleanup on delete if enabled
|
|
67
|
+
if (operation === 'delete' && fieldConfig.cleanupOnDelete) {
|
|
68
|
+
const fileMetadata = item[fieldName];
|
|
69
|
+
if (fileMetadata && fileMetadata.filename) {
|
|
70
|
+
try {
|
|
71
|
+
await context.storage.deleteFile(fileMetadata.storageProvider, fileMetadata.filename);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Log error but don't fail the operation
|
|
75
|
+
console.error(`Failed to cleanup file on delete: ${fileMetadata.filename}`, error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
getZodSchema: (_fieldName, _operation) => {
|
|
82
|
+
// File metadata follows the FileMetadata schema
|
|
83
|
+
const fileMetadataSchema = z.object({
|
|
84
|
+
filename: z.string(),
|
|
85
|
+
originalFilename: z.string(),
|
|
86
|
+
url: z.string(), // Accept both absolute URLs and relative paths
|
|
87
|
+
mimeType: z.string(),
|
|
88
|
+
size: z.number(),
|
|
89
|
+
uploadedAt: z.string(),
|
|
90
|
+
storageProvider: z.string(),
|
|
91
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
92
|
+
});
|
|
93
|
+
// Allow null or undefined values
|
|
94
|
+
return z.union([fileMetadataSchema, z.null(), z.undefined()]);
|
|
95
|
+
},
|
|
96
|
+
getPrismaType: (_fieldName) => {
|
|
97
|
+
// Store as JSON in database
|
|
98
|
+
return { type: 'Json', modifiers: '?' };
|
|
99
|
+
},
|
|
100
|
+
getTypeScriptType: () => {
|
|
101
|
+
// TypeScript type is FileMetadata | null
|
|
102
|
+
return {
|
|
103
|
+
type: 'import("@opensaas/stack-storage").FileMetadata | null',
|
|
104
|
+
optional: true,
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
return fieldConfig;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Creates an image upload field with optional transformations
|
|
112
|
+
*
|
|
113
|
+
* Uses JSON field backing to store image metadata including dimensions, transformations, etc.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* fields: {
|
|
118
|
+
* avatar: image({
|
|
119
|
+
* storage: 'avatars',
|
|
120
|
+
* transformations: {
|
|
121
|
+
* thumbnail: { width: 100, height: 100, fit: 'cover' },
|
|
122
|
+
* profile: { width: 400, height: 400, fit: 'cover' }
|
|
123
|
+
* },
|
|
124
|
+
* validation: {
|
|
125
|
+
* maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
126
|
+
* acceptedMimeTypes: ['image/jpeg', 'image/png', 'image/webp']
|
|
127
|
+
* }
|
|
128
|
+
* })
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function image(options) {
|
|
133
|
+
const fieldConfig = {
|
|
134
|
+
type: 'image',
|
|
135
|
+
...options,
|
|
136
|
+
hooks: {
|
|
137
|
+
resolveInput: async ({ inputValue, context, item, fieldName }) => {
|
|
138
|
+
// If null/undefined, return as-is (deletion or no change)
|
|
139
|
+
if (inputValue === null || inputValue === undefined) {
|
|
140
|
+
return inputValue;
|
|
141
|
+
}
|
|
142
|
+
// If already ImageMetadata, keep existing (edit mode - no new file uploaded)
|
|
143
|
+
if (typeof inputValue === 'object' &&
|
|
144
|
+
'filename' in inputValue &&
|
|
145
|
+
'url' in inputValue &&
|
|
146
|
+
'width' in inputValue &&
|
|
147
|
+
'height' in inputValue) {
|
|
148
|
+
return inputValue;
|
|
149
|
+
}
|
|
150
|
+
// If File object, upload it
|
|
151
|
+
// Check if it's a File-like object (has arrayBuffer method)
|
|
152
|
+
if (typeof inputValue === 'object' &&
|
|
153
|
+
'arrayBuffer' in inputValue &&
|
|
154
|
+
typeof inputValue.arrayBuffer === 'function') {
|
|
155
|
+
// Convert File to buffer
|
|
156
|
+
const fileObj = inputValue;
|
|
157
|
+
const arrayBuffer = await fileObj.arrayBuffer();
|
|
158
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
159
|
+
// Upload image using context.storage utilities
|
|
160
|
+
const metadata = (await context.storage.uploadImage(fieldConfig.storage, fileObj, buffer, {
|
|
161
|
+
validation: fieldConfig.validation,
|
|
162
|
+
transformations: fieldConfig.transformations,
|
|
163
|
+
}));
|
|
164
|
+
// If cleanupOnReplace is enabled and there was an old file, delete it
|
|
165
|
+
if (fieldConfig.cleanupOnReplace && item && fieldName) {
|
|
166
|
+
const oldMetadata = item[fieldName];
|
|
167
|
+
if (oldMetadata && oldMetadata.filename) {
|
|
168
|
+
try {
|
|
169
|
+
await context.storage.deleteImage(oldMetadata);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// Log error but don't fail the operation
|
|
173
|
+
console.error(`Failed to cleanup old image: ${oldMetadata.filename}`, error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return metadata;
|
|
178
|
+
}
|
|
179
|
+
// Unknown type - return as-is and let validation catch it
|
|
180
|
+
return inputValue;
|
|
181
|
+
},
|
|
182
|
+
afterOperation: async ({ operation, item, fieldName, context }) => {
|
|
183
|
+
// Only cleanup on delete if enabled
|
|
184
|
+
if (operation === 'delete' && fieldConfig.cleanupOnDelete) {
|
|
185
|
+
const imageMetadata = item[fieldName];
|
|
186
|
+
if (imageMetadata && imageMetadata.filename) {
|
|
187
|
+
try {
|
|
188
|
+
await context.storage.deleteImage(imageMetadata);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
// Log error but don't fail the operation
|
|
192
|
+
console.error(`Failed to cleanup image on delete: ${imageMetadata.filename}`, error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
getZodSchema: (_fieldName, _operation) => {
|
|
199
|
+
// Image metadata follows the ImageMetadata schema (extends FileMetadata)
|
|
200
|
+
const imageMetadataSchema = z.object({
|
|
201
|
+
filename: z.string(),
|
|
202
|
+
originalFilename: z.string(),
|
|
203
|
+
url: z.string(), // Accept both absolute URLs and relative paths
|
|
204
|
+
mimeType: z.string(),
|
|
205
|
+
size: z.number(),
|
|
206
|
+
width: z.number(),
|
|
207
|
+
height: z.number(),
|
|
208
|
+
uploadedAt: z.string(),
|
|
209
|
+
storageProvider: z.string(),
|
|
210
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
211
|
+
transformations: z
|
|
212
|
+
.record(z.string(), z.object({
|
|
213
|
+
url: z.string(), // Accept both absolute URLs and relative paths
|
|
214
|
+
width: z.number(),
|
|
215
|
+
height: z.number(),
|
|
216
|
+
size: z.number(),
|
|
217
|
+
}))
|
|
218
|
+
.optional(),
|
|
219
|
+
});
|
|
220
|
+
// Allow null or undefined values
|
|
221
|
+
return z.union([imageMetadataSchema, z.null(), z.undefined()]);
|
|
222
|
+
},
|
|
223
|
+
getPrismaType: (_fieldName) => {
|
|
224
|
+
// Store as JSON in database
|
|
225
|
+
return { type: 'Json', modifiers: '?' };
|
|
226
|
+
},
|
|
227
|
+
getTypeScriptType: () => {
|
|
228
|
+
// TypeScript type is ImageMetadata | null
|
|
229
|
+
return {
|
|
230
|
+
type: 'import("@opensaas/stack-storage").ImageMetadata | null',
|
|
231
|
+
optional: true,
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
return fieldConfig;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fields/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAwEvB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAC,OAAsC;IACzD,MAAM,WAAW,GAAoB;QACnC,IAAI,EAAE,MAAM;QACZ,GAAG,OAAO;QAEV,KAAK,EAAE;YACL,YAAY,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;gBAC/D,0DAA0D;gBAC1D,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;oBACpD,OAAO,UAAU,CAAA;gBACnB,CAAC;gBAED,4EAA4E;gBAC5E,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,IAAI,UAAU,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;oBACtF,OAAO,UAA0B,CAAA;gBACnC,CAAC;gBAED,4BAA4B;gBAC5B,4DAA4D;gBAC5D,IACE,OAAO,UAAU,KAAK,QAAQ;oBAC9B,aAAa,IAAI,UAAU;oBAC3B,OAAQ,UAAwC,CAAC,WAAW,KAAK,UAAU,EAC3E,CAAC;oBACD,yBAAyB;oBACzB,MAAM,OAAO,GAAG,UAAkB,CAAA;oBAClC,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAA;oBAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;oBAEvC,8CAA8C;oBAC9C,MAAM,QAAQ,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE;wBACvF,UAAU,EAAE,WAAW,CAAC,UAAU;qBACnC,CAAC,CAAiB,CAAA;oBAEnB,sEAAsE;oBACtE,IAAI,WAAW,CAAC,gBAAgB,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;wBACtD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAwB,CAAA;wBAC1D,IAAI,WAAW,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;4BACxC,IAAI,CAAC;gCACH,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,eAAe,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;4BACrF,CAAC;4BAAC,OAAO,KAAK,EAAE,CAAC;gCACf,yCAAyC;gCACzC,OAAO,CAAC,KAAK,CAAC,+BAA+B,WAAW,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;4BAC7E,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,OAAO,QAAQ,CAAA;gBACjB,CAAC;gBAED,0DAA0D;gBAC1D,OAAO,UAAU,CAAA;YACnB,CAAC;YAED,cAAc,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;gBAChE,oCAAoC;gBACpC,IAAI,SAAS,KAAK,QAAQ,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC;oBAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAwB,CAAA;oBAE3D,IAAI,YAAY,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;wBAC1C,IAAI,CAAC;4BACH,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,eAAe,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;wBACvF,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,yCAAyC;4BACzC,OAAO,CAAC,KAAK,CAAC,qCAAqC,YAAY,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;wBACpF,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF;QAED,YAAY,EAAE,CAAC,UAAkB,EAAE,UAA+B,EAAE,EAAE;YACpE,gDAAgD;YAChD,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;gBAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;gBACpB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;gBAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,+CAA+C;gBAChE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;gBACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;gBAChB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;gBACtB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;gBAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;aACvD,CAAC,CAAA;YAEF,iCAAiC;YACjC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QAC/D,CAAC;QAED,aAAa,EAAE,CAAC,UAAkB,EAAE,EAAE;YACpC,4BAA4B;YAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA;QACzC,CAAC;QAED,iBAAiB,EAAE,GAAG,EAAE;YACtB,yCAAyC;YACzC,OAAO;gBACL,IAAI,EAAE,uDAAuD;gBAC7D,QAAQ,EAAE,IAAI;aACf,CAAA;QACH,CAAC;KACF,CAAA;IAED,OAAO,WAAW,CAAA;AACpB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,KAAK,CAAC,OAAuC;IAC3D,MAAM,WAAW,GAAqB;QACpC,IAAI,EAAE,OAAO;QACb,GAAG,OAAO;QAEV,KAAK,EAAE;YACL,YAAY,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;gBAC/D,0DAA0D;gBAC1D,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;oBACpD,OAAO,UAAU,CAAA;gBACnB,CAAC;gBAED,6EAA6E;gBAC7E,IACE,OAAO,UAAU,KAAK,QAAQ;oBAC9B,UAAU,IAAI,UAAU;oBACxB,KAAK,IAAI,UAAU;oBACnB,OAAO,IAAI,UAAU;oBACrB,QAAQ,IAAI,UAAU,EACtB,CAAC;oBACD,OAAO,UAA2B,CAAA;gBACpC,CAAC;gBAED,4BAA4B;gBAC5B,4DAA4D;gBAC5D,IACE,OAAO,UAAU,KAAK,QAAQ;oBAC9B,aAAa,IAAI,UAAU;oBAC3B,OAAQ,UAAwC,CAAC,WAAW,KAAK,UAAU,EAC3E,CAAC;oBACD,yBAAyB;oBACzB,MAAM,OAAO,GAAG,UAAkB,CAAA;oBAClC,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAA;oBAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;oBAEvC,+CAA+C;oBAC/C,MAAM,QAAQ,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CACjD,WAAW,CAAC,OAAO,EACnB,OAAO,EACP,MAAM,EACN;wBACE,UAAU,EAAE,WAAW,CAAC,UAAU;wBAClC,eAAe,EAAE,WAAW,CAAC,eAAe;qBAC7C,CACF,CAAkB,CAAA;oBAEnB,sEAAsE;oBACtE,IAAI,WAAW,CAAC,gBAAgB,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;wBACtD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAyB,CAAA;wBAC3D,IAAI,WAAW,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;4BACxC,IAAI,CAAC;gCACH,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;4BAChD,CAAC;4BAAC,OAAO,KAAK,EAAE,CAAC;gCACf,yCAAyC;gCACzC,OAAO,CAAC,KAAK,CAAC,gCAAgC,WAAW,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;4BAC9E,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,OAAO,QAAQ,CAAA;gBACjB,CAAC;gBAED,0DAA0D;gBAC1D,OAAO,UAAU,CAAA;YACnB,CAAC;YAED,cAAc,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;gBAChE,oCAAoC;gBACpC,IAAI,SAAS,KAAK,QAAQ,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC;oBAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAyB,CAAA;oBAE7D,IAAI,aAAa,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;wBAC5C,IAAI,CAAC;4BACH,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;wBAClD,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,yCAAyC;4BACzC,OAAO,CAAC,KAAK,CAAC,sCAAsC,aAAa,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAA;wBACtF,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF;QAED,YAAY,EAAE,CAAC,UAAkB,EAAE,UAA+B,EAAE,EAAE;YACpE,yEAAyE;YACzE,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;gBACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;gBACpB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;gBAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,+CAA+C;gBAChE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;gBACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;gBAChB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;gBACjB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;gBAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;gBACtB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;gBAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;gBACtD,eAAe,EAAE,CAAC;qBACf,MAAM,CACL,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,MAAM,CAAC;oBACP,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,+CAA+C;oBAChE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;oBACjB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;oBAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;iBACjB,CAAC,CACH;qBACA,QAAQ,EAAE;aACd,CAAC,CAAA;YAEF,iCAAiC;YACjC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QAChE,CAAC;QAED,aAAa,EAAE,CAAC,UAAkB,EAAE,EAAE;YACpC,4BAA4B;YAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA;QACzC,CAAC;QAED,iBAAiB,EAAE,GAAG,EAAE;YACtB,0CAA0C;YAC1C,OAAO;gBACL,IAAI,EAAE,wDAAwD;gBAC9D,QAAQ,EAAE,IAAI;aACf,CAAA;QACH,CAAC;KACF,CAAA;IAED,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAA;AAGjC,cAAc,mBAAmB,CAAA;AAGjC,cAAc,sBAAsB,CAAA;AAGpC,cAAc,oBAAoB,CAAA;AAGlC,cAAc,kBAAkB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Config and types
|
|
2
|
+
export * from './config/index.js';
|
|
3
|
+
// Field builders
|
|
4
|
+
export * from './fields/index.js';
|
|
5
|
+
// Storage providers
|
|
6
|
+
export * from './providers/index.js';
|
|
7
|
+
// Runtime utilities
|
|
8
|
+
export * from './runtime/index.js';
|
|
9
|
+
// Upload utilities
|
|
10
|
+
export * from './utils/index.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,cAAc,mBAAmB,CAAA;AAEjC,iBAAiB;AACjB,cAAc,mBAAmB,CAAA;AAEjC,oBAAoB;AACpB,cAAc,sBAAsB,CAAA;AAEpC,oBAAoB;AACpB,cAAc,oBAAoB,CAAA;AAElC,mBAAmB;AACnB,cAAc,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { StorageProvider, UploadOptions, UploadResult, LocalStorageConfig } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Local filesystem storage provider
|
|
4
|
+
* Stores files on the local filesystem
|
|
5
|
+
*/
|
|
6
|
+
export declare class LocalStorageProvider implements StorageProvider {
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config: LocalStorageConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Ensures the upload directory exists
|
|
11
|
+
*/
|
|
12
|
+
private ensureUploadDir;
|
|
13
|
+
/**
|
|
14
|
+
* Generates a unique filename if configured
|
|
15
|
+
*/
|
|
16
|
+
private generateFilename;
|
|
17
|
+
upload(file: Buffer | Uint8Array, filename: string, options?: UploadOptions): Promise<UploadResult>;
|
|
18
|
+
download(filename: string): Promise<Buffer>;
|
|
19
|
+
delete(filename: string): Promise<void>;
|
|
20
|
+
getUrl(filename: string): string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,kBAAkB,EACnB,MAAM,oBAAoB,CAAA;AAE3B;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,kBAAkB;IAItC;;OAEG;YACW,eAAe;IAQ7B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWlB,MAAM,CACV,IAAI,EAAE,MAAM,GAAG,UAAU,EACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC;IAqBlB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK3C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAGjC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
/**
|
|
5
|
+
* Local filesystem storage provider
|
|
6
|
+
* Stores files on the local filesystem
|
|
7
|
+
*/
|
|
8
|
+
export class LocalStorageProvider {
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ensures the upload directory exists
|
|
15
|
+
*/
|
|
16
|
+
async ensureUploadDir() {
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(this.config.uploadDir);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
await fs.mkdir(this.config.uploadDir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generates a unique filename if configured
|
|
26
|
+
*/
|
|
27
|
+
generateFilename(originalFilename) {
|
|
28
|
+
if (this.config.generateUniqueFilenames === false) {
|
|
29
|
+
return originalFilename;
|
|
30
|
+
}
|
|
31
|
+
const ext = path.extname(originalFilename);
|
|
32
|
+
const uniqueId = randomBytes(16).toString('hex');
|
|
33
|
+
const timestamp = Date.now();
|
|
34
|
+
return `${timestamp}-${uniqueId}${ext}`;
|
|
35
|
+
}
|
|
36
|
+
async upload(file, filename, options) {
|
|
37
|
+
await this.ensureUploadDir();
|
|
38
|
+
const generatedFilename = this.generateFilename(filename);
|
|
39
|
+
const filePath = path.join(this.config.uploadDir, generatedFilename);
|
|
40
|
+
// Write file to disk
|
|
41
|
+
await fs.writeFile(filePath, file);
|
|
42
|
+
// Get file stats for size
|
|
43
|
+
const stats = await fs.stat(filePath);
|
|
44
|
+
return {
|
|
45
|
+
filename: generatedFilename,
|
|
46
|
+
url: `${this.config.serveUrl}/${generatedFilename}`,
|
|
47
|
+
size: stats.size,
|
|
48
|
+
contentType: options?.contentType || 'application/octet-stream',
|
|
49
|
+
metadata: options?.metadata,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async download(filename) {
|
|
53
|
+
const filePath = path.join(this.config.uploadDir, filename);
|
|
54
|
+
return await fs.readFile(filePath);
|
|
55
|
+
}
|
|
56
|
+
async delete(filename) {
|
|
57
|
+
const filePath = path.join(this.config.uploadDir, filename);
|
|
58
|
+
await fs.unlink(filePath);
|
|
59
|
+
}
|
|
60
|
+
getUrl(filename) {
|
|
61
|
+
return `${this.config.serveUrl}/${filename}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAQzC;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IACvB,MAAM,CAAoB;IAElC,YAAY,MAA0B;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,gBAAwB;QAC/C,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,KAAK,KAAK,EAAE,CAAC;YAClD,OAAO,gBAAgB,CAAA;QACzB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC1C,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC5B,OAAO,GAAG,SAAS,IAAI,QAAQ,GAAG,GAAG,EAAE,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CACV,IAAyB,EACzB,QAAgB,EAChB,OAAuB;QAEvB,MAAM,IAAI,CAAC,eAAe,EAAE,CAAA;QAE5B,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAA;QAEpE,qBAAqB;QACrB,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAElC,0BAA0B;QAC1B,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAErC,OAAO;YACL,QAAQ,EAAE,iBAAiB;YAC3B,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,iBAAiB,EAAE;YACnD,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,0BAA0B;YAC/D,QAAQ,EAAE,OAAO,EAAE,QAAQ;SAC5B,CAAA;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC3D,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC3D,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,CAAC,QAAgB;QACrB,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAA;IAC9C,CAAC;CACF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core';
|
|
2
|
+
import type { StorageProvider, FileMetadata, ImageMetadata, ImageTransformationConfig } from '../config/types.js';
|
|
3
|
+
import { type FileValidationOptions } from '../utils/upload.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a storage provider instance from config
|
|
6
|
+
*/
|
|
7
|
+
export declare function createStorageProvider(config: OpenSaasConfig, providerName: string): StorageProvider;
|
|
8
|
+
/**
|
|
9
|
+
* Options for uploading a file
|
|
10
|
+
*/
|
|
11
|
+
export interface UploadFileOptions {
|
|
12
|
+
/** Validation options */
|
|
13
|
+
validation?: FileValidationOptions;
|
|
14
|
+
/** Custom metadata */
|
|
15
|
+
metadata?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Options for uploading an image with transformations
|
|
19
|
+
*/
|
|
20
|
+
export interface UploadImageOptions extends UploadFileOptions {
|
|
21
|
+
/** Image transformations to apply */
|
|
22
|
+
transformations?: Record<string, ImageTransformationConfig>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Uploads a file to the specified storage provider
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const metadata = await uploadFile(config, 'documents', {
|
|
30
|
+
* file,
|
|
31
|
+
* buffer,
|
|
32
|
+
* validation: {
|
|
33
|
+
* maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
34
|
+
* acceptedMimeTypes: ['application/pdf']
|
|
35
|
+
* }
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function uploadFile(config: OpenSaasConfig, storageProviderName: string, data: {
|
|
40
|
+
file: File;
|
|
41
|
+
buffer: Buffer;
|
|
42
|
+
}, options?: UploadFileOptions): Promise<FileMetadata>;
|
|
43
|
+
/**
|
|
44
|
+
* Uploads an image with optional transformations
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const metadata = await uploadImage(config, 'avatars', {
|
|
49
|
+
* file,
|
|
50
|
+
* buffer,
|
|
51
|
+
* validation: {
|
|
52
|
+
* maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
53
|
+
* acceptedMimeTypes: ['image/jpeg', 'image/png', 'image/webp']
|
|
54
|
+
* },
|
|
55
|
+
* transformations: {
|
|
56
|
+
* thumbnail: { width: 100, height: 100, fit: 'cover' },
|
|
57
|
+
* profile: { width: 400, height: 400, fit: 'cover' }
|
|
58
|
+
* }
|
|
59
|
+
* })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function uploadImage(config: OpenSaasConfig, storageProviderName: string, data: {
|
|
63
|
+
file: File;
|
|
64
|
+
buffer: Buffer;
|
|
65
|
+
}, options?: UploadImageOptions): Promise<ImageMetadata>;
|
|
66
|
+
/**
|
|
67
|
+
* Deletes a file from storage
|
|
68
|
+
*/
|
|
69
|
+
export declare function deleteFile(config: OpenSaasConfig, storageProviderName: string, filename: string): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Deletes an image and all its transformations from storage
|
|
72
|
+
*/
|
|
73
|
+
export declare function deleteImage(config: OpenSaasConfig, metadata: ImageMetadata): Promise<void>;
|
|
74
|
+
export { parseFileFromFormData } from '../utils/upload.js';
|
|
75
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EACV,eAAe,EAEf,YAAY,EACZ,aAAa,EACb,yBAAyB,EAC1B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAG1F;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,MAAM,GACnB,eAAe,CAajB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAA;CAC5D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,mBAAmB,EAAE,MAAM,EAC3B,IAAI,EAAE;IACJ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;CACf,EACD,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA0CvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,mBAAmB,EAAE,MAAM,EAC3B,IAAI,EAAE;IACJ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;CACf,EACD,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA8DxB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,cAAc,EACtB,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhG;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA"}
|