modern-tar 0.4.2 → 0.5.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/README.md +4 -1
- package/dist/fs/index.d.ts +32 -15
- package/dist/fs/index.js +38 -15
- package/dist/{types-D-xPQp4Z.d.ts → types-Dc3p5B3s.d.ts} +2 -26
- package/dist/{unpacker-DBTDVhe4.js → unpacker-yB6Ahxxk.js} +19 -28
- package/dist/web/index.d.ts +27 -1
- package/dist/web/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -205,8 +205,11 @@ import { pipeline } from 'node:stream/promises';
|
|
|
205
205
|
const sources: TarSource[] = [
|
|
206
206
|
{ type: 'file', source: './package.json', target: 'project/package.json' },
|
|
207
207
|
{ type: 'directory', source: './src', target: 'project/src' },
|
|
208
|
+
|
|
208
209
|
{ type: 'content', content: 'Hello World!', target: 'project/hello.txt' },
|
|
209
|
-
{ type: 'content', content: '#!/bin/bash\necho "Executable"', target: 'bin/script.sh', mode: 0o755 }
|
|
210
|
+
{ type: 'content', content: '#!/bin/bash\necho "Executable"', target: 'bin/script.sh', mode: 0o755 },
|
|
211
|
+
{ type: 'stream', content: createReadStream('./large-file.bin'), target: 'project/data.bin', size: 1048576 },
|
|
212
|
+
{ type: 'stream', content: fetch('/api/data').then(r => r.body!), target: 'project/remote.json', size: 2048 }
|
|
210
213
|
];
|
|
211
214
|
|
|
212
215
|
const archiveStream = packTar(sources);
|
package/dist/fs/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TarEntryData, TarHeader, UnpackOptions } from "../types-
|
|
1
|
+
import { TarEntryData, TarHeader, UnpackOptions } from "../types-Dc3p5B3s.js";
|
|
2
2
|
import { Readable, Writable } from "node:stream";
|
|
3
3
|
import { Stats } from "node:fs";
|
|
4
4
|
|
|
@@ -50,34 +50,51 @@ interface UnpackOptionsFS extends UnpackOptions {
|
|
|
50
50
|
*/
|
|
51
51
|
concurrency?: number;
|
|
52
52
|
}
|
|
53
|
+
/** Base interface containing common metadata properties for all source types. */
|
|
54
|
+
interface BaseSource {
|
|
55
|
+
/** Destination path for the entry inside the tar archive. */
|
|
56
|
+
target: string;
|
|
57
|
+
/** Optional modification time. Overrides filesystem values or defaults to current time. */
|
|
58
|
+
mtime?: Date;
|
|
59
|
+
/** Optional user ID. Overrides filesystem values or defaults to 0. */
|
|
60
|
+
uid?: number;
|
|
61
|
+
/** Optional group ID. Overrides filesystem values or defaults to 0. */
|
|
62
|
+
gid?: number;
|
|
63
|
+
/** Optional user name. */
|
|
64
|
+
uname?: string;
|
|
65
|
+
/** Optional group name. */
|
|
66
|
+
gname?: string;
|
|
67
|
+
/** Optional Unix file permissions for the entry (e.g., 0o644, 0o755). */
|
|
68
|
+
mode?: number;
|
|
69
|
+
}
|
|
53
70
|
/** Describes a file on the local filesystem to be added to the archive. */
|
|
54
|
-
interface FileSource {
|
|
71
|
+
interface FileSource extends BaseSource {
|
|
55
72
|
type: "file";
|
|
56
73
|
/** Path to the source file on the local filesystem. */
|
|
57
74
|
source: string;
|
|
58
|
-
/** Destination path for the file inside the tar archive. */
|
|
59
|
-
target: string;
|
|
60
75
|
}
|
|
61
76
|
/** Describes a directory on the local filesystem to be added to the archive. */
|
|
62
|
-
interface DirectorySource {
|
|
77
|
+
interface DirectorySource extends BaseSource {
|
|
63
78
|
type: "directory";
|
|
64
79
|
/** Path to the source directory on the local filesystem. */
|
|
65
80
|
source: string;
|
|
66
|
-
/** Destination path for the directory inside the tar archive. */
|
|
67
|
-
target: string;
|
|
68
81
|
}
|
|
69
|
-
/** Describes raw content to be added to the archive.
|
|
70
|
-
interface ContentSource {
|
|
82
|
+
/** Describes raw, buffered content to be added to the archive. */
|
|
83
|
+
interface ContentSource extends BaseSource {
|
|
71
84
|
type: "content";
|
|
72
|
-
/** Raw content to add. Supports string, Uint8Array, ArrayBuffer,
|
|
85
|
+
/** Raw content to add. Supports string, Uint8Array, ArrayBuffer, Blob, or null. */
|
|
73
86
|
content: TarEntryData;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
}
|
|
88
|
+
/** Describes a stream of content to be added to the archive. */
|
|
89
|
+
interface StreamSource extends BaseSource {
|
|
90
|
+
type: "stream";
|
|
91
|
+
/** A Readable or ReadableStream. */
|
|
92
|
+
content: Readable | ReadableStream;
|
|
93
|
+
/** The total size of the stream's content in bytes. This is required for streams. */
|
|
94
|
+
size: number;
|
|
78
95
|
}
|
|
79
96
|
/** A union of all possible source types for creating a tar archive. */
|
|
80
|
-
type TarSource = FileSource | DirectorySource | ContentSource;
|
|
97
|
+
type TarSource = FileSource | DirectorySource | ContentSource | StreamSource;
|
|
81
98
|
//#endregion
|
|
82
99
|
//#region src/fs/pack.d.ts
|
|
83
100
|
/**
|
package/dist/fs/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTarPacker, createTarUnpacker, normalizeBody, transformHeader } from "../unpacker-
|
|
1
|
+
import { createTarPacker, createTarUnpacker, normalizeBody, transformHeader } from "../unpacker-yB6Ahxxk.js";
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import { cpus } from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
@@ -46,7 +46,16 @@ function packTar(sources, options = {}) {
|
|
|
46
46
|
packer.add(result.header);
|
|
47
47
|
if (result.body) if (result.body instanceof Uint8Array) {
|
|
48
48
|
if (result.body.length > 0) packer.write(result.body);
|
|
49
|
-
} else {
|
|
49
|
+
} else if (result.body instanceof Readable || result.body instanceof ReadableStream) try {
|
|
50
|
+
for await (const chunk of result.body) {
|
|
51
|
+
if (stream.destroyed) break;
|
|
52
|
+
packer.write(chunk instanceof Uint8Array ? chunk : Buffer.from(chunk));
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
stream.destroy(error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
50
59
|
const { handle, size } = result.body;
|
|
51
60
|
try {
|
|
52
61
|
let bytesLeft = size;
|
|
@@ -87,32 +96,44 @@ function packTar(sources, options = {}) {
|
|
|
87
96
|
let jobResult = null;
|
|
88
97
|
const target = job.target.replace(/\\/g, "/");
|
|
89
98
|
try {
|
|
90
|
-
if (job.type === "content") {
|
|
91
|
-
|
|
99
|
+
if (job.type === "content" || job.type === "stream") {
|
|
100
|
+
let body$1;
|
|
101
|
+
let size;
|
|
102
|
+
if (job.type === "stream") {
|
|
103
|
+
if (typeof job.size !== "number" || job.size <= 0) throw new Error("StreamSource requires a positive size property.");
|
|
104
|
+
size = job.size;
|
|
105
|
+
body$1 = job.content;
|
|
106
|
+
} else {
|
|
107
|
+
const content = await normalizeBody(job.content);
|
|
108
|
+
size = content.length;
|
|
109
|
+
body$1 = content;
|
|
110
|
+
}
|
|
92
111
|
const stat$1 = {
|
|
93
|
-
size
|
|
112
|
+
size,
|
|
94
113
|
isFile: () => true,
|
|
95
114
|
isDirectory: () => false,
|
|
96
115
|
isSymbolicLink: () => false,
|
|
97
116
|
mode: job.mode ?? 420,
|
|
98
|
-
mtime: /* @__PURE__ */ new Date(),
|
|
99
|
-
uid:
|
|
100
|
-
gid:
|
|
117
|
+
mtime: job.mtime ?? /* @__PURE__ */ new Date(),
|
|
118
|
+
uid: job.uid ?? 0,
|
|
119
|
+
gid: job.gid ?? 0
|
|
101
120
|
};
|
|
102
121
|
if (filter && !filter(target, stat$1)) return;
|
|
103
122
|
let header$1 = {
|
|
104
123
|
name: target,
|
|
105
124
|
type: "file",
|
|
106
|
-
size
|
|
125
|
+
size,
|
|
107
126
|
mode: stat$1.mode,
|
|
108
127
|
mtime: stat$1.mtime,
|
|
109
128
|
uid: stat$1.uid,
|
|
110
|
-
gid: stat$1.gid
|
|
129
|
+
gid: stat$1.gid,
|
|
130
|
+
uname: job.uname,
|
|
131
|
+
gname: job.gname
|
|
111
132
|
};
|
|
112
133
|
if (map) header$1 = map(header$1);
|
|
113
134
|
jobResult = {
|
|
114
135
|
header: header$1,
|
|
115
|
-
body:
|
|
136
|
+
body: body$1
|
|
116
137
|
};
|
|
117
138
|
return;
|
|
118
139
|
}
|
|
@@ -128,10 +149,12 @@ function packTar(sources, options = {}) {
|
|
|
128
149
|
let header = {
|
|
129
150
|
name: target,
|
|
130
151
|
size: 0,
|
|
131
|
-
mode: Number(stat.mode),
|
|
132
|
-
mtime: stat.mtime,
|
|
133
|
-
uid: Number(stat.uid),
|
|
134
|
-
gid: Number(stat.gid),
|
|
152
|
+
mode: job.mode ?? Number(stat.mode),
|
|
153
|
+
mtime: job.mtime ?? stat.mtime,
|
|
154
|
+
uid: job.uid ?? Number(stat.uid),
|
|
155
|
+
gid: job.gid ?? Number(stat.gid),
|
|
156
|
+
uname: job.uname,
|
|
157
|
+
gname: job.gname,
|
|
135
158
|
type: "file"
|
|
136
159
|
};
|
|
137
160
|
let body;
|
|
@@ -46,31 +46,7 @@ interface TarHeader {
|
|
|
46
46
|
/**
|
|
47
47
|
* Union type for entry body data that can be packed into a tar archive.
|
|
48
48
|
*/
|
|
49
|
-
type TarEntryData = string | Uint8Array | ArrayBuffer |
|
|
50
|
-
/**
|
|
51
|
-
* Represents a complete entry to be packed into a tar archive.
|
|
52
|
-
*
|
|
53
|
-
* Combines header metadata with optional body data. Used as input to {@link packTar}
|
|
54
|
-
* and the controller returned by {@link createTarPacker}.
|
|
55
|
-
*/
|
|
56
|
-
interface TarEntry {
|
|
57
|
-
header: TarHeader;
|
|
58
|
-
body?: TarEntryData;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Represents an entry parsed from a tar archive stream.
|
|
62
|
-
*/
|
|
63
|
-
interface ParsedTarEntry {
|
|
64
|
-
header: TarHeader;
|
|
65
|
-
body: ReadableStream<Uint8Array>;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Represents an extracted entry with fully buffered content.
|
|
69
|
-
*/
|
|
70
|
-
interface ParsedTarEntryWithData {
|
|
71
|
-
header: TarHeader;
|
|
72
|
-
data: Uint8Array;
|
|
73
|
-
}
|
|
49
|
+
type TarEntryData = string | Uint8Array | ArrayBuffer | Blob | null | undefined;
|
|
74
50
|
/**
|
|
75
51
|
* Configuration options for creating a tar decoder stream.
|
|
76
52
|
*/
|
|
@@ -105,4 +81,4 @@ interface UnpackOptions extends DecoderOptions {
|
|
|
105
81
|
streamTimeout?: number;
|
|
106
82
|
}
|
|
107
83
|
//#endregion
|
|
108
|
-
export { DecoderOptions,
|
|
84
|
+
export { DecoderOptions, TarEntryData, TarHeader, UnpackOptions };
|
|
@@ -93,8 +93,10 @@ function readOctal(view, offset, size) {
|
|
|
93
93
|
function readNumeric(view, offset, size) {
|
|
94
94
|
if (view[offset] & 128) {
|
|
95
95
|
let result = 0;
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
result = view[offset] & 127;
|
|
97
|
+
for (let i = 1; i < size; i++) result = result * 256 + view[offset + i];
|
|
98
|
+
if (!Number.isSafeInteger(result)) throw new Error("TAR number too large");
|
|
99
|
+
return result;
|
|
98
100
|
}
|
|
99
101
|
return readOctal(view, offset, size);
|
|
100
102
|
}
|
|
@@ -126,7 +128,6 @@ async function normalizeBody(body) {
|
|
|
126
128
|
if (typeof body === "string") return encoder.encode(body);
|
|
127
129
|
if (body instanceof ArrayBuffer) return new Uint8Array(body);
|
|
128
130
|
if (body instanceof Blob) return new Uint8Array(await body.arrayBuffer());
|
|
129
|
-
if (body instanceof ReadableStream) return streamToBuffer(body);
|
|
130
131
|
throw new TypeError("Unsupported content type for entry body.");
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -253,6 +254,16 @@ function parseUstarHeader(block, strict) {
|
|
|
253
254
|
if (magic === "ustar") header.prefix = readString(block, USTAR_PREFIX_OFFSET, USTAR_PREFIX_SIZE);
|
|
254
255
|
return header;
|
|
255
256
|
}
|
|
257
|
+
const PAX_MAPPING = {
|
|
258
|
+
path: ["name", (v) => v],
|
|
259
|
+
linkpath: ["linkname", (v) => v],
|
|
260
|
+
size: ["size", (v) => parseInt(v, 10)],
|
|
261
|
+
mtime: ["mtime", parseFloat],
|
|
262
|
+
uid: ["uid", (v) => parseInt(v, 10)],
|
|
263
|
+
gid: ["gid", (v) => parseInt(v, 10)],
|
|
264
|
+
uname: ["uname", (v) => v],
|
|
265
|
+
gname: ["gname", (v) => v]
|
|
266
|
+
};
|
|
256
267
|
function parsePax(buffer) {
|
|
257
268
|
const decoder$1 = new TextDecoder("utf-8");
|
|
258
269
|
const overrides = {};
|
|
@@ -267,31 +278,11 @@ function parsePax(buffer) {
|
|
|
267
278
|
const [key, value] = decoder$1.decode(buffer.subarray(spaceIndex + 1, recordEnd - 1)).split("=", 2);
|
|
268
279
|
if (key && value !== void 0) {
|
|
269
280
|
pax[key] = value;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
overrides.linkname = value;
|
|
276
|
-
break;
|
|
277
|
-
case "size":
|
|
278
|
-
overrides.size = parseInt(value, 10);
|
|
279
|
-
break;
|
|
280
|
-
case "mtime":
|
|
281
|
-
overrides.mtime = parseFloat(value);
|
|
282
|
-
break;
|
|
283
|
-
case "uid":
|
|
284
|
-
overrides.uid = parseInt(value, 10);
|
|
285
|
-
break;
|
|
286
|
-
case "gid":
|
|
287
|
-
overrides.gid = parseInt(value, 10);
|
|
288
|
-
break;
|
|
289
|
-
case "uname":
|
|
290
|
-
overrides.uname = value;
|
|
291
|
-
break;
|
|
292
|
-
case "gname":
|
|
293
|
-
overrides.gname = value;
|
|
294
|
-
break;
|
|
281
|
+
const mapping = PAX_MAPPING[key];
|
|
282
|
+
if (mapping) {
|
|
283
|
+
const [targetKey, parser] = mapping;
|
|
284
|
+
const parsedValue = parser(value);
|
|
285
|
+
if (typeof parsedValue === "string" || !Number.isNaN(parsedValue)) overrides[targetKey] = parsedValue;
|
|
295
286
|
}
|
|
296
287
|
}
|
|
297
288
|
offset = recordEnd;
|
package/dist/web/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DecoderOptions,
|
|
1
|
+
import { DecoderOptions, TarEntryData, TarHeader, UnpackOptions } from "../types-Dc3p5B3s.js";
|
|
2
2
|
|
|
3
3
|
//#region src/web/compression.d.ts
|
|
4
4
|
|
|
@@ -72,6 +72,32 @@ declare function createGzipEncoder(): ReadableWritablePair<Uint8Array, Uint8Arra
|
|
|
72
72
|
*/
|
|
73
73
|
declare function createGzipDecoder(): ReadableWritablePair<Uint8Array, Uint8Array>;
|
|
74
74
|
//#endregion
|
|
75
|
+
//#region src/web/types.d.ts
|
|
76
|
+
/**
|
|
77
|
+
* Represents a complete entry to be packed into a tar archive.
|
|
78
|
+
*
|
|
79
|
+
* Combines header metadata with optional body data. Used as input to {@link packTar}
|
|
80
|
+
* and the controller returned by {@link createTarPacker}.
|
|
81
|
+
*/
|
|
82
|
+
interface TarEntry {
|
|
83
|
+
header: TarHeader;
|
|
84
|
+
body?: TarEntryData | ReadableStream<Uint8Array>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Represents an entry parsed from a tar archive stream.
|
|
88
|
+
*/
|
|
89
|
+
interface ParsedTarEntry {
|
|
90
|
+
header: TarHeader;
|
|
91
|
+
body: ReadableStream<Uint8Array>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Represents an extracted entry with fully buffered content.
|
|
95
|
+
*/
|
|
96
|
+
interface ParsedTarEntryWithData {
|
|
97
|
+
header: TarHeader;
|
|
98
|
+
data: Uint8Array;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
75
101
|
//#region src/web/helpers.d.ts
|
|
76
102
|
/**
|
|
77
103
|
* Packs an array of tar entries into a single `Uint8Array` buffer.
|
package/dist/web/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTarPacker as createTarPacker$1, createTarUnpacker, normalizeBody, streamToBuffer, transformHeader } from "../unpacker-
|
|
1
|
+
import { createTarPacker as createTarPacker$1, createTarUnpacker, normalizeBody, streamToBuffer, transformHeader } from "../unpacker-yB6Ahxxk.js";
|
|
2
2
|
|
|
3
3
|
//#region src/web/compression.ts
|
|
4
4
|
function createGzipEncoder() {
|