@gyng/remote-zip 1.0.0 → 1.0.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.
@@ -0,0 +1,39 @@
1
+ /** Incremental CRC-32, for verifying decompressed output (including streaming). */
2
+ export declare class Crc32 {
3
+ private state;
4
+ update(bytes: Uint8Array): void;
5
+ digest(): number;
6
+ }
7
+ /** Compute the CRC-32 of `bytes` (the ZIP/IEEE variant). */
8
+ export declare const crc32: (bytes: Uint8Array) => number;
9
+ /** Test seam: raw AES block encryption (FIPS-197), used to validate the core. */
10
+ export declare const aesEncryptBlockRaw: (key: Uint8Array, block: Uint8Array) => Uint8Array;
11
+ /**
12
+ * Decrypt traditional-ZipCrypto bytes (the 12-byte encryption header is consumed
13
+ * and stripped). Returns the compressed plaintext and the header's check byte.
14
+ */
15
+ export declare const decryptZipCrypto: (data: Uint8Array, password: Uint8Array) => {
16
+ plaintext: Uint8Array;
17
+ checkByte: number;
18
+ };
19
+ /** Encrypt for ZipCrypto (used by tests to build fixtures). */
20
+ export declare const encryptZipCrypto: (plaintext: Uint8Array, password: Uint8Array, header: Uint8Array) => Uint8Array;
21
+ /** Parse the WinZip AES extra field (id 0x9901): strength + actual method. */
22
+ export declare const parseAesExtra: (extra: ArrayBuffer) => {
23
+ strength: number;
24
+ actualMethod: number;
25
+ } | null;
26
+ /** Reasons a WinZip AES decryption can fail (mapped to RemoteZipError codes). */
27
+ export type AesDecryptError = "WRONG_PASSWORD" | "BAD_MAC" | "UNSUPPORTED";
28
+ export declare class CryptoError extends Error {
29
+ reason: AesDecryptError;
30
+ constructor(reason: AesDecryptError);
31
+ }
32
+ /**
33
+ * Decrypt a WinZip AES entry payload (salt || pwVerify || ciphertext || mac).
34
+ * Verifies the password-check bytes and the authentication code, then returns
35
+ * the still-compressed plaintext.
36
+ */
37
+ export declare const decryptWinzipAes: (data: Uint8Array, password: Uint8Array, strength: number) => Promise<Uint8Array>;
38
+ /** Encrypt a WinZip AES payload (used by tests to build fixtures). */
39
+ export declare const encryptWinzipAes: (plaintext: Uint8Array, password: Uint8Array, strength: number, salt: Uint8Array) => Promise<Uint8Array>;
@@ -1,6 +1,6 @@
1
- export { crc32 } from "./crypto";
1
+ export { crc32 } from "./crypto.mjs";
2
2
  /** Machine-readable discriminant for {@link RemoteZipError}. */
