neozipkit 1.0.5 → 1.5.0
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/NEOZIP_APPNOTE.md +116 -18
- package/README.md +38 -8
- package/WHATS_NEW.md +111 -0
- package/dist/browser/zstd-browser-shim.d.ts +17 -9
- package/dist/browser/zstd-browser-shim.d.ts.map +1 -1
- package/dist/browser/zstd-browser-shim.js +99 -21
- package/dist/browser/zstd-browser-shim.js.map +1 -1
- package/dist/browser-esm/index.js +6178 -1261
- package/dist/browser-esm/index.js.map +4 -4
- package/dist/browser-umd/index.js +6178 -1261
- package/dist/browser-umd/index.js.map +4 -4
- package/dist/browser-umd/index.min.js +6 -3
- package/dist/core/ZipCompress.d.ts +6 -0
- package/dist/core/ZipCompress.d.ts.map +1 -1
- package/dist/core/ZipCompress.js.map +1 -1
- package/dist/core/ZipCopy.d.ts.map +1 -1
- package/dist/core/ZipCopy.js +33 -25
- package/dist/core/ZipCopy.js.map +1 -1
- package/dist/core/ZipEntry.d.ts +18 -0
- package/dist/core/ZipEntry.d.ts.map +1 -1
- package/dist/core/ZipEntry.js +139 -13
- package/dist/core/ZipEntry.js.map +1 -1
- package/dist/core/Zipkit.d.ts.map +1 -1
- package/dist/core/Zipkit.js +26 -19
- package/dist/core/Zipkit.js.map +1 -1
- package/dist/core/constants/Headers.d.ts +1 -0
- package/dist/core/constants/Headers.d.ts.map +1 -1
- package/dist/core/constants/Headers.js +1 -0
- package/dist/core/constants/Headers.js.map +1 -1
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/inflateZipPayload.d.ts +6 -0
- package/dist/core/inflateZipPayload.d.ts.map +1 -0
- package/dist/core/inflateZipPayload.js +28 -0
- package/dist/core/inflateZipPayload.js.map +1 -0
- package/dist/core/origin/OriginExtra.d.ts +43 -0
- package/dist/core/origin/OriginExtra.d.ts.map +1 -0
- package/dist/core/origin/OriginExtra.js +187 -0
- package/dist/core/origin/OriginExtra.js.map +1 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zip64/Zip64.d.ts +138 -0
- package/dist/core/zip64/Zip64.d.ts.map +1 -0
- package/dist/core/zip64/Zip64.js +353 -0
- package/dist/core/zip64/Zip64.js.map +1 -0
- package/dist/node/ZipCopyNode.d.ts.map +1 -1
- package/dist/node/ZipCopyNode.js +26 -26
- package/dist/node/ZipCopyNode.js.map +1 -1
- package/dist/node/ZipDecompressNode.d.ts.map +1 -1
- package/dist/node/ZipDecompressNode.js +8 -6
- package/dist/node/ZipDecompressNode.js.map +1 -1
- package/dist/node/ZipkitNode.d.ts +14 -1
- package/dist/node/ZipkitNode.d.ts.map +1 -1
- package/dist/node/ZipkitNode.js +91 -53
- package/dist/node/ZipkitNode.js.map +1 -1
- package/dist/node/ZstdNode.d.ts +14 -4
- package/dist/node/ZstdNode.d.ts.map +1 -1
- package/dist/node/ZstdNode.js +28 -4
- package/dist/node/ZstdNode.js.map +1 -1
- package/dist/node/buildZipBuffer.d.ts +49 -0
- package/dist/node/buildZipBuffer.d.ts.map +1 -0
- package/dist/node/buildZipBuffer.js +146 -0
- package/dist/node/buildZipBuffer.js.map +1 -0
- package/dist/node/index.d.ts +3 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +6 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/inflateZipPayload.d.ts +5 -0
- package/dist/node/inflateZipPayload.d.ts.map +1 -0
- package/dist/node/inflateZipPayload.js +21 -0
- package/dist/node/inflateZipPayload.js.map +1 -0
- package/dist/types/index.js +2 -2
- package/node-esm.mjs +32 -0
- package/package.json +11 -5
- package/src/browser/zstd-browser-shim.ts +110 -28
- package/src/core/ZipCompress.ts +6 -0
- package/src/core/ZipCopy.ts +56 -27
- package/src/core/ZipEntry.ts +192 -13
- package/src/core/Zipkit.ts +40 -22
- package/src/core/constants/Headers.ts +1 -0
- package/src/core/index.ts +3 -0
- package/src/core/inflateZipPayload.ts +27 -0
- package/src/core/origin/OriginExtra.ts +209 -0
- package/src/core/version.ts +1 -1
- package/src/core/zip64/Zip64.ts +473 -0
- package/src/node/ZipCopyNode.ts +31 -29
- package/src/node/ZipDecompressNode.ts +6 -5
- package/src/node/ZipkitNode.ts +121 -68
- package/src/node/ZstdNode.ts +33 -8
- package/src/node/buildZipBuffer.ts +221 -0
- package/src/node/index.ts +7 -0
- package/src/node/inflateZipPayload.ts +19 -0
- package/src/types/index.ts +2 -2
package/src/core/Zipkit.ts
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
CENTRAL_END,
|
|
26
26
|
CENTRAL_DIR,
|
|
27
27
|
ZIP64_CENTRAL_END,
|
|
28
|
-
ZIP64_CENTRAL_DIR
|
|
28
|
+
ZIP64_CENTRAL_DIR,
|
|
29
29
|
GP_FLAG,
|
|
30
30
|
TIMESTAMP_SUBMITTED,
|
|
31
31
|
TIMESTAMP_METADATA,
|
|
@@ -35,6 +35,14 @@ import {
|
|
|
35
35
|
CENTRAL_DIRECTORY_END,
|
|
36
36
|
HDR_ID
|
|
37
37
|
} from './constants/Headers';
|
|
38
|
+
import {
|
|
39
|
+
buildEndRecords,
|
|
40
|
+
classicEocdNeedsZip64,
|
|
41
|
+
parseZip64Eocd,
|
|
42
|
+
parseZip64Locator,
|
|
43
|
+
ZIP64_EOCD_RECORD_SIZE,
|
|
44
|
+
ZIP64_LOCATOR_SIZE,
|
|
45
|
+
} from './zip64/Zip64';
|
|
38
46
|
import {
|
|
39
47
|
findReservedMetaEntry,
|
|
40
48
|
isMetaInfPath,
|
|
@@ -605,17 +613,30 @@ export default class Zipkit {
|
|
|
605
613
|
if (eocdBuffer.readUInt32LE(0) === CENTRAL_END.SIGNATURE) {
|
|
606
614
|
this.centralDirSize = eocdBuffer.readUInt32LE(CENTRAL_END.CENTRAL_DIR_SIZE);
|
|
607
615
|
this.centralDirOffset = eocdBuffer.readUInt32LE(CENTRAL_END.CENTRAL_DIR_OFFSET);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
this.
|
|
617
|
-
|
|
616
|
+
const volEntries = eocdBuffer.readUInt16LE(CENTRAL_END.VOL_ENTRIES);
|
|
617
|
+
const totalEntries = eocdBuffer.readUInt16LE(CENTRAL_END.TOTAL_ENTRIES);
|
|
618
|
+
|
|
619
|
+
if (
|
|
620
|
+
classicEocdNeedsZip64({
|
|
621
|
+
volEntries,
|
|
622
|
+
totalEntries,
|
|
623
|
+
centralDirSize: this.centralDirSize,
|
|
624
|
+
centralDirOffset: this.centralDirOffset,
|
|
625
|
+
})
|
|
626
|
+
) {
|
|
627
|
+
const locatorOffset = eocdOffset - ZIP64_LOCATOR_SIZE;
|
|
628
|
+
if (locatorOffset < 0) {
|
|
629
|
+
throw new Error(Errors.INVALID_FORMAT);
|
|
618
630
|
}
|
|
631
|
+
const locatorBuffer = buffer.subarray(locatorOffset, locatorOffset + ZIP64_LOCATOR_SIZE);
|
|
632
|
+
const zip64Offset = parseZip64Locator(locatorBuffer);
|
|
633
|
+
const zip64Buffer = buffer.subarray(
|
|
634
|
+
zip64Offset,
|
|
635
|
+
zip64Offset + ZIP64_EOCD_RECORD_SIZE
|
|
636
|
+
);
|
|
637
|
+
const z64 = parseZip64Eocd(zip64Buffer);
|
|
638
|
+
this.centralDirSize = z64.centralDirSize;
|
|
639
|
+
this.centralDirOffset = z64.centralDirOffset;
|
|
619
640
|
}
|
|
620
641
|
} else {
|
|
621
642
|
throw new Error(Errors.INVALID_FORMAT);
|
|
@@ -691,17 +712,14 @@ export default class Zipkit {
|
|
|
691
712
|
* Note: totalEntries must be passed as parameter since zipEntries[] in Zipkit is the cache
|
|
692
713
|
*/
|
|
693
714
|
private centralEndHdrMethod(centralDirSize: number, centralDirOffset: number, totalEntries: number): Buffer {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
ceBuf.writeUInt16LE(0, 20); // ZIP file comment length
|
|
703
|
-
|
|
704
|
-
return ceBuf;
|
|
715
|
+
// Buffer path: allow entry-count Zip64; refuse size/offset Zip64 (multi-GiB in memory).
|
|
716
|
+
return buildEndRecords({
|
|
717
|
+
totalEntries,
|
|
718
|
+
centralDirSize,
|
|
719
|
+
centralDirOffset,
|
|
720
|
+
zip64EocdOffset: centralDirOffset + centralDirSize,
|
|
721
|
+
allowSizeOffsetZip64: false,
|
|
722
|
+
});
|
|
705
723
|
}
|
|
706
724
|
|
|
707
725
|
/**
|
|
@@ -187,6 +187,7 @@ export const HDR_ID = {
|
|
|
187
187
|
IBM1: 0x0065, // IBM S/390 (Z390) - Attribute
|
|
188
188
|
IBM2: 0x0066, // IBM S/390 (Z390) - Attribute
|
|
189
189
|
SHA256: 0x014E, // NeoZip Extra Field: 32-byte SHA-256 of uncompressed payload (APPNOTE §5)
|
|
190
|
+
ORIGIN: 0x014F, // ZipWiki origin locator (URI, size, mtime, CRC-32 or SHA-256)
|
|
190
191
|
NEO_CRYPTO: 0x024E, // NeoEncrypt metadata (see docs/NEO_CRYPTO_FORMAT.md); LE on wire: 4E 02
|
|
191
192
|
POSZIP: 0x4690, // POSZIP 4690
|
|
192
193
|
UNV_TIME: 0x5455, // Universal Time (UT) (32-bit) 5 data bytes
|
package/src/core/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './ZipEntry';
|
|
|
10
10
|
export { ZipCompress } from './ZipCompress';
|
|
11
11
|
export type { CompressOptions, CreateZipOptions } from './ZipCompress';
|
|
12
12
|
export type { DecompressionResult, DecompressionOptions } from './ZipDecompress';
|
|
13
|
+
export { inflateZipPayload } from './inflateZipPayload';
|
|
13
14
|
export { ZipCopy } from './ZipCopy';
|
|
14
15
|
export type {
|
|
15
16
|
CopyOptions,
|
|
@@ -25,6 +26,8 @@ export * from './components/Util';
|
|
|
25
26
|
export * from './components/Support';
|
|
26
27
|
export { ProgressTracker } from './components/ProgressTracker';
|
|
27
28
|
export * from './merkle/MerkleRoot';
|
|
29
|
+
export * from './zip64/Zip64';
|
|
30
|
+
export * from './origin/OriginExtra';
|
|
28
31
|
|
|
29
32
|
// Encryption functionality
|
|
30
33
|
export { EncryptionManager } from './encryption/Manager';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inflate one ZIP member payload (store, deflate, zstd) from an in-memory buffer.
|
|
3
|
+
* Browser bundles alias ZstdNode to the CompressionStream codec.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import pako from 'pako';
|
|
7
|
+
import { decompress } from '../node/ZstdNode';
|
|
8
|
+
|
|
9
|
+
export async function inflateZipPayload(
|
|
10
|
+
method: number,
|
|
11
|
+
compressed: Uint8Array | ArrayBuffer,
|
|
12
|
+
): Promise<Uint8Array> {
|
|
13
|
+
const bytes =
|
|
14
|
+
compressed instanceof ArrayBuffer ? new Uint8Array(compressed) : compressed;
|
|
15
|
+
if (method === 0) {
|
|
16
|
+
return bytes.slice();
|
|
17
|
+
}
|
|
18
|
+
if (method === 8) {
|
|
19
|
+
const out = pako.inflateRaw(bytes);
|
|
20
|
+
return out instanceof Uint8Array ? out : new Uint8Array(out);
|
|
21
|
+
}
|
|
22
|
+
if (method === 93) {
|
|
23
|
+
const out = await decompress(bytes);
|
|
24
|
+
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`unsupported compression method ${method}`);
|
|
27
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// ======================================
|
|
2
|
+
// OriginExtra.ts — NeoZip Extra Field 0x014F (original locator)
|
|
3
|
+
// Copyright (c) 2026 NeoWare, Inc. All rights reserved.
|
|
4
|
+
// ======================================
|
|
5
|
+
// APPNOTE §7.1.1 / ZipWiki §6.7 — v1 TLV (URI, CRC-32, size, mtime, SHA-256).
|
|
6
|
+
// The kit stores opaque caller extras on ZipEntry.additionalExtra; these helpers
|
|
7
|
+
// build and parse the 0x014F wire form.
|
|
8
|
+
|
|
9
|
+
import { HDR_ID } from '../constants/Headers';
|
|
10
|
+
import { crc32, sha256 } from '../encryption/ZipCrypto';
|
|
11
|
+
|
|
12
|
+
/** Payload version byte. Stays 0x01 until first release. */
|
|
13
|
+
export const ORIGIN_EXTRA_VERSION = 0x01;
|
|
14
|
+
|
|
15
|
+
/** Soft cap on URI byte length (well under uint16 extra size). */
|
|
16
|
+
export const ORIGIN_URI_MAX_BYTES = 2048;
|
|
17
|
+
|
|
18
|
+
/** Registered v1 TLV tags. Unknown tags are skipped (forward compatible). */
|
|
19
|
+
export const ORIGIN_TAG = {
|
|
20
|
+
URI: 0x01,
|
|
21
|
+
CRC32: 0x02,
|
|
22
|
+
SIZE: 0x03,
|
|
23
|
+
MTIME: 0x04,
|
|
24
|
+
SHA256: 0x05,
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type OriginLocator = {
|
|
28
|
+
/** Absolute RFC 3986 URI (`https:` / `http:` / `file:`). */
|
|
29
|
+
uri?: string;
|
|
30
|
+
/** ZIP/IEEE CRC-32 of original uncompressed bytes. */
|
|
31
|
+
crc32?: number;
|
|
32
|
+
/** Original uncompressed byte length. */
|
|
33
|
+
size?: number;
|
|
34
|
+
/** Original modification time: Unix seconds (UTC, signed). */
|
|
35
|
+
mtime?: number;
|
|
36
|
+
/** SHA-256 of original uncompressed bytes (32 bytes or hex). */
|
|
37
|
+
sha256?: Buffer | string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function originSha256Bytes(value: Buffer | string): Buffer {
|
|
41
|
+
const buf = typeof value === 'string' ? Buffer.from(value, 'hex') : value;
|
|
42
|
+
if (buf.length !== 32) {
|
|
43
|
+
throw new Error('0x014F sha256 must be 32 bytes');
|
|
44
|
+
}
|
|
45
|
+
return buf;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function tlv(tag: number, value: Buffer): Buffer {
|
|
49
|
+
const rec = Buffer.alloc(3 + value.length);
|
|
50
|
+
rec.writeUInt8(tag, 0);
|
|
51
|
+
rec.writeUInt16LE(value.length, 1);
|
|
52
|
+
value.copy(rec, 3);
|
|
53
|
+
return rec;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function assertInteger(name: string, value: number): void {
|
|
57
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
58
|
+
throw new Error(`0x014F ${name} must be an integer`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function originLocatorPresent(
|
|
63
|
+
loc: OriginLocator | null | undefined
|
|
64
|
+
): loc is OriginLocator {
|
|
65
|
+
if (!loc) return false;
|
|
66
|
+
return (
|
|
67
|
+
(typeof loc.uri === 'string' && loc.uri.length > 0) ||
|
|
68
|
+
loc.crc32 !== undefined ||
|
|
69
|
+
loc.size !== undefined ||
|
|
70
|
+
loc.mtime !== undefined ||
|
|
71
|
+
loc.sha256 !== undefined
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** ZIP/IEEE CRC-32 of uncompressed original bytes. */
|
|
76
|
+
export function originCrc32Of(buf: Buffer): number {
|
|
77
|
+
return crc32(buf) >>> 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** SHA-256 of uncompressed original bytes (32-byte Buffer). */
|
|
81
|
+
export function originSha256Of(buf: Buffer): Buffer {
|
|
82
|
+
return Buffer.from(sha256(buf), 'hex');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Truncate a Date to Unix seconds (UTC). */
|
|
86
|
+
export function unixTimeSeconds(date: Date): number {
|
|
87
|
+
return Math.floor(date.getTime() / 1000);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Build Extra Field 0x014F (v1 TLV). Throws if no attribute is present,
|
|
92
|
+
* if URI is empty when provided, or if URI exceeds max bytes.
|
|
93
|
+
*/
|
|
94
|
+
export function makeOriginExtra(loc: OriginLocator): Buffer {
|
|
95
|
+
const records: Buffer[] = [];
|
|
96
|
+
|
|
97
|
+
const uri = loc.uri?.trim();
|
|
98
|
+
if (uri !== undefined && uri.length === 0) {
|
|
99
|
+
throw new Error('0x014F URI must be non-empty when present');
|
|
100
|
+
}
|
|
101
|
+
if (uri) {
|
|
102
|
+
const uriBuf = Buffer.from(uri, 'utf8');
|
|
103
|
+
if (uriBuf.length > ORIGIN_URI_MAX_BYTES) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`0x014F URI exceeds ${ORIGIN_URI_MAX_BYTES} bytes (${uriBuf.length})`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
records.push(tlv(ORIGIN_TAG.URI, uriBuf));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (loc.crc32 !== undefined) {
|
|
112
|
+
assertInteger('crc32', loc.crc32);
|
|
113
|
+
const b = Buffer.alloc(4);
|
|
114
|
+
b.writeUInt32LE(loc.crc32 >>> 0, 0);
|
|
115
|
+
records.push(tlv(ORIGIN_TAG.CRC32, b));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (loc.size !== undefined) {
|
|
119
|
+
assertInteger('size', loc.size);
|
|
120
|
+
if (loc.size < 0) {
|
|
121
|
+
throw new Error('0x014F size must be >= 0');
|
|
122
|
+
}
|
|
123
|
+
const b = Buffer.alloc(8);
|
|
124
|
+
b.writeBigUInt64LE(BigInt(loc.size), 0);
|
|
125
|
+
records.push(tlv(ORIGIN_TAG.SIZE, b));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (loc.mtime !== undefined) {
|
|
129
|
+
assertInteger('mtime', loc.mtime);
|
|
130
|
+
const b = Buffer.alloc(8);
|
|
131
|
+
b.writeBigInt64LE(BigInt(loc.mtime), 0);
|
|
132
|
+
records.push(tlv(ORIGIN_TAG.MTIME, b));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (loc.sha256 !== undefined) {
|
|
136
|
+
records.push(tlv(ORIGIN_TAG.SHA256, originSha256Bytes(loc.sha256)));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (records.length === 0) {
|
|
140
|
+
throw new Error('0x014F requires at least one attribute');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const dataSize = 1 + records.reduce((n, r) => n + r.length, 0);
|
|
144
|
+
const extra = Buffer.alloc(4 + dataSize);
|
|
145
|
+
extra.writeUInt16LE(HDR_ID.ORIGIN, 0);
|
|
146
|
+
extra.writeUInt16LE(dataSize, 2);
|
|
147
|
+
extra.writeUInt8(ORIGIN_EXTRA_VERSION, 4);
|
|
148
|
+
let off = 5;
|
|
149
|
+
for (const rec of records) {
|
|
150
|
+
rec.copy(extra, off);
|
|
151
|
+
off += rec.length;
|
|
152
|
+
}
|
|
153
|
+
return extra;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function parseOriginTlv(data: Buffer): OriginLocator | null {
|
|
157
|
+
const loc: OriginLocator = {};
|
|
158
|
+
let i = 0;
|
|
159
|
+
while (i + 3 <= data.length) {
|
|
160
|
+
const tag = data.readUInt8(i);
|
|
161
|
+
const len = data.readUInt16LE(i + 1);
|
|
162
|
+
i += 3;
|
|
163
|
+
if (i + len > data.length) break;
|
|
164
|
+
const value = data.subarray(i, i + len);
|
|
165
|
+
i += len;
|
|
166
|
+
if (tag === ORIGIN_TAG.URI && len > 0) {
|
|
167
|
+
const u = value.toString('utf8');
|
|
168
|
+
if (u.length > 0) loc.uri = u;
|
|
169
|
+
} else if (tag === ORIGIN_TAG.CRC32 && len === 4) {
|
|
170
|
+
loc.crc32 = value.readUInt32LE(0) >>> 0;
|
|
171
|
+
} else if (tag === ORIGIN_TAG.SIZE && len === 8) {
|
|
172
|
+
loc.size = Number(value.readBigUInt64LE(0));
|
|
173
|
+
} else if (tag === ORIGIN_TAG.MTIME && len === 8) {
|
|
174
|
+
loc.mtime = Number(value.readBigInt64LE(0));
|
|
175
|
+
} else if (tag === ORIGIN_TAG.SHA256 && len === 32) {
|
|
176
|
+
loc.sha256 = Buffer.from(value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return originLocatorPresent(loc) ? loc : null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Walk a ZIP Extra Field blob for NeoZip 0x014F (v1 TLV). */
|
|
183
|
+
export function parseOriginFromExtra(extra: Buffer | null | undefined): OriginLocator | null {
|
|
184
|
+
if (!extra || extra.length < 4) return null;
|
|
185
|
+
let i = 0;
|
|
186
|
+
while (i + 4 <= extra.length) {
|
|
187
|
+
const id = extra.readUInt16LE(i);
|
|
188
|
+
const size = extra.readUInt16LE(i + 2);
|
|
189
|
+
i += 4;
|
|
190
|
+
if (i + size > extra.length) break;
|
|
191
|
+
if (id === HDR_ID.ORIGIN && size >= 1) {
|
|
192
|
+
const version = extra.readUInt8(i);
|
|
193
|
+
const payload = extra.subarray(i + 1, i + size);
|
|
194
|
+
if (version === ORIGIN_EXTRA_VERSION) {
|
|
195
|
+
const loc = parseOriginTlv(payload);
|
|
196
|
+
if (loc) return loc;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
i += size;
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Read origin locator from a ZipEntry's preserved caller extras. */
|
|
205
|
+
export function parseOriginFromEntry(entry: {
|
|
206
|
+
additionalExtra?: Buffer | null;
|
|
207
|
+
}): OriginLocator | null {
|
|
208
|
+
return parseOriginFromExtra(entry.additionalExtra ?? null);
|
|
209
|
+
}
|
package/src/core/version.ts
CHANGED
|
@@ -28,6 +28,6 @@ const currentDate = new Date();
|
|
|
28
28
|
const releaseDate = `${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(currentDate.getDate()).padStart(2, '0')}-${currentDate.getFullYear()}`;
|
|
29
29
|
|
|
30
30
|
export const VERSION = {
|
|
31
|
-
number: '1.0
|
|
31
|
+
number: '1.5.0', // packageJson.version
|
|
32
32
|
date: releaseDate
|
|
33
33
|
};
|