@naturalcycles/nodejs-lib 15.137.0 → 15.139.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/dist/cache/lruMemoCache.d.ts +2 -0
- package/dist/cache/lruMemoCache.js +6 -0
- package/dist/security/secret.util.js +1 -3
- package/dist/stream/transform/transformSplit.js +2 -3
- package/dist/zip/zipReader.js +3 -6
- package/dist/zip/zipWriter.js +4 -7
- package/package.json +2 -2
- package/src/cache/lruMemoCache.ts +8 -0
- package/src/security/secret.util.ts +1 -3
- package/src/stream/transform/transformSplit.ts +2 -3
- package/src/stream/transform/worker/workerClassProxy.js +2 -0
- package/src/zip/zipReader.ts +6 -6
- package/src/zip/zipWriter.ts +7 -5
|
@@ -15,6 +15,7 @@ export declare class LRUMemoCache<KEY = any, VALUE = any> implements MemoCache<K
|
|
|
15
15
|
has(k: any): boolean;
|
|
16
16
|
get(k: any): any;
|
|
17
17
|
set(k: any, v: any): void;
|
|
18
|
+
delete(k: any): void;
|
|
18
19
|
clear(): void;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
@@ -26,5 +27,6 @@ export declare class LRUAsyncMemoCache<KEY = any, VALUE = any> implements AsyncM
|
|
|
26
27
|
has(k: any): Promise<boolean>;
|
|
27
28
|
get(k: any): Promise<VALUE | typeof MISS>;
|
|
28
29
|
set(k: any, v: any): Promise<void>;
|
|
30
|
+
delete(k: any): Promise<void>;
|
|
29
31
|
clear(): Promise<void>;
|
|
30
32
|
}
|
|
@@ -24,6 +24,9 @@ export class LRUMemoCache {
|
|
|
24
24
|
set(k, v) {
|
|
25
25
|
this.lru.set(k, v);
|
|
26
26
|
}
|
|
27
|
+
delete(k) {
|
|
28
|
+
this.lru.delete(k);
|
|
29
|
+
}
|
|
27
30
|
clear() {
|
|
28
31
|
this.lru.clear();
|
|
29
32
|
}
|
|
@@ -53,6 +56,9 @@ export class LRUAsyncMemoCache {
|
|
|
53
56
|
async set(k, v) {
|
|
54
57
|
this.lru.set(k, v === undefined ? UNDEFINED : v);
|
|
55
58
|
}
|
|
59
|
+
async delete(k) {
|
|
60
|
+
this.lru.delete(k);
|
|
61
|
+
}
|
|
56
62
|
async clear() {
|
|
57
63
|
this.lru.clear();
|
|
58
64
|
}
|
|
@@ -106,7 +106,5 @@ export function setSecretMap(map) {
|
|
|
106
106
|
.join(', ')}`);
|
|
107
107
|
}
|
|
108
108
|
function requireLoaded() {
|
|
109
|
-
|
|
110
|
-
throw new Error(`Secrets were not loaded! Call loadSecrets() before accessing secrets.`);
|
|
111
|
-
}
|
|
109
|
+
_assert(loaded, `Secrets were not loaded! Call loadSecrets() before accessing secrets.`);
|
|
112
110
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transform } from 'node:stream';
|
|
2
|
+
import { _assert } from '@naturalcycles/js-lib/error';
|
|
2
3
|
// The code below is carefully adopted from: https://github.com/max-mapper/binary-split
|
|
3
4
|
// (including the v2.0.0 performance improvements: native Buffer#indexOf and linear-time long lines)
|
|
4
5
|
/**
|
|
@@ -22,9 +23,7 @@ export function transformSplitOnNewline() {
|
|
|
22
23
|
*/
|
|
23
24
|
export function transformSplit(separator = '\n') {
|
|
24
25
|
const matcher = Buffer.from(separator);
|
|
25
|
-
|
|
26
|
-
throw new Error('transformSplit: separator must not be empty');
|
|
27
|
-
}
|
|
26
|
+
_assert(matcher.length !== 0, 'transformSplit: separator must not be empty');
|
|
28
27
|
const matcherLength = matcher.length;
|
|
29
28
|
// indexOf with a byte value is much faster than with a 1-byte Buffer, which matters for short lines
|
|
30
29
|
const needle = matcherLength === 1 ? matcher[0] : matcher;
|
package/dist/zip/zipReader.js
CHANGED
|
@@ -25,6 +25,7 @@ import { Readable } from 'node:stream';
|
|
|
25
25
|
import { pipeline } from 'node:stream/promises';
|
|
26
26
|
import { promisify } from 'node:util';
|
|
27
27
|
import zlib from 'node:zlib';
|
|
28
|
+
import { _assert } from '@naturalcycles/js-lib/error';
|
|
28
29
|
import { assertSafeZipEntryName, CDFH_SIG, CDFH_SIZE, DEFLATE, dosDateTimeToUnix, EOCDR_SIG, EOCDR_SIZE, LOCAL_FILE_HEADER_SIG, MAX_COMMENT_SIZE, normalizeZipEntryName, readUInt64LE, STORED, ZIP64_EOCDL_SIG, ZIP64_EOCDL_SIZE, ZIP64_EOCDR_SIG, ZIP64_EOCDR_SIZE, } from './zipInternal.js';
|
|
29
30
|
// oxlint-disable no-bitwise -- parsing the binary ZIP format requires bitwise ops on bit flags and packed DOS date/time fields
|
|
30
31
|
const inflateRawAsync = promisify(zlib.inflateRaw.bind(zlib));
|
|
@@ -239,12 +240,8 @@ async function readEndOfCentralDirectory(source) {
|
|
|
239
240
|
if (locatorIndex >= 0 && buf.readUInt32LE(locatorIndex) === ZIP64_EOCDL_SIG) {
|
|
240
241
|
const zip64EocdrOffset = readUInt64LE(buf, locatorIndex + 8);
|
|
241
242
|
const zip64 = await source.read(zip64EocdrOffset, ZIP64_EOCDR_SIZE);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
if (zip64.readUInt32LE(16) !== 0) {
|
|
246
|
-
throw new Error('multi-disk zip files are not supported');
|
|
247
|
-
}
|
|
243
|
+
_assert(zip64.readUInt32LE(0) === ZIP64_EOCDR_SIG, 'invalid zip64 end of central directory record signature');
|
|
244
|
+
_assert(zip64.readUInt32LE(16) === 0, 'multi-disk zip files are not supported');
|
|
248
245
|
entryCount = readUInt64LE(zip64, 32);
|
|
249
246
|
centralDirectoryOffset = readUInt64LE(zip64, 48);
|
|
250
247
|
centralDirectoryEnd = zip64EocdrOffset;
|
package/dist/zip/zipWriter.js
CHANGED
|
@@ -29,6 +29,7 @@ import { finished, pipeline } from 'node:stream/promises';
|
|
|
29
29
|
import { promisify } from 'node:util';
|
|
30
30
|
import zlib from 'node:zlib';
|
|
31
31
|
import { comparators } from '@naturalcycles/js-lib/array/sort.js';
|
|
32
|
+
import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
32
33
|
import { glob } from 'tinyglobby';
|
|
33
34
|
import { assertSafeZipEntryName, CDFH_SIG, CDFH_SIZE, DATA_DESCRIPTOR_SIG, DEFLATE, EOCDR_SIG, EOCDR_SIZE, LOCAL_FILE_HEADER_SIG, MAX_COMMENT_SIZE, normalizeZipEntryName, STORED, unixToDosDateTime, writeUInt64LE, ZIP64_EOCDL_SIG, ZIP64_EOCDL_SIZE, ZIP64_EOCDR_SIG, ZIP64_EOCDR_SIZE, } from './zipInternal.js';
|
|
34
35
|
// oxlint-disable no-bitwise, unicorn/prefer-math-trunc -- writing the binary ZIP format requires bitwise ops on bit flags, packed DOS date/time fields, and unsigned 32-bit attribute packing
|
|
@@ -187,9 +188,7 @@ export class ZipWriter {
|
|
|
187
188
|
}
|
|
188
189
|
// A comment containing this signature would confuse readers that scan
|
|
189
190
|
// backwards for the end-of-central-directory record.
|
|
190
|
-
|
|
191
|
-
throw new Error('archive comment must not contain the end-of-central-directory signature');
|
|
192
|
-
}
|
|
191
|
+
_assert(!comment.includes(EOCDR_SIG_BYTES), 'archive comment must not contain the end-of-central-directory signature');
|
|
193
192
|
this.finalized = true;
|
|
194
193
|
const centralDirectoryOffset = this.offset;
|
|
195
194
|
for (const entry of this.entries) {
|
|
@@ -215,8 +214,7 @@ export class ZipWriter {
|
|
|
215
214
|
assertWritable() {
|
|
216
215
|
if (this.streamError)
|
|
217
216
|
throw this.streamError;
|
|
218
|
-
|
|
219
|
-
throw new Error('ZipWriter has already been finalized');
|
|
217
|
+
_assert(!this.finalized, 'ZipWriter has already been finalized');
|
|
220
218
|
}
|
|
221
219
|
/** Build the in-memory representation of an entry from its name and options. */
|
|
222
220
|
createEntry(fileName, isDirectory, opt) {
|
|
@@ -508,8 +506,7 @@ function buildEndRecords(input) {
|
|
|
508
506
|
return Buffer.concat([zip64Eocdr, locator, eocdr]);
|
|
509
507
|
}
|
|
510
508
|
function normalizeAndValidateEntryName(fileName, isDirectory) {
|
|
511
|
-
|
|
512
|
-
throw new Error('zip entry name must not be empty');
|
|
509
|
+
_assert(fileName, 'zip entry name must not be empty');
|
|
513
510
|
let name = normalizeZipEntryName(fileName);
|
|
514
511
|
if (isDirectory) {
|
|
515
512
|
if (!name.endsWith('/'))
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.139.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@standard-schema/spec": "^1",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"yaml": "^2"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@naturalcycles/dev-lib": "
|
|
17
|
+
"@naturalcycles/dev-lib": "20.70.0",
|
|
18
18
|
"typescript": "^7"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
@@ -34,6 +34,10 @@ export class LRUMemoCache<KEY = any, VALUE = any> implements MemoCache<KEY, VALU
|
|
|
34
34
|
this.lru.set(k, v)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
delete(k: any): void {
|
|
38
|
+
this.lru.delete(k)
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
clear(): void {
|
|
38
42
|
this.lru.clear()
|
|
39
43
|
}
|
|
@@ -69,6 +73,10 @@ export class LRUAsyncMemoCache<KEY = any, VALUE = any> implements AsyncMemoCache
|
|
|
69
73
|
this.lru.set(k, v === undefined ? UNDEFINED : v)
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
async delete(k: any): Promise<void> {
|
|
77
|
+
this.lru.delete(k)
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
async clear(): Promise<void> {
|
|
73
81
|
this.lru.clear()
|
|
74
82
|
}
|
|
@@ -151,7 +151,5 @@ export function setSecretMap(map: StringMap): void {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
function requireLoaded(): void {
|
|
154
|
-
|
|
155
|
-
throw new Error(`Secrets were not loaded! Call loadSecrets() before accessing secrets.`)
|
|
156
|
-
}
|
|
154
|
+
_assert(loaded, `Secrets were not loaded! Call loadSecrets() before accessing secrets.`)
|
|
157
155
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transform } from 'node:stream'
|
|
2
|
+
import { _assert } from '@naturalcycles/js-lib/error'
|
|
2
3
|
import type { TransformTyped } from '../stream.model.js'
|
|
3
4
|
|
|
4
5
|
// The code below is carefully adopted from: https://github.com/max-mapper/binary-split
|
|
@@ -26,9 +27,7 @@ export function transformSplitOnNewline(): TransformTyped<Buffer, Buffer> {
|
|
|
26
27
|
*/
|
|
27
28
|
export function transformSplit(separator = '\n'): TransformTyped<Buffer, Buffer> {
|
|
28
29
|
const matcher = Buffer.from(separator)
|
|
29
|
-
|
|
30
|
-
throw new Error('transformSplit: separator must not be empty')
|
|
31
|
-
}
|
|
30
|
+
_assert(matcher.length !== 0, 'transformSplit: separator must not be empty')
|
|
32
31
|
const matcherLength = matcher.length
|
|
33
32
|
// indexOf with a byte value is much faster than with a 1-byte Buffer, which matters for short lines
|
|
34
33
|
const needle = matcherLength === 1 ? matcher[0]! : matcher
|
|
@@ -4,6 +4,8 @@ import { workerData, parentPort } from 'node:worker_threads'
|
|
|
4
4
|
|
|
5
5
|
const { workerFile, workerIndex, logEvery = 1000, metric = 'worker', silent } = workerData || {}
|
|
6
6
|
|
|
7
|
+
// The worker entry stays dependency-free, so no `_assert` here
|
|
8
|
+
// oxlint-disable-next-line nc/prefer-assert
|
|
7
9
|
if (!workerFile) {
|
|
8
10
|
throw new Error('workerData.workerFile is required!')
|
|
9
11
|
}
|
package/src/zip/zipReader.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { Readable } from 'node:stream'
|
|
|
27
27
|
import { pipeline } from 'node:stream/promises'
|
|
28
28
|
import { promisify } from 'node:util'
|
|
29
29
|
import zlib from 'node:zlib'
|
|
30
|
+
import { _assert } from '@naturalcycles/js-lib/error'
|
|
30
31
|
import type { UnixTimestamp } from '@naturalcycles/js-lib/types'
|
|
31
32
|
import {
|
|
32
33
|
assertSafeZipEntryName,
|
|
@@ -283,12 +284,11 @@ async function readEndOfCentralDirectory(source: ZipSource): Promise<EndOfCentra
|
|
|
283
284
|
if (locatorIndex >= 0 && buf.readUInt32LE(locatorIndex) === ZIP64_EOCDL_SIG) {
|
|
284
285
|
const zip64EocdrOffset = readUInt64LE(buf, locatorIndex + 8)
|
|
285
286
|
const zip64 = await source.read(zip64EocdrOffset, ZIP64_EOCDR_SIZE)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
287
|
+
_assert(
|
|
288
|
+
zip64.readUInt32LE(0) === ZIP64_EOCDR_SIG,
|
|
289
|
+
'invalid zip64 end of central directory record signature',
|
|
290
|
+
)
|
|
291
|
+
_assert(zip64.readUInt32LE(16) === 0, 'multi-disk zip files are not supported')
|
|
292
292
|
entryCount = readUInt64LE(zip64, 32)
|
|
293
293
|
centralDirectoryOffset = readUInt64LE(zip64, 48)
|
|
294
294
|
centralDirectoryEnd = zip64EocdrOffset
|
package/src/zip/zipWriter.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { finished, pipeline } from 'node:stream/promises'
|
|
|
31
31
|
import { promisify } from 'node:util'
|
|
32
32
|
import zlib from 'node:zlib'
|
|
33
33
|
import { comparators } from '@naturalcycles/js-lib/array/sort.js'
|
|
34
|
+
import { _assert } from '@naturalcycles/js-lib/error/assert.js'
|
|
34
35
|
import type { UnixTimestamp } from '@naturalcycles/js-lib/types'
|
|
35
36
|
import { glob } from 'tinyglobby'
|
|
36
37
|
import {
|
|
@@ -250,9 +251,10 @@ export class ZipWriter implements AsyncDisposable {
|
|
|
250
251
|
}
|
|
251
252
|
// A comment containing this signature would confuse readers that scan
|
|
252
253
|
// backwards for the end-of-central-directory record.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
_assert(
|
|
255
|
+
!comment.includes(EOCDR_SIG_BYTES),
|
|
256
|
+
'archive comment must not contain the end-of-central-directory signature',
|
|
257
|
+
)
|
|
256
258
|
this.finalized = true
|
|
257
259
|
|
|
258
260
|
const centralDirectoryOffset = this.offset
|
|
@@ -282,7 +284,7 @@ export class ZipWriter implements AsyncDisposable {
|
|
|
282
284
|
|
|
283
285
|
private assertWritable(): void {
|
|
284
286
|
if (this.streamError) throw this.streamError
|
|
285
|
-
|
|
287
|
+
_assert(!this.finalized, 'ZipWriter has already been finalized')
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
/** Build the in-memory representation of an entry from its name and options. */
|
|
@@ -659,7 +661,7 @@ function buildEndRecords(input: EndRecordsInput): Buffer {
|
|
|
659
661
|
}
|
|
660
662
|
|
|
661
663
|
function normalizeAndValidateEntryName(fileName: string, isDirectory: boolean): string {
|
|
662
|
-
|
|
664
|
+
_assert(fileName, 'zip entry name must not be empty')
|
|
663
665
|
let name = normalizeZipEntryName(fileName)
|
|
664
666
|
if (isDirectory) {
|
|
665
667
|
if (!name.endsWith('/')) name += '/'
|