@uploadista/flow-utility-zipjs 0.0.3

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,5 @@
1
+
2
+ 
3
+ > @uploadista/flow-utility-zipjs@0.0.2 build /Users/denislaboureyras/Documents/uploadista/dev/uploadista-workspace/uploadista-sdk/packages/flow/utility/zipjs
4
+ > tsc -b
5
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,293 @@
1
+ # @uploadista/flow-utility-zipjs
2
+
3
+ Flow utility node for creating ZIP archives in Uploadista pipelines. Combines multiple files into compressed archives.
4
+
5
+ ## Overview
6
+
7
+ The Zip node enables archiving workflows without custom code:
8
+
9
+ - **Archive Creation**: Combine files into ZIP archives
10
+ - **Compression**: Reduce total size
11
+ - **Batch Processing**: Archive multiple files at once
12
+ - **Format**: Standard ZIP format compatible everywhere
13
+
14
+ Perfect for backup, distribution, and batch delivery workflows.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @uploadista/flow-utility-zipjs
20
+ # or
21
+ pnpm add @uploadista/flow-utility-zipjs
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { zipNode } from "@uploadista/flow-utility-zipjs";
28
+
29
+ const flow = {
30
+ nodes: [
31
+ { id: "input", type: "input" },
32
+ {
33
+ id: "archive",
34
+ type: "zip",
35
+ params: {
36
+ filename: "archive.zip",
37
+ compressionLevel: 6,
38
+ },
39
+ },
40
+ { id: "s3", type: "s3" },
41
+ { id: "output", type: "output" },
42
+ ],
43
+ edges: [
44
+ { from: "input", to: "archive" },
45
+ { from: "archive", to: "s3" },
46
+ { from: "s3", to: "output" },
47
+ ],
48
+ };
49
+ ```
50
+
51
+ ## Features
52
+
53
+ - ✅ **ZIP Archives**: Standard compression format
54
+ - ✅ **Configurable**: Compression levels and naming
55
+ - ✅ **Streaming**: Memory-efficient processing
56
+ - ✅ **Metadata**: Preserve file information
57
+ - ✅ **Cross-Platform**: Works everywhere
58
+
59
+ ## Node Parameters
60
+
61
+ ```typescript
62
+ {
63
+ filename: string, // Output archive name
64
+ compressionLevel?: 0-9, // Compression (default: 6)
65
+ comment?: string, // ZIP comment
66
+ }
67
+ ```
68
+
69
+ ## Configuration
70
+
71
+ ### Basic Archive
72
+
73
+ ```typescript
74
+ {
75
+ type: "zip",
76
+ params: {
77
+ filename: "backup.zip",
78
+ },
79
+ }
80
+ ```
81
+
82
+ ### High Compression
83
+
84
+ ```typescript
85
+ {
86
+ type: "zip",
87
+ params: {
88
+ filename: "archive.zip",
89
+ compressionLevel: 9, // Maximum compression
90
+ },
91
+ }
92
+ ```
93
+
94
+ ### With Metadata
95
+
96
+ ```typescript
97
+ {
98
+ type: "zip",
99
+ params: {
100
+ filename: "export.zip",
101
+ comment: "Export from upload batch",
102
+ },
103
+ }
104
+ ```
105
+
106
+ ## Use Cases
107
+
108
+ ### Case 1: Backup Archive
109
+
110
+ ```
111
+ Multiple Files → Zip ("backup.zip") → S3 Storage → Download
112
+ ```
113
+
114
+ ### Case 2: Distribution Package
115
+
116
+ ```
117
+ Input Files → Zip ("release.zip") → CDN → Users
118
+ ```
119
+
120
+ ### Case 3: Batch Delivery
121
+
122
+ ```
123
+ Batch Input → Merge → Zip ("batch.zip") → Email → Recipients
124
+ ```
125
+
126
+ ## Examples
127
+
128
+ ### Example 1: Create Backup Archive
129
+
130
+ ```typescript
131
+ const backupFlow = {
132
+ nodes: [
133
+ { id: "input", type: "input" },
134
+ {
135
+ id: "archive",
136
+ type: "zip",
137
+ params: {
138
+ filename: "backup-2025-10-21.zip",
139
+ compressionLevel: 9,
140
+ comment: "Full backup archive",
141
+ },
142
+ },
143
+ { id: "s3", type: "s3", params: { bucket: "backups" } },
144
+ { id: "output", type: "output" },
145
+ ],
146
+ edges: [
147
+ { from: "input", to: "archive" },
148
+ { from: "archive", to: "s3" },
149
+ { from: "s3", to: "output" },
150
+ ],
151
+ };
152
+ ```
153
+
154
+ ### Example 2: Package Multiple Uploads
155
+
156
+ ```typescript
157
+ const packageFlow = {
158
+ nodes: [
159
+ { id: "file1", type: "input" },
160
+ { id: "file2", type: "input" },
161
+ { id: "file3", type: "input" },
162
+ {
163
+ id: "merge",
164
+ type: "merge",
165
+ params: { strategy: "batch", inputCount: 3 },
166
+ },
167
+ {
168
+ id: "zip",
169
+ type: "zip",
170
+ params: { filename: "package.zip" },
171
+ },
172
+ { id: "s3", type: "s3" },
173
+ { id: "output", type: "output" },
174
+ ],
175
+ edges: [
176
+ { from: "file1", to: "merge" },
177
+ { from: "file2", to: "merge" },
178
+ { from: "file3", to: "merge" },
179
+ { from: "merge", to: "zip" },
180
+ { from: "zip", to: "s3" },
181
+ { from: "s3", to: "output" },
182
+ ],
183
+ };
184
+ ```
185
+
186
+ ### Example 3: Conditional Archiving
187
+
188
+ ```typescript
189
+ const conditionalArchive = {
190
+ nodes: [
191
+ { id: "input", type: "input" },
192
+ {
193
+ id: "isDocument",
194
+ type: "conditional",
195
+ params: {
196
+ field: "mimeType",
197
+ operator: "contains",
198
+ value: "pdf",
199
+ },
200
+ },
201
+ {
202
+ id: "archive",
203
+ type: "zip",
204
+ params: { filename: "documents.zip" },
205
+ },
206
+ { id: "s3", type: "s3" },
207
+ { id: "output", type: "output" },
208
+ ],
209
+ edges: [
210
+ { from: "input", to: "isDocument" },
211
+ { from: "isDocument", true: "archive", false: "s3" },
212
+ { from: "archive", to: "s3" },
213
+ { from: "s3", to: "output" },
214
+ ],
215
+ };
216
+ ```
217
+
218
+ ## Performance
219
+
220
+ | Operation | Time |
221
+ |-----------|------|
222
+ | Small archive (< 100MB) | ~100ms |
223
+ | Medium archive (100-500MB) | ~500ms |
224
+ | Large archive (500MB-1GB) | ~2-5s |
225
+ | Compression Level 1 | ~50% faster |
226
+ | Compression Level 9 | ~50% slower, 20-30% smaller |
227
+
228
+ Compression level recommendations:
229
+ - Level 1-3: Speed priority (network bottleneck)
230
+ - Level 6: Default balance (recommended)
231
+ - Level 9: Size priority (cold storage)
232
+
233
+ ## Best Practices
234
+
235
+ ### 1. Choose Appropriate Compression
236
+
237
+ ```typescript
238
+ // Fast for network delivery
239
+ { compressionLevel: 3 }
240
+
241
+ // Balanced (recommended)
242
+ { compressionLevel: 6 }
243
+
244
+ // Maximum for storage
245
+ { compressionLevel: 9 }
246
+ ```
247
+
248
+ ### 2. Meaningful Archive Names
249
+
250
+ ```typescript
251
+ // Good: Descriptive
252
+ "backup-2025-10-21.zip"
253
+ "export-users.zip"
254
+ "release-v1.0.0.zip"
255
+
256
+ // Avoid: Generic
257
+ "archive.zip"
258
+ "output.zip"
259
+ ```
260
+
261
+ ### 3. Monitor Archive Size
262
+
263
+ ```typescript
264
+ // Check output before upload
265
+ const archiveSize = yield* getFileSize(archiveFile);
266
+
267
+ if (archiveSize > MAX_ARCHIVE_SIZE) {
268
+ // Split into multiple archives
269
+ }
270
+ ```
271
+
272
+ ## Limitations
273
+
274
+ - **ZIP Format**: Limited to ZIP (no 7z, rar, etc)
275
+ - **Size Limits**: File size limited by available memory
276
+ - **Compression Overhead**: Small files may grow when archived
277
+ - **No Encryption**: Standard ZIP (optional encryption in future)
278
+
279
+ ## Related Packages
280
+
281
+ - [@uploadista/flow-utility-nodes](../nodes) - Conditional routing
282
+ - [@uploadista/core](../../core) - Core flow types
283
+ - [@uploadista/flow-images-sharp](../images/sharp) - Image optimization
284
+ - [@uploadista/server](../../servers/server) - Upload server
285
+
286
+ ## License
287
+
288
+ See [LICENSE](../../../LICENSE) in the main repository.
289
+
290
+ ## See Also
291
+
292
+ - [FLOW_NODES.md](../FLOW_NODES.md) - All available nodes
293
+ - [Server Setup Guide](../../../SERVER_SETUP.md) - Flow integration
@@ -0,0 +1,2 @@
1
+ export * from "./zip-plugin";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./zip-plugin";
@@ -0,0 +1,4 @@
1
+ import { ZipPlugin } from "@uploadista/core/flow";
2
+ import { Layer } from "effect";
3
+ export declare const zipJsPlugin: () => Layer.Layer<ZipPlugin, never, never>;
4
+ //# sourceMappingURL=zip-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-plugin.d.ts","sourceRoot":"","sources":["../src/zip-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAGvC,eAAO,MAAM,WAAW,4CAwDvB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import { ZipPlugin } from "@uploadista/core/flow";
3
+ import { Effect, Layer } from "effect";
4
+ import JSZip from "jszip";
5
+ export const zipJsPlugin = () => {
6
+ return Layer.succeed(ZipPlugin, ZipPlugin.of({
7
+ zip: (inputs, options) => {
8
+ return Effect.gen(function* () {
9
+ const { includeMetadata } = options;
10
+ const zip = new JSZip();
11
+ // Process all input files
12
+ for (const input of inputs) {
13
+ // Use metadata for filename if available, otherwise use id
14
+ const fileName = input.metadata?.fileName ||
15
+ input.metadata?.originalName ||
16
+ input.id;
17
+ zip.file(fileName.toString(), input.data);
18
+ if (includeMetadata && input.metadata) {
19
+ zip.file(`${fileName}.meta.json`, JSON.stringify(input.metadata, null, 2));
20
+ }
21
+ }
22
+ // Generate the zip file
23
+ const zipBuffer = yield* Effect.tryPromise({
24
+ try: () => zip.generateAsync({
25
+ type: "nodebuffer",
26
+ compression: "DEFLATE",
27
+ compressionOptions: {
28
+ level: 6, // Good balance between speed and compression
29
+ },
30
+ }),
31
+ catch: (error) => UploadistaError.fromCode("UNKNOWN_ERROR", {
32
+ body: "Failed to generate zip file",
33
+ cause: error,
34
+ }),
35
+ });
36
+ // Convert to Uint8Array
37
+ const zipBytes = new Uint8Array(zipBuffer.buffer, zipBuffer.byteOffset, zipBuffer.byteLength);
38
+ return zipBytes;
39
+ });
40
+ },
41
+ }));
42
+ };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@uploadista/flow-utility-zipjs",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "ZipJS utility for Uploadista Flow",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "dependencies": {
16
+ "effect": "3.18.4",
17
+ "jszip": "3.10.1",
18
+ "zod": "4.1.12",
19
+ "@uploadista/core": "0.0.3"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "24.8.1",
23
+ "@uploadista/typescript-config": "0.0.3"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -b",
27
+ "format": "biome format --write ./src",
28
+ "lint": "biome lint --write ./src",
29
+ "check": "biome check --write ./src"
30
+ }
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./zip-plugin";
@@ -0,0 +1,62 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import { ZipPlugin } from "@uploadista/core/flow";
3
+ import { Effect, Layer } from "effect";
4
+ import JSZip from "jszip";
5
+
6
+ export const zipJsPlugin = () => {
7
+ return Layer.succeed(
8
+ ZipPlugin,
9
+ ZipPlugin.of({
10
+ zip: (inputs, options) => {
11
+ return Effect.gen(function* () {
12
+ const { includeMetadata } = options;
13
+ const zip = new JSZip();
14
+
15
+ // Process all input files
16
+ for (const input of inputs) {
17
+ // Use metadata for filename if available, otherwise use id
18
+ const fileName =
19
+ input.metadata?.fileName ||
20
+ input.metadata?.originalName ||
21
+ input.id;
22
+
23
+ zip.file(fileName.toString(), input.data);
24
+
25
+ if (includeMetadata && input.metadata) {
26
+ zip.file(
27
+ `${fileName}.meta.json`,
28
+ JSON.stringify(input.metadata, null, 2),
29
+ );
30
+ }
31
+ }
32
+
33
+ // Generate the zip file
34
+ const zipBuffer = yield* Effect.tryPromise({
35
+ try: () =>
36
+ zip.generateAsync({
37
+ type: "nodebuffer",
38
+ compression: "DEFLATE",
39
+ compressionOptions: {
40
+ level: 6, // Good balance between speed and compression
41
+ },
42
+ }),
43
+ catch: (error) =>
44
+ UploadistaError.fromCode("UNKNOWN_ERROR", {
45
+ body: "Failed to generate zip file",
46
+ cause: error,
47
+ }),
48
+ });
49
+
50
+ // Convert to Uint8Array
51
+ const zipBytes = new Uint8Array(
52
+ zipBuffer.buffer,
53
+ zipBuffer.byteOffset,
54
+ zipBuffer.byteLength,
55
+ );
56
+
57
+ return zipBytes;
58
+ });
59
+ },
60
+ }),
61
+ );
62
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "@uploadista/typescript-config/server.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./",
5
+ "paths": {
6
+ "@/*": ["./src/*"]
7
+ },
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
11
+ "types": []
12
+ },
13
+ "include": ["src"]
14
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts","./src/zip-plugin.ts"],"version":"5.9.3"}