@stacksjs/storage 0.75.161 → 0.75.163
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/dist/zip.d.ts +34 -0
- package/dist/zip.js +1 -1
- package/package.json +10 -10
package/dist/zip.d.ts
CHANGED
|
@@ -41,6 +41,40 @@ export declare function gzipSync(data: Uint8Array, options?: ZlibCompressionOpti
|
|
|
41
41
|
export declare function gunzipSync(data: Uint8Array): Uint8Array;
|
|
42
42
|
export declare function deflateSync(data: Uint8Array, options?: ZlibCompressionOptions): Uint8Array;
|
|
43
43
|
export declare function inflateSync(data: Uint8Array): Uint8Array;
|
|
44
|
+
/**
|
|
45
|
+
* Build a ZIP archive in memory and return its bytes - for a download made of
|
|
46
|
+
* several files, answered straight from a request:
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const bytes = zipEntries([
|
|
50
|
+
* { name: 'members.csv', data: membersCsv },
|
|
51
|
+
* { name: 'README.txt', data: 'What each file holds.' },
|
|
52
|
+
* ])
|
|
53
|
+
* return new Response(bytes, { headers: { 'Content-Type': 'application/zip' } })
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* Unlike {@link zip}, nothing touches the disk and no `zip` binary is needed.
|
|
57
|
+
* The format follows PKWARE's APPNOTE 6.3 (section 4): CRC-32 per entry,
|
|
58
|
+
* UTF-8 names (general purpose bit 11), DOS timestamps, and each entry
|
|
59
|
+
* deflated (method 8, Bun's raw DEFLATE) when that is smaller, else stored
|
|
60
|
+
* (method 0). Every unzip tool reads both.
|
|
61
|
+
*
|
|
62
|
+
* Entry order is kept. A repeated name, or a name that is absolute or holds a
|
|
63
|
+
* `..` part, is refused. There is no ZIP64, so an archive past 65,535 entries
|
|
64
|
+
* or 4 GB (any entry, offset or the whole archive) throws rather than writing
|
|
65
|
+
* a file readers would get wrong.
|
|
66
|
+
*/
|
|
67
|
+
export declare function zipEntries(entries: ZipEntry[], options?: ZipEntriesOptions): Uint8Array;
|
|
44
68
|
declare interface ZipOptions {
|
|
45
69
|
cwd?: string
|
|
46
70
|
}
|
|
71
|
+
/** One file for {@link zipEntries}. */
|
|
72
|
+
export declare interface ZipEntry {
|
|
73
|
+
name: string
|
|
74
|
+
data: string | Uint8Array
|
|
75
|
+
date?: Date
|
|
76
|
+
}
|
|
77
|
+
export declare interface ZipEntriesOptions {
|
|
78
|
+
level?: number
|
|
79
|
+
date?: Date
|
|
80
|
+
}
|
package/dist/zip.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{runCommand}from"@stacksjs/cli";export async function zip(from,to,options){const toPath=to||"archive.zip",sources=Array.isArray(from)?from:[from];return runCommand(["zip","-r",toPath,...sources],options)}export async function unzip(paths,options){const[first,...rest]=Array.isArray(paths)?paths:[paths];if(first===void 0)throw Error("unzip() needs at least one archive");let result=await runCommand(["unzip","-o",first],options);for(const source of rest){if(result.isErr)break;result=await runCommand(["unzip","-o",source],options)}return result}export function archive(paths,to,options){return zip(paths,to,options)}export function unarchive(paths,options){return unzip(paths,options)}export function compress(paths,to,options){return zip(paths,to,options)}export function decompress(paths,options){return unzip(paths,options)}export function gzipSync(data,options){return Bun.gzipSync(data,options)}export function gunzipSync(data){return Bun.gunzipSync(data)}export function deflateSync(data,options){return Bun.deflateSync(data,options)}export function inflateSync(data){return Bun.inflateSync(data)}
|
|
1
|
+
import{runCommand}from"@stacksjs/cli";export async function zip(from,to,options){const toPath=to||"archive.zip",sources=Array.isArray(from)?from:[from];return runCommand(["zip","-r",toPath,...sources],options)}export async function unzip(paths,options){const[first,...rest]=Array.isArray(paths)?paths:[paths];if(first===void 0)throw Error("unzip() needs at least one archive");let result=await runCommand(["unzip","-o",first],options);for(const source of rest){if(result.isErr)break;result=await runCommand(["unzip","-o",source],options)}return result}export function archive(paths,to,options){return zip(paths,to,options)}export function unarchive(paths,options){return unzip(paths,options)}export function compress(paths,to,options){return zip(paths,to,options)}export function decompress(paths,options){return unzip(paths,options)}export function gzipSync(data,options){return Bun.gzipSync(data,options)}export function gunzipSync(data){return Bun.gunzipSync(data)}export function deflateSync(data,options){return Bun.deflateSync(data,options)}export function inflateSync(data){return Bun.inflateSync(data)}const ZIP32_LIMIT=4294967295,zipText=new TextEncoder;function dosDateTime(at){if(Number.isNaN(at.getTime()))throw Error("zipEntries(): an entry has an invalid date");if(at.getFullYear()<1980)return{date:33,time:0};if(at.getFullYear()>2107)return{date:65439,time:49021};return{date:at.getFullYear()-1980<<9|at.getMonth()+1<<5|at.getDate(),time:at.getHours()<<11|at.getMinutes()<<5|at.getSeconds()>>1}}function zipEntryName(name){const path=String(name??"").replace(/\\/g,"/");if(!path||path.startsWith("/")||/^[a-z]:/i.test(path)||path.includes("\x00")||path.split("/").some((part)=>part===""||part==="."||part===".."))throw Error(`zipEntries(): "${name}" is not a safe file name inside a ZIP (relative, forward slashes, no empty, "." or ".." parts)`);return path}export function zipEntries(entries,options={}){if(entries.length>65535)throw Error(`zipEntries(): ${entries.length} entries is more than the 65,535 a ZIP without ZIP64 holds`);const level=options.level??6;if(!Number.isInteger(level)||level<0||level>9)throw Error(`zipEntries(): level must be an integer from 0 to 9, got ${level}`);const tooBig=(what)=>Error(`zipEntries(): ${what} is past the 4 GB a ZIP without ZIP64 holds`),fallbackDate=options.date??new Date,seen=new Set,parts=[],centrals=[];let offset=0;for(const entry of entries){const path=zipEntryName(entry.name);if(seen.has(path))throw Error(`zipEntries(): two entries are named "${path}"`);seen.add(path);const name=zipText.encode(path);if(name.length>65535)throw Error(`zipEntries(): the name "${path.slice(0,40)}..." is longer than 65,535 bytes`);const raw=typeof entry.data==="string"?zipText.encode(entry.data):entry.data;if(raw.length>=ZIP32_LIMIT)throw tooBig(`"${path}" (${raw.length} bytes)`);if(offset>=ZIP32_LIMIT)throw tooBig(`the archive before "${path}"`);const crc=Bun.hash.crc32(raw)>>>0,deflated=level>0&&raw.length>0?deflateSync(raw,{level}):void 0,method=deflated&&deflated.length<raw.length?8:0,data=method===8?deflated:raw,{date,time}=dosDateTime(entry.date??fallbackDate),local=new Uint8Array(30+name.length),head=new DataView(local.buffer);head.setUint32(0,67324752,!0);head.setUint16(4,20,!0);head.setUint16(6,2048,!0);head.setUint16(8,method,!0);head.setUint16(10,time,!0);head.setUint16(12,date,!0);head.setUint32(14,crc,!0);head.setUint32(18,data.length,!0);head.setUint32(22,raw.length,!0);head.setUint16(26,name.length,!0);head.setUint16(28,0,!0);local.set(name,30);const central=new Uint8Array(46+name.length),dir=new DataView(central.buffer);dir.setUint32(0,33639248,!0);dir.setUint16(4,788,!0);dir.setUint16(6,20,!0);dir.setUint16(8,2048,!0);dir.setUint16(10,method,!0);dir.setUint16(12,time,!0);dir.setUint16(14,date,!0);dir.setUint32(16,crc,!0);dir.setUint32(20,data.length,!0);dir.setUint32(24,raw.length,!0);dir.setUint16(28,name.length,!0);dir.setUint32(38,2175008768,!0);dir.setUint32(42,offset,!0);central.set(name,46);parts.push(local,data);centrals.push(central);offset+=local.length+data.length}const directorySize=centrals.reduce((total,part)=>total+part.length,0);if(offset>=ZIP32_LIMIT||offset+directorySize+22>ZIP32_LIMIT)throw tooBig("the archive");const end=new Uint8Array(22),tail=new DataView(end.buffer);tail.setUint32(0,101010256,!0);tail.setUint16(8,entries.length,!0);tail.setUint16(10,entries.length,!0);tail.setUint32(12,directorySize,!0);tail.setUint32(16,offset,!0);const out=new Uint8Array(offset+directorySize+end.length);let at=0;for(const part of[...parts,...centrals,end]){out.set(part,at);at+=part.length}return out}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/storage",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.163",
|
|
6
6
|
"description": "The Stacks file system.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -61,20 +61,20 @@
|
|
|
61
61
|
"prepublishOnly": "bun run build"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@stacksjs/arrays": "0.75.
|
|
65
|
-
"@stacksjs/cli": "0.75.
|
|
66
|
-
"@stacksjs/config": "0.75.
|
|
67
|
-
"@stacksjs/env": "0.75.
|
|
68
|
-
"@stacksjs/error-handling": "0.75.
|
|
69
|
-
"@stacksjs/logging": "0.75.
|
|
70
|
-
"@stacksjs/path": "0.75.
|
|
71
|
-
"@stacksjs/strings": "0.75.
|
|
64
|
+
"@stacksjs/arrays": "0.75.163",
|
|
65
|
+
"@stacksjs/cli": "0.75.163",
|
|
66
|
+
"@stacksjs/config": "0.75.163",
|
|
67
|
+
"@stacksjs/env": "0.75.163",
|
|
68
|
+
"@stacksjs/error-handling": "0.75.163",
|
|
69
|
+
"@stacksjs/logging": "0.75.163",
|
|
70
|
+
"@stacksjs/path": "0.75.163",
|
|
71
|
+
"@stacksjs/strings": "0.75.163",
|
|
72
72
|
"@stacksjs/ts-cloud": "^0.16.52",
|
|
73
73
|
"@stacksjs/ts-xml": "^0.1.0",
|
|
74
74
|
"ts-images": "^0.2.23"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@stacksjs/types": "0.75.
|
|
77
|
+
"@stacksjs/types": "0.75.163",
|
|
78
78
|
"better-dx": "^0.2.24"
|
|
79
79
|
}
|
|
80
80
|
}
|