3
- export type RemoteZipErrorCode = "UNKNOWN" | "CONTENT_LENGTH_MISSING" | "HTTP_ERROR" | "EOCD_NOT_FOUND" | "UNSUPPORTED_ZIP64" | "UNSUPPORTED_ENCRYPTION" | "FILE_NOT_FOUND" | "LOCAL_HEADER_PARSE_FAILED" | "CENTRAL_DIRECTORY_OUT_OF_BOUNDS" | "DECOMPRESSION_LIMIT_EXCEEDED" | "CRC_MISMATCH" | "WRONG_PASSWORD" | "DECRYPTION_FAILED";
3
+ export type RemoteZipErrorCode = "UNKNOWN" | "CONTENT_LENGTH_MISSING" | "INVALID_CONTENT_LENGTH" | "HTTP_ERROR" | "RANGE_NOT_SUPPORTED" | "RANGE_RESPONSE_MISMATCH" | "EOCD_NOT_FOUND" | "UNSUPPORTED_ZIP64" | "UNSUPPORTED_ENCRYPTION" | "FILE_NOT_FOUND" | "LOCAL_HEADER_PARSE_FAILED" | "CENTRAL_DIRECTORY_OUT_OF_BOUNDS" | "INVALID_ARCHIVE" | "TRUNCATED_ENTRY" | "UNSUPPORTED_COMPRESSION" | "UNSUPPORTED_MULTI_DISK" | "DECOMPRESSION_LIMIT_EXCEEDED" | "CRC_MISMATCH" | "WRONG_PASSWORD" | "DECRYPTION_FAILED";
4
4
  export declare class RemoteZipError extends Error {
5
5
  /** Machine-readable error code, for programmatic handling without matching on `message`. */
6
6
  code: RemoteZipErrorCode;
@@ -273,7 +273,7 @@ export declare class RemoteZip {
273
273
  /** Passed to fetch when performing a HTTP GET request for the file */
274
274
  method: string;
275
275
  /** Passed to fetch when performing a HTTP GET request for the file. */
276
- credentials: "include" | "omit" | "same-origin";
276
+ credentials?: "include" | "omit" | "same-origin";
277
277
  } & Pick<RemoteZipRequestOptions, "redirect" | "signal" | "timeoutMs" | "requestInit">);
278
278
  /** Build a fetch RequestInit from this instance's network options. */
279
279
  private requestInitFor;
@@ -305,7 +305,7 @@ export declare class RemoteZip {
305
305
  * @param options.verifyCrc If set, verify the decompressed output against the
306
306
  * entry's CRC-32 and throw a {@link RemoteZipError} (`CRC_MISMATCH`) on mismatch.
307
307
  * @returns Inflated (uncompressed) bytes of the requested file
308
- * @throws [RemoteZipError](RemoteZipError) if it fails to parse, fetch, or exceeds limits
308
+ * @throws {@link RemoteZipError} if it fails to parse, fetch, or exceeds limits
309
309
  */
310
310
  fetch(path: string, additionalHeaders?: Headers, options?: EntryDecodeOptions): Promise<Uint8Array>;
311
311
  /**
@@ -333,6 +333,7 @@ export declare class RemoteZip {
333
333
  * {@link fetchStream}.
334
334
  */
335
335
  private fetchEntryResponse;
336
+ private fetchRange;
336
337
  }
337
338
  /**
338
339
  * Network options shared by every request a {@link RemoteZip} / {@link RemoteZipPointer}
@@ -403,8 +404,8 @@ export declare class RemoteZipPointer {
403
404
  /**
404
405
  * Gets metadata about the ZIP file and constructs an initialised `RemoteZip`.
405
406
  *
406
- * @returns An initialised [RemoteZip](RemoteZip)
407
- * @throws [RemoteZipError](RemoteZipError) if it fails to parse or fetch
407
+ * @returns An initialised {@link RemoteZip}
408
+ * @throws {@link RemoteZipError} if it fails to parse or fetch
408
409
  */
409
410
  populate(): Promise<RemoteZip>;
410
411
  private fetchEndOfCentralDirectory;
@@ -428,13 +429,18 @@ export declare const parseZipDatetime: (zipDate: number, zipTime: number) => str
428
429
  export declare const isZip64: (eocd: EndOfCentralDirectory) => boolean;
429
430
  /** Effective central-directory location from a ZIP64 End Of Central Directory record. */
430
431
  export interface Zip64EndOfCentralDirectory {
432
+ diskNumber: number;
433
+ cdDisk: number;
434
+ centralDirectoryDiskRecordCount: number;
431
435
  centralDirectoryRecordCount: number;
432
436
  centralDirectoryByteSize: number;
433
437
  centralDirectoryByteOffset: number;
434
438
  }
435
439
  /** Locate the ZIP64 EOCD locator in a tail buffer and return the ZIP64 EOCD offset. */
