@publint/pack
Advanced tools
| import fs from 'node:fs/promises' | ||
| import path from 'node:path' | ||
| /** @type {import('../index.d.ts').getPackDirectory} */ | ||
| export async function getPackDirectory(dir, packageManager) { | ||
| if (packageManager === 'pnpm') { | ||
| // pnpm respects `publishConfig.directory` field in `package.json` | ||
| try { | ||
| const pkgJsonPath = path.resolve(dir, 'package.json') | ||
| const pkgJsonData = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8')) | ||
| if (pkgJsonData.publishConfig?.directory) { | ||
| return path.resolve(dir, pkgJsonData.publishConfig.directory) | ||
| } | ||
| } catch { | ||
| // Ignore errors in case `package.json` is malformed or anything | ||
| } | ||
| } | ||
| // All other package managers don't support changing the packed directory | ||
| return dir | ||
| } |
+1
-1
| MIT License | ||
| Copyright (c) 2025 Bjorn Lu and publint contributors | ||
| Copyright (c) 2026 Bjorn Lu and publint contributors | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
+3
-3
| { | ||
| "name": "@publint/pack", | ||
| "version": "0.1.2", | ||
| "version": "0.1.3", | ||
| "description": "Utilities for packing and unpacking npm packages", | ||
@@ -35,4 +35,4 @@ "type": "module", | ||
| "devDependencies": { | ||
| "fs-fixture": "^2.7.1", | ||
| "vitest": "^3.0.6" | ||
| "fs-fixture": "^2.11.0", | ||
| "vitest": "^4.0.17" | ||
| }, | ||
@@ -39,0 +39,0 @@ "scripts": { |
+18
-3
@@ -38,2 +38,4 @@ # @publint/pack | ||
| The relative file paths should be resolved via `getPackDirectory()` if a different packed directory was used. | ||
| > [!NOTE] | ||
@@ -58,2 +60,4 @@ > Compared to [`npm-packlist`](https://github.com/npm/npm-packlist), this API works at a higher level by invoking the package manager `pack` command to retrieve the list of files packed. While `npm-packlist` is abstracted away from `npm` to expose a more direct API, unfortunately not all package managers pack files the same way, e.g. the patterns in `"files"` may be interpreted differently. Plus, since `npm-packlist` v7, it requires `@npmcli/arborist` to be used together, which is a much larger dependency to include altogether. | ||
| Relative file paths in the output can be resolved via `getPackDirectory()` if a different packed directory was used. | ||
| > [!NOTE] | ||
@@ -70,2 +74,15 @@ > Does not work in pnpm <9.14.1 and bun as they don't support the `--json` flag. | ||
| ### `getPackDirectory()` | ||
| - **Type**: `(dir: string, packageManager?: PackageManager): Promise<string>` | ||
| Gets the directory that is being packed by the package manager. Usually this is the same as the input `dir`, but some package managers (like pnpm) allows changing the packed directory via the `publishConfig.directory` field in `package.json`. | ||
| ```js | ||
| import { getPackDirectory } from '@publint/pack' | ||
| const packDir = await getPackDirectory(process.cwd(), 'pnpm') | ||
| console.log(packDir) | ||
| // => '<cwd>/dist' (if "publishConfig.directory" is set to "dist" in package.json) | ||
| ``` | ||
| ### `unpack()` | ||
@@ -82,5 +99,3 @@ | ||
| const response = await fetch( | ||
| 'https://registry.npmjs.org/mylib/-/mylib-1.0.0.tgz', | ||
| ) | ||
| const response = await fetch('https://registry.npmjs.org/mylib/-/mylib-1.0.0.tgz') | ||
| if (!response.body) throw new Error('Failed to fetch tarball') | ||
@@ -87,0 +102,0 @@ |
@@ -9,7 +9,5 @@ import { | ||
| export async function unpack(tarball) { | ||
| const stream = | ||
| tarball instanceof ReadableStream | ||
| ? tarball | ||
| : arrayBufferToReadableStream(tarball) | ||
| const stream = tarball instanceof ReadableStream ? tarball : arrayBufferToReadableStream(tarball) | ||
| const buffer = await readableStreamToArrayBuffer( | ||
| // @ts-expect-error not dealing with this issue for now | ||
| stream.pipeThrough(new DecompressionStream('gzip')), | ||
@@ -16,0 +14,0 @@ ) |
@@ -13,2 +13,6 @@ export function pack() { | ||
| export function getPackDirectory() { | ||
| throw new Error('`getPackDirectory` is not supported in the browser') | ||
| } | ||
| export { unpack } from './browser/unpack.js' |
| export { pack } from './node/pack.js' | ||
| export { packAsList } from './node/pack-as-list.js' | ||
| export { packAsJson } from './node/pack-as-json.js' | ||
| export { getPackDirectory } from './node/get-pack-directory.js' | ||
| export { unpack } from './node/unpack.js' |
+20
-8
@@ -0,1 +1,3 @@ | ||
| export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun' | ||
| interface SharedPackOptions { | ||
@@ -7,3 +9,3 @@ /** | ||
| */ | ||
| packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun' | ||
| packageManager?: PackageManager | ||
| /** | ||
@@ -32,7 +34,7 @@ * Whether to ignore lifecycle scripts during packing, i.e. `prepare`, `prepack`, | ||
| * Packs the given directory and returns a list of relative file paths that were packed. | ||
| * | ||
| * The relative file paths should be resolved via `getPackDirectory()` if a different | ||
| * packed directory was used. | ||
| */ | ||
| export function packAsList( | ||
| dir: string, | ||
| opts?: PackAsListOptions, | ||
| ): Promise<string[]> | ||
| export function packAsList(dir: string, opts?: PackAsListOptions): Promise<string[]> | ||
@@ -44,2 +46,5 @@ export interface PackAsJsonOptions extends SharedPackOptions {} | ||
| * | ||
| * Relative file paths in the output can be resolved via `getPackDirectory()` if a | ||
| * different packed directory was used. | ||
| * | ||
| * NOTE: Does not work in pnpm <9.14.1 and bun as they don't support the `--json` flag. | ||
@@ -49,2 +54,11 @@ */ | ||
| /** | ||
| * Gets the directory that is being packed by the package manager. Usually this is | ||
| * the same as the input `dir`, but some package managers (like pnpm) allows changing | ||
| * the packed directory via the `publishConfig.directory` field in `package.json`. | ||
| * | ||
| * @param packageManager The package manager to use for packing. Defaults to 'npm'. | ||
| */ | ||
| export function getPackDirectory(dir: string, packageManager?: PackageManager): Promise<string> | ||
| export interface TarballFile { | ||
@@ -77,4 +91,2 @@ name: string | ||
| */ | ||
| export function unpack( | ||
| tarball: ArrayBuffer | ReadableStream<Uint8Array>, | ||
| ): Promise<UnpackResult> | ||
| export function unpack(tarball: ArrayBuffer | ReadableStream<Uint8Array>): Promise<UnpackResult> |
@@ -58,4 +58,5 @@ import fs from 'node:fs/promises' | ||
| try { | ||
| const nodeBuffer = await fs.readFile(tarballPath) | ||
| const buffer = /** @type {ArrayBuffer} */ ( | ||
| (await fs.readFile(tarballPath)).buffer | ||
| nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength) | ||
| ) | ||
@@ -62,0 +63,0 @@ const { files, rootDir } = await unpack(buffer) |
+1
-3
@@ -52,5 +52,3 @@ import cp from 'node:child_process' | ||
| const tarballFile = await fs.readdir(packDestination).then((files) => { | ||
| return files.find( | ||
| (file) => file.endsWith('.tgz') && output.stdout.includes(file), | ||
| ) | ||
| return files.find((file) => file.endsWith('.tgz') && output.stdout.includes(file)) | ||
| }) | ||
@@ -57,0 +55,0 @@ if (!tarballFile) { |
@@ -12,2 +12,3 @@ import util from 'node:util' | ||
| buffer = await readableStreamToArrayBuffer( | ||
| // @ts-expect-error not dealing with this issue for now | ||
| tarball.pipeThrough(new DecompressionStream('gzip')), | ||
@@ -17,3 +18,5 @@ ) | ||
| const nodeBuffer = await util.promisify(zlib.gunzip)(tarball) | ||
| buffer = /** @type {ArrayBuffer} */ (nodeBuffer.buffer) | ||
| buffer = /** @type {ArrayBuffer} */ ( | ||
| nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength) | ||
| ) | ||
| } | ||
@@ -20,0 +23,0 @@ const files = parseTar(buffer) |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
22571
13.81%15
7.14%462
7.69%107
16.3%5
25%