feat: init

This commit is contained in:
2026-02-13 22:02:30 +01:00
commit 8f9ff830fb
16711 changed files with 3307340 additions and 0 deletions

21
node_modules/nanotar/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

193
node_modules/nanotar/README.md generated vendored Normal file
View File

@@ -0,0 +1,193 @@
# 📼 nanotar
[![npm version][npm-version-src]][npm-version-href]
[![bundle][bundle-src]][bundle-href]
<!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] -->
<!-- [![Codecov][codecov-src]][codecov-href] -->
Tiny and fast [tar](<https://en.wikipedia.org/wiki/Tar_(computing)>) utils for any JavaScript runtime!
🌳 Tiny (~1KB minified + gzipped with all utils) and tree-shakable!
✨ Written with modern TypeScript and ESM format
✅ Works in any JavaScript runtime Node.js (18+), Bun, Deno, Browsers, and Edge Workers
🌐 Web Standard Compatible
🗜️ Built-in compression and decompression support
## Installation
Install package:
```sh
# npm
npm install nanotar
# yarn
yarn add nanotar
# pnpm
pnpm install nanotar
# bun
bun install nanotar
```
Import:
```js
// ESM
import {
createTar,
createTarGzip,
createTarGzipStream,
parseTar,
parseTarGzip,
} from "nanotar";
// CommonJS
const { createTar } = require("nanotar");
```
## Creating a tar archive
Easily create a new tar archive using the `createTar` utility.
The first argument is an array of files to archive:
- `name` field is required and you can use `/` to specify files within sub-directories.
- `data` field is optional for directories and can be either a [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) or [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array).
- `attrs` field is optional for file attributes.
The second argument is for archive options. You can use `attrs` to set default attributes for all files (can still be overridden per file).
Possible attributes are:
- `mtime`: Last modification time. The default is `Date.now()`
- `uid`: Owner user id. The default is `1000`
- `gid`: Owner group id. The default is `1000`
- `user`: Owner user name. The default is `""`
- `group`: Owner user group. The default is `""`
- `mode`: file mode (permissions). Default is `664` (`-rw-rw-r--`) for files and `775` (`-rwxrwxr-x`) for directories
**Example:**
```ts
import { createTar } from "nanotar";
const data = createTar(
[
{ name: "README.md", data: "# Hello World!" },
{ name: "test", attrs: { mode: "777", mtime: 0 } },
{ name: "src/index.js", data: "console.log('wow!')" },
],
{ attrs: { user: "js", group: "js" } },
);
// Data is a Uint8Array view you can send or write to a file
```
### Compression
You can optionally use `createTarGzip` or `createTarGzipStream` to create a compressed tar data stream (returned value is a [`Promise<Uint8Array>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) or [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) piped to [`CompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream))
```js
import { createTarGzip, createTarGzipStream } from "nanotar";
createTarGzip([]); // Promise<Uint8Array>
createTarGzipStream([]); // ReadableStream
```
## Parsing a tar archive
Easily parse a tar archive using `parseTar` utility.
**Example:**
```ts
import { parseTar } from "nanotar";
// Read tar data from file or other sources into an ArrayBuffer or Uint8Array
const files = parseTar(data);
/**
[
{
"type": "file",
"name": "hello.txt",
"size": 12,
"data": Uint8Array [ ... ],
"text": "Hello World!",
"attrs": {
"gid": 1750,
"group": "",
"mode": "0000664",
"mtime": 1702076997,
"uid": 1750,
"user": "root",
},
},
...
]
*/
```
Parsed files array has two additional properties: `size` file size and `text`, a lazy getter that decodes `data` view as a string.
You can filter iterms to read using `filter` option:
```ts
const files = parseTar(data, {
filter: (file) => file.name.starsWith("dir/"),
});
```
Additionally, you can use `metaOnly` option to skip reading file data and listing purposes:
```ts
const fileMetas = parseTar(data, {
metaOnly: true,
});
```
### Decompression
If input is compressed, you can use `parseTarGzip` utility instead to parse it (it used [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream) internally and return a `Promise<Uint8Array>` value)
```js
import { parseTarGzip } from "nanotar";
parseTarGzip(data); // Promise<Uint8Array>
```
## Development
- Clone this repository
- Install the latest LTS version of [Node.js](https://nodejs.org/en/)
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`
## License
Made with 💛
Inspired by [ankitrohatgi/tarballjs](https://github.com/ankitrohatgi/tarballjs)
Published under the [MIT License](./LICENSE).
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/nanotar
[npm-downloads-src]: https://img.shields.io/npm/dm/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/nanotar
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/nanotar/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/nanotar
[bundle-src]: https://img.shields.io/bundlephobia/minzip/nanotar?style=flat&colorA=18181B&colorB=F0DB4F
[bundle-href]: https://bundlephobia.com/result?p=nanotar

229
node_modules/nanotar/dist/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,229 @@
'use strict';
const TAR_TYPE_FILE = 0;
const TAR_TYPE_DIR = 5;
function parseTar(data, opts) {
const buffer = data.buffer || data;
const files = [];
let offset = 0;
while (offset < buffer.byteLength - 512) {
let name = _readString(buffer, offset, 100);
if (name.length === 0) {
break;
}
const mode = _readString(buffer, offset + 100, 8).trim();
const uid = Number.parseInt(_readString(buffer, offset + 108, 8));
const gid = Number.parseInt(_readString(buffer, offset + 116, 8));
const size = _readNumber(buffer, offset + 124, 12);
const seek = 512 + 512 * Math.trunc(size / 512) + (size % 512 ? 512 : 0);
const mtime = _readNumber(buffer, offset + 136, 12);
const _type = _readNumber(buffer, offset + 156, 1);
const type = _type === TAR_TYPE_FILE ? "file" : _type === TAR_TYPE_DIR ? "directory" : _type;
const user = _readString(buffer, offset + 265, 32);
const group = _readString(buffer, offset + 297, 32);
name = _sanitizePath(name);
const meta = {
name,
type,
size,
attrs: {
mode,
uid,
gid,
mtime,
user,
group
}
};
if (opts?.filter && !opts.filter(meta)) {
offset += seek;
continue;
}
if (opts?.metaOnly) {
files.push(meta);
offset += seek;
continue;
}
const data2 = _type === TAR_TYPE_DIR ? undefined : new Uint8Array(buffer, offset + 512, size);
files.push({
...meta,
data: data2,
get text() {
return new TextDecoder().decode(this.data);
}
});
offset += seek;
}
return files;
}
async function parseTarGzip(data, opts = {}) {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array(data));
controller.close();
}
}).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
const decompressedData = await new Response(stream).arrayBuffer();
return parseTar(decompressedData, opts);
}
function _sanitizePath(path) {
let normalized = path.replace(/\\/g, "/");
normalized = normalized.replace(/^[a-zA-Z]:\//, "");
normalized = normalized.replace(/^\/+/, "");
const hasLeadingDotSlash = normalized.startsWith("./");
const parts = normalized.split("/");
const resolved = [];
for (const part of parts) {
if (part === "..") {
resolved.pop();
} else if (part !== "." && part !== "") {
resolved.push(part);
}
}
let result = resolved.join("/");
if (hasLeadingDotSlash && !result.startsWith("./")) {
result = "./" + result;
}
if (path.endsWith("/") && !result.endsWith("/")) {
result += "/";
}
return result;
}
function _readString(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
const i = view.indexOf(0);
const td = new TextDecoder();
return td.decode(i === -1 ? view : view.slice(0, i));
}
function _readNumber(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
let str = "";
for (let i = 0; i < size; i++) {
str += String.fromCodePoint(view[i]);
}
return Number.parseInt(str, 8);
}
function createTar(files, opts = {}) {
const _files = files.map((file) => {
const data = _normalizeData(file.data);
return {
...file,
data,
size: data?.length || 0
};
});
let tarDataSize = 0;
for (let i = 0; i < files.length; i++) {
const size = _files[i].data?.length ?? 0;
tarDataSize += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
tarDataSize += 512;
}
}
let bufSize = 10240 * Math.trunc(tarDataSize / 10240);
if (tarDataSize % 10240) {
bufSize += 10240;
}
const buffer = new ArrayBuffer(bufSize);
let offset = 0;
for (const file of _files) {
const isDir = !file.data;
_writeString(buffer, file.name, offset, 100);
const mode = file.attrs?.mode ?? opts.attrs?.mode ?? (isDir ? "775" : "664");
_writeString(buffer, _leftPad(mode, 7), offset + 100, 8);
const uid = file.attrs?.uid ?? opts.attrs?.uid ?? 1e3;
_writeString(buffer, _leftPad(uid.toString(8), 7), offset + 108, 8);
const gid = file.attrs?.gid ?? opts.attrs?.gid ?? 1e3;
_writeString(buffer, _leftPad(gid.toString(8), 7), offset + 116, 8);
_writeString(buffer, _leftPad(file.size.toString(8), 11), offset + 124, 12);
const mtime = file.attrs?.mtime ?? opts.attrs?.mtime ?? Date.now();
_writeString(
buffer,
_leftPad(Math.trunc(mtime / 1e3).toString(8), 11),
offset + 136,
12
);
const type = isDir ? "5" : "0";
_writeString(buffer, type, offset + 156, 1);
_writeString(
buffer,
"ustar",
offset + 257,
6
/* magic string */
);
_writeString(
buffer,
"00",
offset + 263,
2
/* magic version */
);
const user = file.attrs?.user ?? opts.attrs?.user ?? "";
_writeString(buffer, user, offset + 265, 32);
const group = file.attrs?.group ?? opts.attrs?.group ?? "";
_writeString(buffer, group, offset + 297, 32);
_writeString(buffer, " ", offset + 148, 8);
const header = new Uint8Array(buffer, offset, 512);
let chksum = 0;
for (let i = 0; i < 512; i++) {
chksum += header[i];
}
_writeString(buffer, chksum.toString(8), offset + 148, 8);
if (!isDir) {
const destArray = new Uint8Array(buffer, offset + 512, file.size);
for (let byteIdx = 0; byteIdx < file.size; byteIdx++) {
destArray[byteIdx] = file.data[byteIdx];
}
offset += 512 * Math.trunc(file.size / 512);
if (file.size % 512) {
offset += 512;
}
}
offset += 512;
}
return new Uint8Array(buffer);
}
function createTarGzipStream(files, opts = {}) {
const buffer = createTar(files, opts);
return new ReadableStream({
start(controller) {
controller.enqueue(buffer);
controller.close();
}
}).pipeThrough(new CompressionStream(opts.compression ?? "gzip"));
}
async function createTarGzip(files, opts = {}) {
const data = await new Response(createTarGzipStream(files, opts)).arrayBuffer().then((buffer) => new Uint8Array(buffer));
return data;
}
function _writeString(buffer, str, offset, size) {
const strView = new Uint8Array(buffer, offset, size);
const te = new TextEncoder();
const written = te.encodeInto(str, strView).written;
for (let i = written; i < size; i++) {
strView[i] = 0;
}
}
function _leftPad(input, targetLength) {
return String(input).padStart(targetLength, "0");
}
function _normalizeData(data) {
if (data === null || data === undefined) {
return undefined;
}
if (typeof data === "string") {
return new TextEncoder().encode(data);
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
return data;
}
exports.createTar = createTar;
exports.createTarGzip = createTarGzip;
exports.createTarGzipStream = createTarGzipStream;
exports.parseTar = parseTar;
exports.parseTarGzip = parseTarGzip;

133
node_modules/nanotar/dist/index.d.cts generated vendored Normal file
View File

@@ -0,0 +1,133 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* The data associated with the file. This field is usually omitted for directories.
* @optional
*/
data?: DataT;
/**
* The attributes of the file. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
/**
* The type of file system element. It can be `"file"`, `"directory"` or an operating system specific numeric code.
*/
type: "file" | "directory" | number;
/**
* The size of the file in bytes.
*/
size: number;
/**
* The textual representation of the file data. This property is read-only.
*/
readonly text: string;
}
type ParsedTarFileItemMeta = Omit<ParsedTarFileItem, "data" | "text">;
interface TarFileAttrs {
/**
* File mode in octal (e.g., `664`) represents read, write, and execute permissions for the owner, group, and others.
*/
mode?: string;
/**
* The user ID associated with the file.
* @default 1000
*/
uid?: number;
/**
* The group ID associated with the file.
* @default 1000
*/
gid?: number;
/**
* The modification time of the file, expressed as the number of milliseconds since the UNIX epoch.
* @default Date.now()
*/
mtime?: number;
/**
* The name of the user who owns the file.
* @default ""
*/
user?: string;
/**
* The name of the group that owns the file.
* @default ""
*/
group?: string;
}
interface ParseTarOptions {
/**
* A filter function that determines whether a file entry should be skipped or not.
*/
filter?: (file: ParsedTarFileItemMeta) => boolean;
/**
* If `true`, only the metadata of the files will be parsed, and the file data will be omitted for listing purposes.
*/
metaOnly?: boolean;
}
/**
* Parses a TAR file from a binary buffer and returns an array of {@link TarFileItem} objects.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the TAR file.
* @returns {ParsedTarFileItem[]} An array of file items contained in the TAR file.
*/
declare function parseTar<_ = never, _Opts extends ParseTarOptions = ParseTarOptions, _ItemType extends ParsedTarFileItem | ParsedTarFileItemMeta = _Opts["metaOnly"] extends true ? ParsedTarFileItemMeta : ParsedTarFileItem>(data: ArrayBuffer | Uint8Array, opts?: _Opts): _ItemType[];
/**
* Decompresses a gzipped TAR file and parses it to produce an array of file elements.
* This function handles the decompression of the gzip format before parsing the contents of the TAR.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the gzipped TAR file.
* @param {object} opts - Decompression options.
* @param {CompressionFormat} [opts.compression="gzip"] - Specifies the compression format to use, defaults to `"gzip"`.
* @returns {Promise<TarFileItem[]>} A promise that resolves to an array of file items as described by {@link TarFileItem}.
*/
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: ParseTarOptions & {
compression?: CompressionFormat;
}): Promise<ParsedTarFileItem[]>;
interface CreateTarOptions {
/**
* Default attributes applied to all file unless overridden. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
/**
* Creates a TAR file from a list of file inputs and options, returning the TAR file as an `Uint8Array`.
* This function takes care of normalising the file data, setting default attributes and calculating the TAR structure.
*
* @param {TarFileInput[]} files - An array of files to include in the TAR archive. Each file can contain different data types. See {@link TarFileInput}.
* @param {CreateTarOptions} opts - File creation configuration options, including default file attributes. See {@link CreateTarOptions}.
* @returns {Uint8Array} The TAR file encoded as an `Uint8Array`.
*/
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
/**
* Creates a gzipped TAR file stream from an array of file inputs, using optional compression settings.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive. See {@link TarFileInput}.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression. See {@link CreateTarOptions}.
* @returns {ReadableStream} A stream of the gzipped TAR file data.
*/
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
/**
* Asynchronously creates a gzipped TAR file from an array of file inputs.
* This function is suitable for scenarios where a complete gzipped TAR file is required as a single `Uint8` array.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression.
* @returns {Promise<Uint8Array>} A promise that resolves to the gzipped TAR file as an Uint8Array.
*/
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParseTarOptions, type ParsedTarFileItem, type ParsedTarFileItemMeta, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };

133
node_modules/nanotar/dist/index.d.mts generated vendored Normal file
View File

@@ -0,0 +1,133 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* The data associated with the file. This field is usually omitted for directories.
* @optional
*/
data?: DataT;
/**
* The attributes of the file. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
/**
* The type of file system element. It can be `"file"`, `"directory"` or an operating system specific numeric code.
*/
type: "file" | "directory" | number;
/**
* The size of the file in bytes.
*/
size: number;
/**
* The textual representation of the file data. This property is read-only.
*/
readonly text: string;
}
type ParsedTarFileItemMeta = Omit<ParsedTarFileItem, "data" | "text">;
interface TarFileAttrs {
/**
* File mode in octal (e.g., `664`) represents read, write, and execute permissions for the owner, group, and others.
*/
mode?: string;
/**
* The user ID associated with the file.
* @default 1000
*/
uid?: number;
/**
* The group ID associated with the file.
* @default 1000
*/
gid?: number;
/**
* The modification time of the file, expressed as the number of milliseconds since the UNIX epoch.
* @default Date.now()
*/
mtime?: number;
/**
* The name of the user who owns the file.
* @default ""
*/
user?: string;
/**
* The name of the group that owns the file.
* @default ""
*/
group?: string;
}
interface ParseTarOptions {
/**
* A filter function that determines whether a file entry should be skipped or not.
*/
filter?: (file: ParsedTarFileItemMeta) => boolean;
/**
* If `true`, only the metadata of the files will be parsed, and the file data will be omitted for listing purposes.
*/
metaOnly?: boolean;
}
/**
* Parses a TAR file from a binary buffer and returns an array of {@link TarFileItem} objects.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the TAR file.
* @returns {ParsedTarFileItem[]} An array of file items contained in the TAR file.
*/
declare function parseTar<_ = never, _Opts extends ParseTarOptions = ParseTarOptions, _ItemType extends ParsedTarFileItem | ParsedTarFileItemMeta = _Opts["metaOnly"] extends true ? ParsedTarFileItemMeta : ParsedTarFileItem>(data: ArrayBuffer | Uint8Array, opts?: _Opts): _ItemType[];
/**
* Decompresses a gzipped TAR file and parses it to produce an array of file elements.
* This function handles the decompression of the gzip format before parsing the contents of the TAR.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the gzipped TAR file.
* @param {object} opts - Decompression options.
* @param {CompressionFormat} [opts.compression="gzip"] - Specifies the compression format to use, defaults to `"gzip"`.
* @returns {Promise<TarFileItem[]>} A promise that resolves to an array of file items as described by {@link TarFileItem}.
*/
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: ParseTarOptions & {
compression?: CompressionFormat;
}): Promise<ParsedTarFileItem[]>;
interface CreateTarOptions {
/**
* Default attributes applied to all file unless overridden. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
/**
* Creates a TAR file from a list of file inputs and options, returning the TAR file as an `Uint8Array`.
* This function takes care of normalising the file data, setting default attributes and calculating the TAR structure.
*
* @param {TarFileInput[]} files - An array of files to include in the TAR archive. Each file can contain different data types. See {@link TarFileInput}.
* @param {CreateTarOptions} opts - File creation configuration options, including default file attributes. See {@link CreateTarOptions}.
* @returns {Uint8Array} The TAR file encoded as an `Uint8Array`.
*/
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
/**
* Creates a gzipped TAR file stream from an array of file inputs, using optional compression settings.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive. See {@link TarFileInput}.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression. See {@link CreateTarOptions}.
* @returns {ReadableStream} A stream of the gzipped TAR file data.
*/
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
/**
* Asynchronously creates a gzipped TAR file from an array of file inputs.
* This function is suitable for scenarios where a complete gzipped TAR file is required as a single `Uint8` array.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression.
* @returns {Promise<Uint8Array>} A promise that resolves to the gzipped TAR file as an Uint8Array.
*/
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParseTarOptions, type ParsedTarFileItem, type ParsedTarFileItemMeta, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };

133
node_modules/nanotar/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,133 @@
type TarFileItem<DataT = Uint8Array> = {
/**
* File name
*/
name: string;
/**
* The data associated with the file. This field is usually omitted for directories.
* @optional
*/
data?: DataT;
/**
* The attributes of the file. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
};
interface ParsedTarFileItem extends TarFileItem {
/**
* The type of file system element. It can be `"file"`, `"directory"` or an operating system specific numeric code.
*/
type: "file" | "directory" | number;
/**
* The size of the file in bytes.
*/
size: number;
/**
* The textual representation of the file data. This property is read-only.
*/
readonly text: string;
}
type ParsedTarFileItemMeta = Omit<ParsedTarFileItem, "data" | "text">;
interface TarFileAttrs {
/**
* File mode in octal (e.g., `664`) represents read, write, and execute permissions for the owner, group, and others.
*/
mode?: string;
/**
* The user ID associated with the file.
* @default 1000
*/
uid?: number;
/**
* The group ID associated with the file.
* @default 1000
*/
gid?: number;
/**
* The modification time of the file, expressed as the number of milliseconds since the UNIX epoch.
* @default Date.now()
*/
mtime?: number;
/**
* The name of the user who owns the file.
* @default ""
*/
user?: string;
/**
* The name of the group that owns the file.
* @default ""
*/
group?: string;
}
interface ParseTarOptions {
/**
* A filter function that determines whether a file entry should be skipped or not.
*/
filter?: (file: ParsedTarFileItemMeta) => boolean;
/**
* If `true`, only the metadata of the files will be parsed, and the file data will be omitted for listing purposes.
*/
metaOnly?: boolean;
}
/**
* Parses a TAR file from a binary buffer and returns an array of {@link TarFileItem} objects.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the TAR file.
* @returns {ParsedTarFileItem[]} An array of file items contained in the TAR file.
*/
declare function parseTar<_ = never, _Opts extends ParseTarOptions = ParseTarOptions, _ItemType extends ParsedTarFileItem | ParsedTarFileItemMeta = _Opts["metaOnly"] extends true ? ParsedTarFileItemMeta : ParsedTarFileItem>(data: ArrayBuffer | Uint8Array, opts?: _Opts): _ItemType[];
/**
* Decompresses a gzipped TAR file and parses it to produce an array of file elements.
* This function handles the decompression of the gzip format before parsing the contents of the TAR.
*
* @param {ArrayBuffer | Uint8Array} data - The binary data of the gzipped TAR file.
* @param {object} opts - Decompression options.
* @param {CompressionFormat} [opts.compression="gzip"] - Specifies the compression format to use, defaults to `"gzip"`.
* @returns {Promise<TarFileItem[]>} A promise that resolves to an array of file items as described by {@link TarFileItem}.
*/
declare function parseTarGzip(data: ArrayBuffer | Uint8Array, opts?: ParseTarOptions & {
compression?: CompressionFormat;
}): Promise<ParsedTarFileItem[]>;
interface CreateTarOptions {
/**
* Default attributes applied to all file unless overridden. See {@link TarFileAttrs}.
* @optional
*/
attrs?: TarFileAttrs;
}
type TarFileInput = TarFileItem<string | Uint8Array | ArrayBuffer>;
/**
* Creates a TAR file from a list of file inputs and options, returning the TAR file as an `Uint8Array`.
* This function takes care of normalising the file data, setting default attributes and calculating the TAR structure.
*
* @param {TarFileInput[]} files - An array of files to include in the TAR archive. Each file can contain different data types. See {@link TarFileInput}.
* @param {CreateTarOptions} opts - File creation configuration options, including default file attributes. See {@link CreateTarOptions}.
* @returns {Uint8Array} The TAR file encoded as an `Uint8Array`.
*/
declare function createTar(files: TarFileInput[], opts?: CreateTarOptions): Uint8Array;
/**
* Creates a gzipped TAR file stream from an array of file inputs, using optional compression settings.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive. See {@link TarFileInput}.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression. See {@link CreateTarOptions}.
* @returns {ReadableStream} A stream of the gzipped TAR file data.
*/
declare function createTarGzipStream(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): ReadableStream;
/**
* Asynchronously creates a gzipped TAR file from an array of file inputs.
* This function is suitable for scenarios where a complete gzipped TAR file is required as a single `Uint8` array.
*
* @param {TarFileInput[]} files - The files to include in the gzipped TAR archive.
* @param {CreateTarOptions & { Compression? CompressionFormat }} opts - Options for TAR creation and gzip compression.
* @returns {Promise<Uint8Array>} A promise that resolves to the gzipped TAR file as an Uint8Array.
*/
declare function createTarGzip(files: TarFileInput[], opts?: CreateTarOptions & {
compression?: CompressionFormat;
}): Promise<Uint8Array>;
export { type CreateTarOptions, type ParseTarOptions, type ParsedTarFileItem, type ParsedTarFileItemMeta, type TarFileAttrs, type TarFileInput, type TarFileItem, createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };

223
node_modules/nanotar/dist/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,223 @@
const TAR_TYPE_FILE = 0;
const TAR_TYPE_DIR = 5;
function parseTar(data, opts) {
const buffer = data.buffer || data;
const files = [];
let offset = 0;
while (offset < buffer.byteLength - 512) {
let name = _readString(buffer, offset, 100);
if (name.length === 0) {
break;
}
const mode = _readString(buffer, offset + 100, 8).trim();
const uid = Number.parseInt(_readString(buffer, offset + 108, 8));
const gid = Number.parseInt(_readString(buffer, offset + 116, 8));
const size = _readNumber(buffer, offset + 124, 12);
const seek = 512 + 512 * Math.trunc(size / 512) + (size % 512 ? 512 : 0);
const mtime = _readNumber(buffer, offset + 136, 12);
const _type = _readNumber(buffer, offset + 156, 1);
const type = _type === TAR_TYPE_FILE ? "file" : _type === TAR_TYPE_DIR ? "directory" : _type;
const user = _readString(buffer, offset + 265, 32);
const group = _readString(buffer, offset + 297, 32);
name = _sanitizePath(name);
const meta = {
name,
type,
size,
attrs: {
mode,
uid,
gid,
mtime,
user,
group
}
};
if (opts?.filter && !opts.filter(meta)) {
offset += seek;
continue;
}
if (opts?.metaOnly) {
files.push(meta);
offset += seek;
continue;
}
const data2 = _type === TAR_TYPE_DIR ? undefined : new Uint8Array(buffer, offset + 512, size);
files.push({
...meta,
data: data2,
get text() {
return new TextDecoder().decode(this.data);
}
});
offset += seek;
}
return files;
}
async function parseTarGzip(data, opts = {}) {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array(data));
controller.close();
}
}).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
const decompressedData = await new Response(stream).arrayBuffer();
return parseTar(decompressedData, opts);
}
function _sanitizePath(path) {
let normalized = path.replace(/\\/g, "/");
normalized = normalized.replace(/^[a-zA-Z]:\//, "");
normalized = normalized.replace(/^\/+/, "");
const hasLeadingDotSlash = normalized.startsWith("./");
const parts = normalized.split("/");
const resolved = [];
for (const part of parts) {
if (part === "..") {
resolved.pop();
} else if (part !== "." && part !== "") {
resolved.push(part);
}
}
let result = resolved.join("/");
if (hasLeadingDotSlash && !result.startsWith("./")) {
result = "./" + result;
}
if (path.endsWith("/") && !result.endsWith("/")) {
result += "/";
}
return result;
}
function _readString(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
const i = view.indexOf(0);
const td = new TextDecoder();
return td.decode(i === -1 ? view : view.slice(0, i));
}
function _readNumber(buffer, offset, size) {
const view = new Uint8Array(buffer, offset, size);
let str = "";
for (let i = 0; i < size; i++) {
str += String.fromCodePoint(view[i]);
}
return Number.parseInt(str, 8);
}
function createTar(files, opts = {}) {
const _files = files.map((file) => {
const data = _normalizeData(file.data);
return {
...file,
data,
size: data?.length || 0
};
});
let tarDataSize = 0;
for (let i = 0; i < files.length; i++) {
const size = _files[i].data?.length ?? 0;
tarDataSize += 512 + 512 * Math.trunc(size / 512);
if (size % 512) {
tarDataSize += 512;
}
}
let bufSize = 10240 * Math.trunc(tarDataSize / 10240);
if (tarDataSize % 10240) {
bufSize += 10240;
}
const buffer = new ArrayBuffer(bufSize);
let offset = 0;
for (const file of _files) {
const isDir = !file.data;
_writeString(buffer, file.name, offset, 100);
const mode = file.attrs?.mode ?? opts.attrs?.mode ?? (isDir ? "775" : "664");
_writeString(buffer, _leftPad(mode, 7), offset + 100, 8);
const uid = file.attrs?.uid ?? opts.attrs?.uid ?? 1e3;
_writeString(buffer, _leftPad(uid.toString(8), 7), offset + 108, 8);
const gid = file.attrs?.gid ?? opts.attrs?.gid ?? 1e3;
_writeString(buffer, _leftPad(gid.toString(8), 7), offset + 116, 8);
_writeString(buffer, _leftPad(file.size.toString(8), 11), offset + 124, 12);
const mtime = file.attrs?.mtime ?? opts.attrs?.mtime ?? Date.now();
_writeString(
buffer,
_leftPad(Math.trunc(mtime / 1e3).toString(8), 11),
offset + 136,
12
);
const type = isDir ? "5" : "0";
_writeString(buffer, type, offset + 156, 1);
_writeString(
buffer,
"ustar",
offset + 257,
6
/* magic string */
);
_writeString(
buffer,
"00",
offset + 263,
2
/* magic version */
);
const user = file.attrs?.user ?? opts.attrs?.user ?? "";
_writeString(buffer, user, offset + 265, 32);
const group = file.attrs?.group ?? opts.attrs?.group ?? "";
_writeString(buffer, group, offset + 297, 32);
_writeString(buffer, " ", offset + 148, 8);
const header = new Uint8Array(buffer, offset, 512);
let chksum = 0;
for (let i = 0; i < 512; i++) {
chksum += header[i];
}
_writeString(buffer, chksum.toString(8), offset + 148, 8);
if (!isDir) {
const destArray = new Uint8Array(buffer, offset + 512, file.size);
for (let byteIdx = 0; byteIdx < file.size; byteIdx++) {
destArray[byteIdx] = file.data[byteIdx];
}
offset += 512 * Math.trunc(file.size / 512);
if (file.size % 512) {
offset += 512;
}
}
offset += 512;
}
return new Uint8Array(buffer);
}
function createTarGzipStream(files, opts = {}) {
const buffer = createTar(files, opts);
return new ReadableStream({
start(controller) {
controller.enqueue(buffer);
controller.close();
}
}).pipeThrough(new CompressionStream(opts.compression ?? "gzip"));
}
async function createTarGzip(files, opts = {}) {
const data = await new Response(createTarGzipStream(files, opts)).arrayBuffer().then((buffer) => new Uint8Array(buffer));
return data;
}
function _writeString(buffer, str, offset, size) {
const strView = new Uint8Array(buffer, offset, size);
const te = new TextEncoder();
const written = te.encodeInto(str, strView).written;
for (let i = written; i < size; i++) {
strView[i] = 0;
}
}
function _leftPad(input, targetLength) {
return String(input).padStart(targetLength, "0");
}
function _normalizeData(data) {
if (data === null || data === undefined) {
return undefined;
}
if (typeof data === "string") {
return new TextEncoder().encode(data);
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
return data;
}
export { createTar, createTarGzip, createTarGzipStream, parseTar, parseTarGzip };

51
node_modules/nanotar/package.json generated vendored Normal file
View File

@@ -0,0 +1,51 @@
{
"name": "nanotar",
"version": "0.2.1",
"description": "Tiny and fast Tar utils for any JavaScript runtime!",
"repository": "unjs/nanotar",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "vitest dev",
"play": "jiti playground",
"lint": "eslint --cache . && prettier -c src test",
"lint:fix": "eslint --cache . --fix && prettier -c src test -w",
"prepack": "pnpm run build",
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
"test:types": "tsc --noEmit --skipLibCheck"
},
"devDependencies": {
"@types/node": "^22.10.7",
"@vitest/coverage-v8": "^3.0.2",
"changelogen": "^0.5.7",
"eslint": "^9.18.0",
"eslint-config-unjs": "^0.4.2",
"jiti": "^2.4.2",
"prettier": "^3.4.2",
"typescript": "^5.7.3",
"unbuild": "^3.3.1",
"vitest": "^3.0.2"
},
"packageManager": "pnpm@9.15.4"
}