436
440
  export declare const parseZip64EOCDLocator: (buffer: ArrayBuffer) => {
441
+ diskWithZip64EOCD: number;
437
442
  zip64EOCDOffset: number;
443
+ totalDisks: number;
438
444
  } | null;
439
445
  /** Parse a ZIP64 End Of Central Directory record (the real CD offset/size/count). */
440
446
  export declare const parseZip64EOCD: (buffer: ArrayBuffer) => Zip64EndOfCentralDirectory | null;
@@ -1,6 +1,6 @@
1
1
  export { crc32 } from "./crypto";
2
2
  /** Machine-readable discriminant for {@link RemoteZipError}. */
3
- export type RemoteZipErrorCode = "UNKNOWN" | "CONTENT_LENGTH_MISSING" | "HTTP_ERROR" | "EOCD_NOT_FOUND" | "UNSUPPORTED_ZIP64" | "UNSUPPORTED_ENCRYPTION" | "FILE_NOT_FOUND" | "LOCAL_HEADER_PARSE_FAILED" | "CENTRAL_DIRECTORY_OUT_OF_BOUNDS" | "DECOMPRESSION_LIMIT_EXCEEDED" | "CRC_MISMATCH" | "WRONG_PASSWORD" | "DECRYPTION_FAILED";
3
+ export type RemoteZipErrorCode = "UNKNOWN" | "CONTENT_LENGTH_MISSING" | "INVALID_CONTENT_LENGTH" | "HTTP_ERROR" | "RANGE_NOT_SUPPORTED" | "RANGE_RESPONSE_MISMATCH" | "EOCD_NOT_FOUND" | "UNSUPPORTED_ZIP64" | "UNSUPPORTED_ENCRYPTION" | "FILE_NOT_FOUND" | "LOCAL_HEADER_PARSE_FAILED" | "CENTRAL_DIRECTORY_OUT_OF_BOUNDS" | "INVALID_ARCHIVE" | "TRUNCATED_ENTRY" | "UNSUPPORTED_COMPRESSION" | "UNSUPPORTED_MULTI_DISK" | "DECOMPRESSION_LIMIT_EXCEEDED" | "CRC_MISMATCH" | "WRONG_PASSWORD" | "DECRYPTION_FAILED";
4
4
  export declare class RemoteZipError extends Error {
5
5
  /** Machine-readable error code, for programmatic handling without matching on `message`. */
6
6
  code: RemoteZipErrorCode;
@@ -273,7 +273,7 @@ export declare class RemoteZip {
273
273
  /** Passed to fetch when performing a HTTP GET request for the file */
274
274
  method: string;
275
275
  /** Passed to fetch when performing a HTTP GET request for the file. */
276
- credentials: "include" | "omit" | "same-origin";
276
+ credentials?: "include" | "omit" | "same-origin";
277
277
  } & Pick<RemoteZipRequestOptions, "redirect" | "signal" | "timeoutMs" | "requestInit">);
278
278
  /** Build a fetch RequestInit from this instance's network options. */
279
279
  private requestInitFor;
@@ -305,7 +305,7 @@ export declare class RemoteZip {
305
305
  * @param options.verifyCrc If set, verify the decompressed output against the
306
306
  * entry's CRC-32 and throw a {@link RemoteZipError} (`CRC_MISMATCH`) on mismatch.
307
307
  * @returns Inflated (uncompressed) bytes of the requested file
308
- * @throws [RemoteZipError](RemoteZipError) if it fails to parse, fetch, or exceeds limits
308
+ * @throws {@link RemoteZipError} if it fails to parse, fetch, or exceeds limits
309
309
  */
310
310
  fetch(path: string, additionalHeaders?: Headers, options?: EntryDecodeOptions): Promise<Uint8Array>;
311
311
  /**
@@ -333,6 +333,7 @@ export declare class RemoteZip {
333
333
  * {@link fetchStream}.
334
334
  */
335
335
  private fetchEntryResponse;
336
+ private fetchRange;
336
337
  }
337
338
  /**
338
339
  * Network options shared by every request a {@link RemoteZip} / {@link RemoteZipPointer}
@@ -403,8 +404,8 @@ export declare class RemoteZipPointer {
403
404
  /**
404
405
  * Gets metadata about the ZIP file and constructs an initialised `RemoteZip`.
405
406
  *
406
- * @returns An initialised [RemoteZip](RemoteZip)
407
- * @throws [RemoteZipError](RemoteZipError) if it fails to parse or fetch
407
+ * @returns An initialised {@link RemoteZip}
408
+ * @throws {@link RemoteZipError} if it fails to parse or fetch
408
409
  */
409
410
  populate(): Promise<RemoteZip>;
410
411
  private fetchEndOfCentralDirectory;
@@ -428,13 +429,18 @@ export declare const parseZipDatetime: (zipDate: number, zipTime: number) => str
428
429
  export declare const isZip64: (eocd: EndOfCentralDirectory) => boolean;
429
430
  /** Effective central-directory location from a ZIP64 End Of Central Directory record. */
430
431
  export interface Zip64EndOfCentralDirectory {
432
+ diskNumber: number;
433
+ cdDisk: number;
434
+ centralDirectoryDiskRecordCount: number;
431
435
  centralDirectoryRecordCount: number;
432
436
  centralDirectoryByteSize: number;
433
437
  centralDirectoryByteOffset: number;
434
438
  }
435
439
  /** Locate the ZIP64 EOCD locator in a tail buffer and return the ZIP64 EOCD offset. */
436
440
  export declare const parseZip64EOCDLocator: (buffer: ArrayBuffer) => {
441
+ diskWithZip64EOCD: number;
437
442
  zip64EOCDOffset: number;
443
+ totalDisks: number;
438
444
  } | null;
439
445
  /** Parse a ZIP64 End Of Central Directory record (the real CD offset/size/count). */
440
446
  export declare const parseZip64EOCD: (buffer: ArrayBuffer) => Zip64EndOfCentralDirectory | null;
package/package.json CHANGED
@@ -1,45 +1,27 @@
1
1
  {
2
2
  "name": "@gyng/remote-zip",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Fetch file listings and individual files from a remote ZIP archive over HTTP Range requests, without downloading the whole archive.",
5
- "type": "commonjs",
6
- "main": "lib/cjs/index.js",
7
- "module": "lib/esm/index.mjs",
8
- "types": "lib/types/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "import": {
12
- "types": "./lib/types/index.d.mts",
13
- "default": "./lib/esm/index.mjs"
14
- },
15
- "require": {
16
- "types": "./lib/types/index.d.ts",
17
- "default": "./lib/cjs/index.js"
18
- }
19
- },
20
- "./package.json": "./package.json"
21
- },
22
- "sideEffects": false,
23
- "author": "Ng Guoyou <gyng@users.noreply.github.com>",
24
- "license": "(MIT OR Apache-2.0)",
25
5
  "keywords": [
26
- "zip",
27
- "remote",
6
+ "browser",
7
+ "central-directory",
8
+ "fetch",
28
9
  "http",
29
10
  "range",
30
- "fetch",
11
+ "remote",
31
12
  "stream",
32
- "central-directory",
33
- "browser"
13
+ "zip"
34
14
  ],
35
15
  "homepage": "https://github.com/gyng/remote-zip#readme",
36
16
  "bugs": {
37
17
  "url": "https://github.com/gyng/remote-zip/issues"
38
18
  },
39
- "engines": {
40
- "node": ">=22"
19
+ "license": "(MIT OR Apache-2.0)",
20
+ "author": "Ng Guoyou <gyng@users.noreply.github.com>",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/gyng/remote-zip.git"
41
24
  },
42
- "packageManager": "npm@11.11.0",
43
25
  "files": [
44
26
  "LICENSE-MIT",
45
27
  "LICENSE-APACHE",
@@ -47,45 +29,55 @@
47
29
  "package.json",
48
30
  "lib/**"
49
31
  ],
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/gyng/remote-zip.git"
32
+ "type": "commonjs",
33
+ "sideEffects": false,
34
+ "main": "lib/cjs/index.js",
35
+ "module": "lib/esm/index.mjs",
36
+ "types": "lib/types/index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "import": {
40
+ "types": "./lib/types/index.d.mts",
41
+ "default": "./lib/esm/index.mjs"
42
+ },
43
+ "require": {
44
+ "types": "./lib/types/index.d.ts",
45
+ "default": "./lib/cjs/index.js"
46
+ }
47
+ },
48
+ "./package.json": "./package.json"
53
49
  },
54
50
  "scripts": {
55
51
  "build": "rm -rf lib/* && npm run ts-types && node ./esbuild.mjs",
56
52
  "d": "WATCH=1 npm run build",
57
- "doc:gen": "typedoc src/index.ts --excludePrivate --cleanOutputDir --logLevel Verbose --out ./docs/api",
53
+ "doc:gen": "npm --prefix tools/typedoc run generate",
58
54
  "doc:site": "npm run build && npm run doc:gen && node ./scripts/build-site.mjs",
59
- "lint:eslint:fix": "npm run lint:eslint -- --fix",
60
- "lint:eslint": "eslint .",
61
- "lint:fix": "npm run lint:prettier:fix && npm run lint:eslint:fix",
62
- "lint:prettier:fix": "prettier --write .",
63
- "lint:prettier": "prettier --check .",
64
- "lint": "npm run lint:prettier && npm run lint:eslint",
55
+ "lint:fix": "oxfmt . && oxlint --type-aware --import-plugin --vitest-plugin --fix .",
56
+ "lint": "oxfmt --check . && oxlint --type-aware --import-plugin --vitest-plugin .",
65
57
  "t:watch": "vitest",
66
58
  "t": "npm test",
67
59
  "test:coverage": "vitest run --coverage",
60
+ "test:package": "npm run build && node ./scripts/test-package.mjs",
68
61
  "test": "vitest run",
69
62
  "ts-types": "tsc -p tsconfig.build.json",
70
63
  "typecheck": "tsc -p tsconfig.json --noEmit",
71
64
  "prepublishOnly": "npm run build"
72
65
  },
66
+ "dependencies": {
67
+ "pako": "^3.0.1"
68
+ },
73
69
  "devDependencies": {
74
- "@eslint/js": "^10.0.0",
75
- "@types/node": "^22.19.20",
76
- "@types/pako": "^2.0.4",
77
- "@vitest/coverage-v8": "^4.1.0",
78
- "esbuild": "^0.28.0",
79
- "eslint": "^10.0.0",
80
- "eslint-config-prettier": "^10.1.8",
81
- "globals": "^17.6.0",
82
- "prettier": "^3.8.3",
83
- "typedoc": "^0.28.19",
84
- "typescript": "~6.0",
85
- "typescript-eslint": "^8.61.0",
86
- "vitest": "^4.1.0"
70
+ "@types/node": "^26.1.1",
71
+ "@vitest/coverage-v8": "^4.1.10",
72
+ "esbuild": "^0.28.1",
73
+ "oxfmt": "^0.58.0",
74
+ "oxlint": "^1.73.0",
75
+ "oxlint-tsgolint": "^0.24.0",
76
+ "typescript": "~7.0.2",
77
+ "vitest": "^4.1.10"
87
78
  },
88
- "dependencies": {
89
- "pako": "^2.1.0"
90
- }
79
+ "engines": {
80
+ "node": ">=22"
81
+ },
82
+ "packageManager": "npm@11.11.0"
91
83
  }