@naturalcycles/nodejs-lib 12.55.1 → 12.58.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.
Files changed (35) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +3 -3
  3. package/dist/stream/ndjson/ndJsonFileRead.js +1 -1
  4. package/dist/stream/transform/{beta/transformMap2.d.ts → legacy/transformMap.d.ts} +1 -1
  5. package/dist/stream/transform/legacy/transformMap.js +94 -0
  6. package/dist/stream/transform/transformLimit.d.ts +5 -1
  7. package/dist/stream/transform/transformLimit.js +2 -1
  8. package/dist/stream/transform/transformLogProgress.d.ts +2 -1
  9. package/dist/stream/transform/transformLogProgress.js +4 -4
  10. package/dist/stream/transform/transformMap.d.ts +6 -1
  11. package/dist/stream/transform/transformMap.js +62 -48
  12. package/dist/stream/transform/transformMapSimple.d.ts +2 -1
  13. package/dist/stream/transform/transformMapSimple.js +2 -2
  14. package/dist/stream/transform/transformMapSync.d.ts +2 -1
  15. package/dist/stream/transform/transformMapSync.js +3 -3
  16. package/dist/stream/transform/transformTap.d.ts +5 -2
  17. package/dist/stream/transform/transformTap.js +2 -1
  18. package/dist/stream/writable/writableForEach.d.ts +5 -1
  19. package/dist/stream/writable/writableForEach.js +8 -1
  20. package/dist/stream/writable/writableFork.d.ts +2 -0
  21. package/dist/stream/writable/writableFork.js +2 -0
  22. package/package.json +1 -1
  23. package/src/index.ts +1 -2
  24. package/src/stream/ndjson/ndJsonFileRead.ts +2 -2
  25. package/src/stream/transform/legacy/transformMap.ts +133 -0
  26. package/src/stream/transform/transformLimit.ts +8 -2
  27. package/src/stream/transform/transformLogProgress.ts +7 -4
  28. package/src/stream/transform/transformMap.ts +79 -67
  29. package/src/stream/transform/transformMapSimple.ts +5 -3
  30. package/src/stream/transform/transformMapSync.ts +6 -3
  31. package/src/stream/transform/transformTap.ts +8 -3
  32. package/src/stream/writable/writableForEach.ts +12 -2
  33. package/src/stream/writable/writableFork.ts +2 -0
  34. package/dist/stream/transform/beta/transformMap2.js +0 -98
  35. package/src/stream/transform/beta/transformMap2.ts +0 -134
package/dist/index.d.ts CHANGED
@@ -47,7 +47,7 @@ import { transformToString } from './stream/transform/transformToString';
47
47
  import { BaseWorkerClass, WorkerClassInterface } from './stream/transform/worker/baseWorkerClass';
48
48
  import { transformMultiThreaded, TransformMultiThreadedOptions } from './stream/transform/worker/transformMultiThreaded';
49
49
  import { WorkerInput, WorkerOutput } from './stream/transform/worker/transformMultiThreaded.model';
50
- import { writableForEach } from './stream/writable/writableForEach';
50
+ export * from './stream/writable/writableForEach';
51
51
  import { writableFork } from './stream/writable/writableFork';
52
52
  import { writablePushToArray } from './stream/writable/writablePushToArray';
53
53
  import { writableVoid } from './stream/writable/writableVoid';
@@ -67,4 +67,4 @@ import { convert, getValidationResult, isValid, JoiValidationResult, undefinedIf
67
67
  import { sanitizeHTML, SanitizeHTMLOptions } from './validation/sanitize.util';
68
68
  import { runScript, RunScriptOptions } from './script';
69
69
  export type { RunScriptOptions, JoiValidationErrorData, JoiValidationResult, ValidationErrorItem, ExtendedJoi, SchemaTyped, AnySchema, AnySchemaTyped, ArraySchemaTyped, BooleanSchemaTyped, NumberSchemaTyped, ObjectSchemaTyped, StringSchemaTyped, IDebug, IDebugger, SlackServiceCfg, SlackMessage, SlackMessageProps, SlackApiBody, SlackMessagePrefixHook, ReadableTyped, WritableTyped, TransformTyped, PipelineFromNDJsonFileOptions, PipelineToNDJsonFileOptions, TransformJsonParseOptions, TransformToNDJsonOptions, TransformMapOptions, TransformMapSyncOptions, NDJSONStreamForEachOptions, TransformOptions, TransformLogProgressOptions, TransformMultiThreadedOptions, WorkerClassInterface, WorkerInput, WorkerOutput, TableDiffOptions, InspectAnyOptions, Got, GetGotOptions, AfterResponseHook, BeforeErrorHook, BeforeRequestHook, AjvValidationOptions, AjvSchemaCfg, AjvValidationErrorData, SanitizeHTMLOptions, };
70
- export { JoiValidationError, validate, getValidationResult, isValid, undefinedIfInvalid, convert, Joi, booleanSchema, booleanDefaultToFalseSchema, stringSchema, numberSchema, integerSchema, percentageSchema, dateStringSchema, arraySchema, binarySchema, objectSchema, oneOfSchema, anySchema, anyObjectSchema, baseDBEntitySchema, savedDBEntitySchema, idSchema, unixTimestampSchema, verSchema, emailSchema, SEM_VER_PATTERN, semVerSchema, userAgentSchema, utcOffsetSchema, ipAddressSchema, slugSchema, urlSchema, processSharedUtil, zipBuffer, gzipBuffer, unzipBuffer, gunzipBuffer, zipString, gzipString, unzipToString, gunzipToString, requireEnvKeys, requireFileToExist, LRUMemoCache, stringId, stringIdAsync, stringIdUnsafe, ALPHABET_NUMBER, ALPHABET_LOWERCASE, ALPHABET_UPPERCASE, ALPHABET_ALPHANUMERIC_LOWERCASE, ALPHABET_ALPHANUMERIC_UPPERCASE, ALPHABET_ALPHANUMERIC, md5, hash, hashAsBuffer, md5AsBuffer, stringToBase64, base64ToString, bufferToBase64, base64ToBuffer, Debug, getSecretMap, setSecretMap, loadSecretsFromEnv, loadSecretsFromJsonFile, removeSecretsFromEnv, secret, secretOptional, memoryUsage, memoryUsageFull, SlackService, slackDefaultMessagePrefixHook, readableCreate, readableFrom, readableFromArray, readableToArray, readableForEach, readableForEachSync, readableMap, readableMapToArray, _pipeline, transformBuffer, ndjsonMap, ndJsonFileRead, ndJsonFileWrite, ndjsonStreamForEach, pipelineFromNDJsonFile, pipelineToNDJsonFile, NDJsonStats, streamToNDJsonFile, transformJsonParse, bufferReviver, transformToNDJson, transformFilter, transformFilterSync, transformMap, transformMapSync, transformMapSimple, transformNoOp, writableForEach, writablePushToArray, transformSplit, transformToString, transformToArray, transformTap, transformLogProgress, transformLimit, writableVoid, writableFork, transformMultiThreaded, BaseWorkerClass, tableDiff, inspectAny, inspectAnyStringifyFn, getGot, HTTPError, TimeoutError, _chunkBuffer, Ajv, getAjv, AjvSchema, AjvValidationError, readJsonSchemas, readAjvSchemas, hasColors, sanitizeHTML, runScript, };
70
+ export { JoiValidationError, validate, getValidationResult, isValid, undefinedIfInvalid, convert, Joi, booleanSchema, booleanDefaultToFalseSchema, stringSchema, numberSchema, integerSchema, percentageSchema, dateStringSchema, arraySchema, binarySchema, objectSchema, oneOfSchema, anySchema, anyObjectSchema, baseDBEntitySchema, savedDBEntitySchema, idSchema, unixTimestampSchema, verSchema, emailSchema, SEM_VER_PATTERN, semVerSchema, userAgentSchema, utcOffsetSchema, ipAddressSchema, slugSchema, urlSchema, processSharedUtil, zipBuffer, gzipBuffer, unzipBuffer, gunzipBuffer, zipString, gzipString, unzipToString, gunzipToString, requireEnvKeys, requireFileToExist, LRUMemoCache, stringId, stringIdAsync, stringIdUnsafe, ALPHABET_NUMBER, ALPHABET_LOWERCASE, ALPHABET_UPPERCASE, ALPHABET_ALPHANUMERIC_LOWERCASE, ALPHABET_ALPHANUMERIC_UPPERCASE, ALPHABET_ALPHANUMERIC, md5, hash, hashAsBuffer, md5AsBuffer, stringToBase64, base64ToString, bufferToBase64, base64ToBuffer, Debug, getSecretMap, setSecretMap, loadSecretsFromEnv, loadSecretsFromJsonFile, removeSecretsFromEnv, secret, secretOptional, memoryUsage, memoryUsageFull, SlackService, slackDefaultMessagePrefixHook, readableCreate, readableFrom, readableFromArray, readableToArray, readableForEach, readableForEachSync, readableMap, readableMapToArray, _pipeline, transformBuffer, ndjsonMap, ndJsonFileRead, ndJsonFileWrite, ndjsonStreamForEach, pipelineFromNDJsonFile, pipelineToNDJsonFile, NDJsonStats, streamToNDJsonFile, transformJsonParse, bufferReviver, transformToNDJson, transformFilter, transformFilterSync, transformMap, transformMapSync, transformMapSimple, transformNoOp, writablePushToArray, transformSplit, transformToString, transformToArray, transformTap, transformLogProgress, transformLimit, writableVoid, writableFork, transformMultiThreaded, BaseWorkerClass, tableDiff, inspectAny, inspectAnyStringifyFn, getGot, HTTPError, TimeoutError, _chunkBuffer, Ajv, getAjv, AjvSchema, AjvValidationError, readJsonSchemas, readAjvSchemas, hasColors, sanitizeHTML, runScript, };
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ALPHABET_LOWERCASE = exports.ALPHABET_NUMBER = exports.stringIdUnsafe = exports.stringIdAsync = exports.stringId = exports.LRUMemoCache = exports.requireFileToExist = exports.requireEnvKeys = exports.gunzipToString = exports.unzipToString = exports.gzipString = exports.zipString = exports.gunzipBuffer = exports.unzipBuffer = exports.gzipBuffer = exports.zipBuffer = exports.processSharedUtil = exports.urlSchema = exports.slugSchema = exports.ipAddressSchema = exports.utcOffsetSchema = exports.userAgentSchema = exports.semVerSchema = exports.SEM_VER_PATTERN = exports.emailSchema = exports.verSchema = exports.unixTimestampSchema = exports.idSchema = exports.savedDBEntitySchema = exports.baseDBEntitySchema = exports.anyObjectSchema = exports.anySchema = exports.oneOfSchema = exports.objectSchema = exports.binarySchema = exports.arraySchema = exports.dateStringSchema = exports.percentageSchema = exports.integerSchema = exports.numberSchema = exports.stringSchema = exports.booleanDefaultToFalseSchema = exports.booleanSchema = exports.Joi = exports.convert = exports.undefinedIfInvalid = exports.isValid = exports.getValidationResult = exports.validate = exports.JoiValidationError = void 0;
4
4
  exports.transformMapSimple = exports.transformMapSync = exports.transformMap = exports.transformFilterSync = exports.transformFilter = exports.transformToNDJson = exports.bufferReviver = exports.transformJsonParse = exports.streamToNDJsonFile = exports.NDJsonStats = exports.pipelineToNDJsonFile = exports.pipelineFromNDJsonFile = exports.ndjsonStreamForEach = exports.ndJsonFileWrite = exports.ndJsonFileRead = exports.ndjsonMap = exports.transformBuffer = exports._pipeline = exports.readableMapToArray = exports.readableMap = exports.readableForEachSync = exports.readableForEach = exports.readableToArray = exports.readableFromArray = exports.readableFrom = exports.readableCreate = exports.slackDefaultMessagePrefixHook = exports.SlackService = exports.memoryUsageFull = exports.memoryUsage = exports.secretOptional = exports.secret = exports.removeSecretsFromEnv = exports.loadSecretsFromJsonFile = exports.loadSecretsFromEnv = exports.setSecretMap = exports.getSecretMap = exports.Debug = exports.base64ToBuffer = exports.bufferToBase64 = exports.base64ToString = exports.stringToBase64 = exports.md5AsBuffer = exports.hashAsBuffer = exports.hash = exports.md5 = exports.ALPHABET_ALPHANUMERIC = exports.ALPHABET_ALPHANUMERIC_UPPERCASE = exports.ALPHABET_ALPHANUMERIC_LOWERCASE = exports.ALPHABET_UPPERCASE = void 0;
5
- exports.runScript = exports.sanitizeHTML = exports.hasColors = exports.readAjvSchemas = exports.readJsonSchemas = exports.AjvValidationError = exports.AjvSchema = exports.getAjv = exports.Ajv = exports._chunkBuffer = exports.TimeoutError = exports.HTTPError = exports.getGot = exports.inspectAnyStringifyFn = exports.inspectAny = exports.tableDiff = exports.BaseWorkerClass = exports.transformMultiThreaded = exports.writableFork = exports.writableVoid = exports.transformLimit = exports.transformLogProgress = exports.transformTap = exports.transformToArray = exports.transformToString = exports.transformSplit = exports.writablePushToArray = exports.writableForEach = exports.transformNoOp = void 0;
5
+ exports.runScript = exports.sanitizeHTML = exports.hasColors = exports.readAjvSchemas = exports.readJsonSchemas = exports.AjvValidationError = exports.AjvSchema = exports.getAjv = exports.Ajv = exports._chunkBuffer = exports.TimeoutError = exports.HTTPError = exports.getGot = exports.inspectAnyStringifyFn = exports.inspectAny = exports.tableDiff = exports.BaseWorkerClass = exports.transformMultiThreaded = exports.writableFork = exports.writableVoid = exports.transformLimit = exports.transformLogProgress = exports.transformTap = exports.transformToArray = exports.transformToString = exports.transformSplit = exports.writablePushToArray = exports.transformNoOp = void 0;
6
+ const tslib_1 = require("tslib");
6
7
  const ajv_1 = require("ajv");
7
8
  exports.Ajv = ajv_1.default;
8
9
  const got_1 = require("got");
@@ -118,8 +119,7 @@ const baseWorkerClass_1 = require("./stream/transform/worker/baseWorkerClass");
118
119
  Object.defineProperty(exports, "BaseWorkerClass", { enumerable: true, get: function () { return baseWorkerClass_1.BaseWorkerClass; } });
119
120
  const transformMultiThreaded_1 = require("./stream/transform/worker/transformMultiThreaded");
120
121
  Object.defineProperty(exports, "transformMultiThreaded", { enumerable: true, get: function () { return transformMultiThreaded_1.transformMultiThreaded; } });
121
- const writableForEach_1 = require("./stream/writable/writableForEach");
122
- Object.defineProperty(exports, "writableForEach", { enumerable: true, get: function () { return writableForEach_1.writableForEach; } });
122
+ (0, tslib_1.__exportStar)(require("./stream/writable/writableForEach"), exports);
123
123
  const writableFork_1 = require("./stream/writable/writableFork");
124
124
  Object.defineProperty(exports, "writableFork", { enumerable: true, get: function () { return writableFork_1.writableFork; } });
125
125
  const writablePushToArray_1 = require("./stream/writable/writablePushToArray");
@@ -8,7 +8,7 @@ const pipelineFromNDJsonFile_1 = require("./pipelineFromNDJsonFile");
8
8
  */
9
9
  async function ndJsonFileRead(opt) {
10
10
  const res = [];
11
- await (0, pipelineFromNDJsonFile_1.pipelineFromNDJsonFile)([(0, __1.writableForEach)(r => void res.push(r))], opt);
11
+ await (0, pipelineFromNDJsonFile_1.pipelineFromNDJsonFile)([(0, __1.writablePushToArray)(res)], opt);
12
12
  return res;
13
13
  }
14
14
  exports.ndJsonFileRead = ndJsonFileRead;
@@ -14,4 +14,4 @@ export declare function notNullishPredicate(item: any): boolean;
14
14
  *
15
15
  * If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
16
16
  */
17
- export declare function transformMap2<IN = any, OUT = IN>(mapper: AsyncMapper<IN, OUT>, opt?: TransformMapOptions<IN, OUT>): TransformTyped<IN, OUT>;
17
+ export declare function transformMapLegacy<IN = any, OUT = IN>(mapper: AsyncMapper<IN, OUT>, opt?: TransformMapOptions<IN, OUT>): TransformTyped<IN, OUT>;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformMapLegacy = exports.notNullishPredicate = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
+ const through2Concurrent = require("through2-concurrent");
6
+ const colors_1 = require("../../../colors");
7
+ function notNullishPredicate(item) {
8
+ return item !== undefined && item !== null;
9
+ }
10
+ exports.notNullishPredicate = notNullishPredicate;
11
+ /**
12
+ * Like pMap, but for streams.
13
+ * Inspired by `through2`.
14
+ * Main feature is concurrency control (implemented via `through2-concurrent`) and convenient options.
15
+ * Using this allows native stream .pipe() to work and use backpressure.
16
+ *
17
+ * Only works in objectMode (due to through2Concurrent).
18
+ *
19
+ * Concurrency defaults to 16.
20
+ *
21
+ * If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
22
+ */
23
+ function transformMapLegacy(mapper, opt = {}) {
24
+ const { concurrency = 16, predicate = notNullishPredicate, errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput, onError, beforeFinal, metric = 'stream', logger = console, } = opt;
25
+ let index = -1;
26
+ let isRejected = false;
27
+ let errors = 0;
28
+ const collectedErrors = []; // only used if errorMode == THROW_AGGREGATED
29
+ return through2Concurrent.obj({
30
+ maxConcurrency: concurrency,
31
+ // autoDestroy: true,
32
+ async final(cb) {
33
+ // console.log('transformMap final')
34
+ logErrorStats(logger, true);
35
+ await beforeFinal?.(); // call beforeFinal if defined
36
+ if (collectedErrors.length) {
37
+ // emit Aggregated error
38
+ cb(new js_lib_1.AggregatedError(collectedErrors));
39
+ }
40
+ else {
41
+ // emit no error
42
+ cb();
43
+ }
44
+ },
45
+ }, async function transformMapFn(chunk, _encoding, cb) {
46
+ index++;
47
+ // console.log({chunk, _encoding})
48
+ // Stop processing if THROW_IMMEDIATELY mode is used
49
+ if (isRejected && errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY)
50
+ return cb();
51
+ try {
52
+ const currentIndex = index; // because we need to pass it to 2 functions - mapper and predicate. Refers to INPUT index (since it may return multiple outputs)
53
+ const res = await mapper(chunk, currentIndex);
54
+ const passedResults = await (0, js_lib_1.pFilter)(flattenArrayOutput && Array.isArray(res) ? res : [res], async (r) => await predicate(r, currentIndex));
55
+ if (passedResults.length === 0) {
56
+ cb(); // 0 results
57
+ }
58
+ else {
59
+ passedResults.forEach(r => {
60
+ this.push(r);
61
+ // cb(null, r)
62
+ });
63
+ cb(); // done processing
64
+ }
65
+ }
66
+ catch (err) {
67
+ logger.error(err);
68
+ errors++;
69
+ logErrorStats(logger);
70
+ if (onError) {
71
+ try {
72
+ onError(err, chunk);
73
+ }
74
+ catch { }
75
+ }
76
+ if (errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY) {
77
+ isRejected = true;
78
+ // Emit error immediately
79
+ return cb(err);
80
+ }
81
+ if (errorMode === js_lib_1.ErrorMode.THROW_AGGREGATED) {
82
+ collectedErrors.push(err);
83
+ }
84
+ // Tell input stream that we're done processing, but emit nothing to output - not error nor result
85
+ cb();
86
+ }
87
+ });
88
+ function logErrorStats(logger, final = false) {
89
+ if (!errors)
90
+ return;
91
+ logger.log(`${metric} ${final ? 'final ' : ''}errors: ${(0, colors_1.yellow)(errors)}`);
92
+ }
93
+ }
94
+ exports.transformMapLegacy = transformMapLegacy;
@@ -1,5 +1,9 @@
1
+ import { CommonLogger } from '@naturalcycles/js-lib';
1
2
  import { TransformOptions, TransformTyped } from '../stream.model';
3
+ export interface TransformLimitOptions extends TransformOptions {
4
+ logger?: CommonLogger;
5
+ }
2
6
  /**
3
7
  * 0 or falsy value means "no limit"
4
8
  */
5
- export declare function transformLimit<IN>(limit?: number, opt?: TransformOptions): TransformTyped<IN, IN>;
9
+ export declare function transformLimit<IN>(limit?: number, opt?: TransformLimitOptions): TransformTyped<IN, IN>;
@@ -6,6 +6,7 @@ const stream_1 = require("stream");
6
6
  * 0 or falsy value means "no limit"
7
7
  */
8
8
  function transformLimit(limit, opt = {}) {
9
+ const { logger = console } = opt;
9
10
  let index = 0;
10
11
  let ended = false;
11
12
  return new stream_1.Transform({
@@ -21,7 +22,7 @@ function transformLimit(limit, opt = {}) {
21
22
  }
22
23
  if (limit && index === limit) {
23
24
  ended = true;
24
- console.log(`transformLimit: limit of ${limit} reached`);
25
+ logger.log(`transformLimit: limit of ${limit} reached`);
25
26
  // this.emit('end') // this makes it "halt" on Node 14 lts
26
27
  }
27
28
  },
@@ -1,4 +1,4 @@
1
- import { AnyObject } from '@naturalcycles/js-lib';
1
+ import { AnyObject, CommonLogger } from '@naturalcycles/js-lib';
2
2
  import { TransformOptions, TransformTyped } from '../stream.model';
3
3
  export interface TransformLogProgressOptions<IN = any> extends TransformOptions {
4
4
  /**
@@ -69,6 +69,7 @@ export interface TransformLogProgressOptions<IN = any> extends TransformOptions
69
69
  * @default 1000
70
70
  */
71
71
  logEvery?: number;
72
+ logger?: CommonLogger;
72
73
  /**
73
74
  * Function to return extra properties to the "progress object".
74
75
  *
@@ -15,7 +15,7 @@ const inspectOpt = {
15
15
  * Pass-through transform that optionally logs progress.
16
16
  */
17
17
  function transformLogProgress(opt = {}) {
18
- const { metric = 'progress', heapTotal: logHeapTotal = false, heapUsed: logHeapUsed = false, rss: logRss = true, peakRSS: logPeakRSS = true, logRPS = true, logEvery = 1000, batchSize = 1, extra, } = opt;
18
+ const { metric = 'progress', heapTotal: logHeapTotal = false, heapUsed: logHeapUsed = false, rss: logRss = true, peakRSS: logPeakRSS = true, logRPS = true, logEvery = 1000, batchSize = 1, extra, logger = console, } = opt;
19
19
  const logProgress = opt.logProgress !== false && logEvery !== 0; // true by default
20
20
  const logEvery10 = logEvery * 10;
21
21
  const started = Date.now();
@@ -54,7 +54,7 @@ function transformLogProgress(opt = {}) {
54
54
  const rps10 = Math.round(sma.push(lastRPS));
55
55
  if (mem.rss > peakRSS)
56
56
  peakRSS = mem.rss;
57
- console.log((0, util_1.inspect)({
57
+ logger.log((0, util_1.inspect)({
58
58
  [final ? `${metric}_final` : metric]: batchedProgress,
59
59
  ...(extra ? extra(chunk, progress) : {}),
60
60
  ...(logHeapUsed ? { heapUsed: (0, js_lib_1._mb)(mem.heapUsed) } : {}),
@@ -76,10 +76,10 @@ function transformLogProgress(opt = {}) {
76
76
  if (perHour > 900) {
77
77
  perHour = Math.round(perHour / 1000) + 'K';
78
78
  }
79
- console.log(`${(0, colors_1.dimGrey)((0, time_lib_1.dayjs)().toPretty())} ${(0, colors_1.white)(metric)} took ${(0, colors_1.yellow)((0, js_lib_1._since)(started))} so far to process ${(0, colors_1.yellow)(batchedProgress)} rows, ~${(0, colors_1.yellow)(perHour)}/hour`);
79
+ logger.log(`${(0, colors_1.dimGrey)((0, time_lib_1.dayjs)().toPretty())} ${(0, colors_1.white)(metric)} took ${(0, colors_1.yellow)((0, js_lib_1._since)(started))} so far to process ${(0, colors_1.yellow)(batchedProgress)} rows, ~${(0, colors_1.yellow)(perHour)}/hour`);
80
80
  }
81
81
  else if (final) {
82
- console.log(`${(0, colors_1.boldWhite)(metric)} took ${(0, colors_1.yellow)((0, js_lib_1._since)(started))} to process ${(0, colors_1.yellow)(batchedProgress)} rows with total RPS of ${(0, colors_1.yellow)(rpsTotal)}`);
82
+ logger.log(`${(0, colors_1.boldWhite)(metric)} took ${(0, colors_1.yellow)((0, js_lib_1._since)(started))} to process ${(0, colors_1.yellow)(batchedProgress)} rows with total RPS of ${(0, colors_1.yellow)(rpsTotal)}`);
83
83
  }
84
84
  }
85
85
  }
@@ -1,5 +1,6 @@
1
1
  import { AsyncMapper, AsyncPredicate, CommonLogger, ErrorMode } from '@naturalcycles/js-lib';
2
2
  import { TransformTyped } from '../stream.model';
3
+ import { transformMapLegacy } from './legacy/transformMap';
3
4
  export interface TransformMapOptions<IN = any, OUT = IN> {
4
5
  /**
5
6
  * Set true to support "multiMap" - possibility to return [] and emit 1 result for each item in the array.
@@ -44,6 +45,10 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
44
45
  logger?: CommonLogger;
45
46
  }
46
47
  export declare function notNullishPredicate(item: any): boolean;
48
+ /**
49
+ * Temporary export legacy transformMap, to debug 503 errors
50
+ */
51
+ export declare const transformMap: typeof transformMapLegacy;
47
52
  /**
48
53
  * Like pMap, but for streams.
49
54
  * Inspired by `through2`.
@@ -56,4 +61,4 @@ export declare function notNullishPredicate(item: any): boolean;
56
61
  *
57
62
  * If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
58
63
  */
59
- export declare function transformMap<IN = any, OUT = IN>(mapper: AsyncMapper<IN, OUT>, opt?: TransformMapOptions<IN, OUT>): TransformTyped<IN, OUT>;
64
+ export declare function transformMapNew<IN = any, OUT = IN>(mapper: AsyncMapper<IN, OUT>, opt?: TransformMapOptions<IN, OUT>): TransformTyped<IN, OUT>;
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformMap = exports.notNullishPredicate = void 0;
3
+ exports.transformMapNew = exports.transformMap = exports.notNullishPredicate = void 0;
4
+ const stream_1 = require("stream");
4
5
  const js_lib_1 = require("@naturalcycles/js-lib");
5
- const through2Concurrent = require("through2-concurrent");
6
6
  const colors_1 = require("../../colors");
7
+ const transformMap_1 = require("./legacy/transformMap");
7
8
  function notNullishPredicate(item) {
8
9
  return item !== undefined && item !== null;
9
10
  }
10
11
  exports.notNullishPredicate = notNullishPredicate;
12
+ /**
13
+ * Temporary export legacy transformMap, to debug 503 errors
14
+ */
15
+ exports.transformMap = transformMap_1.transformMapLegacy;
11
16
  /**
12
17
  * Like pMap, but for streams.
13
18
  * Inspired by `through2`.
@@ -20,70 +25,79 @@ exports.notNullishPredicate = notNullishPredicate;
20
25
  *
21
26
  * If an Array is returned by `mapper` - it will be flattened and multiple results will be emitted from it. Tested by Array.isArray().
22
27
  */
23
- function transformMap(mapper, opt = {}) {
28
+ function transformMapNew(mapper, opt = {}) {
24
29
  const { concurrency = 16, predicate = notNullishPredicate, errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput, onError, beforeFinal, metric = 'stream', logger = console, } = opt;
25
30
  let index = -1;
26
31
  let isRejected = false;
27
32
  let errors = 0;
28
33
  const collectedErrors = []; // only used if errorMode == THROW_AGGREGATED
29
- return through2Concurrent.obj({
30
- maxConcurrency: concurrency,
31
- // autoDestroy: true,
34
+ const q = new js_lib_1.PQueue({
35
+ concurrency,
36
+ resolveOn: 'start',
37
+ // debug: true,
38
+ });
39
+ return new stream_1.Transform({
40
+ objectMode: true,
32
41
  async final(cb) {
33
- // console.log('transformMap final')
42
+ // console.log('transformMap final', {index}, q.inFlight, q.queueSize)
43
+ // wait for the current inFlight jobs to complete and push their results
44
+ await q.onIdle();
34
45
  logErrorStats(logger, true);
35
46
  await beforeFinal?.(); // call beforeFinal if defined
36
47
  if (collectedErrors.length) {
37
48
  // emit Aggregated error
49
+ // For the same reason, magically, let's not call `cb`, but emit an error event instead
50
+ // this.emit('error', new AggregatedError(collectedErrors))
38
51
  cb(new js_lib_1.AggregatedError(collectedErrors));
39
52
  }
40
53
  else {
41
54
  // emit no error
42
- cb();
55
+ // It is truly a mistery, but calling cb() here was causing ERR_MULTIPLE_CALLBACK ?!
56
+ // Commenting it out seems to work ?!
57
+ // ?!
58
+ // cb()
43
59
  }
44
60
  },
45
- }, async function transformMapFn(chunk, _encoding, cb) {
46
- index++;
47
- // console.log({chunk, _encoding})
48
- // Stop processing if THROW_IMMEDIATELY mode is used
49
- if (isRejected && errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY)
50
- return cb();
51
- try {
52
- const currentIndex = index; // because we need to pass it to 2 functions - mapper and predicate. Refers to INPUT index (since it may return multiple outputs)
53
- const res = await mapper(chunk, currentIndex);
54
- const passedResults = await (0, js_lib_1.pFilter)(flattenArrayOutput && Array.isArray(res) ? res : [res], async (r) => await predicate(r, currentIndex));
55
- if (passedResults.length === 0) {
56
- cb(); // 0 results
57
- }
58
- else {
59
- passedResults.forEach(r => {
60
- this.push(r);
61
- // cb(null, r)
62
- });
63
- cb(); // done processing
64
- }
65
- }
66
- catch (err) {
67
- logger.error(err);
68
- errors++;
69
- logErrorStats(logger);
70
- if (onError) {
61
+ async transform(chunk, _encoding, cb) {
62
+ index++;
63
+ // console.log('transform', {index})
64
+ // Stop processing if THROW_IMMEDIATELY mode is used
65
+ if (isRejected && errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY)
66
+ return cb();
67
+ // It resolves when it is successfully STARTED execution.
68
+ // If it's queued instead - it'll wait and resolve only upon START.
69
+ await q.push(async () => {
71
70
  try {
72
- onError(err, chunk);
71
+ const currentIndex = index; // because we need to pass it to 2 functions - mapper and predicate. Refers to INPUT index (since it may return multiple outputs)
72
+ const res = await mapper(chunk, currentIndex);
73
+ const passedResults = await (0, js_lib_1.pFilter)(flattenArrayOutput && Array.isArray(res) ? res : [res], async (r) => await predicate(r, currentIndex));
74
+ passedResults.forEach(r => this.push(r));
73
75
  }
74
- catch { }
75
- }
76
- if (errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY) {
77
- isRejected = true;
78
- // Emit error immediately
79
- return cb(err);
80
- }
81
- if (errorMode === js_lib_1.ErrorMode.THROW_AGGREGATED) {
82
- collectedErrors.push(err);
83
- }
84
- // Tell input stream that we're done processing, but emit nothing to output - not error nor result
76
+ catch (err) {
77
+ logger.error(err);
78
+ errors++;
79
+ logErrorStats(logger);
80
+ if (onError) {
81
+ try {
82
+ onError(err, chunk);
83
+ }
84
+ catch { }
85
+ }
86
+ if (errorMode === js_lib_1.ErrorMode.THROW_IMMEDIATELY) {
87
+ isRejected = true;
88
+ // Emit error immediately
89
+ // return cb(err as Error)
90
+ return this.emit('error', err);
91
+ }
92
+ if (errorMode === js_lib_1.ErrorMode.THROW_AGGREGATED) {
93
+ collectedErrors.push(err);
94
+ }
95
+ }
96
+ });
97
+ // Resolved, which means it STARTED processing
98
+ // This means we can take more load
85
99
  cb();
86
- }
100
+ },
87
101
  });
88
102
  function logErrorStats(logger, final = false) {
89
103
  if (!errors)
@@ -91,4 +105,4 @@ function transformMap(mapper, opt = {}) {
91
105
  logger.log(`${metric} ${final ? 'final ' : ''}errors: ${(0, colors_1.yellow)(errors)}`);
92
106
  }
93
107
  }
94
- exports.transformMap = transformMap;
108
+ exports.transformMapNew = transformMapNew;
@@ -1,4 +1,4 @@
1
- import { ErrorMode, Mapper } from '@naturalcycles/js-lib';
1
+ import { CommonLogger, ErrorMode, Mapper } from '@naturalcycles/js-lib';
2
2
  import { TransformTyped } from '../stream.model';
3
3
  export interface TransformMapSimpleOptions {
4
4
  /**
@@ -7,6 +7,7 @@ export interface TransformMapSimpleOptions {
7
7
  * @default ErrorMode.THROW_IMMEDIATELY
8
8
  */
9
9
  errorMode?: ErrorMode.THROW_IMMEDIATELY | ErrorMode.SUPPRESS;
10
+ logger?: CommonLogger;
10
11
  }
11
12
  /**
12
13
  * Simplest version of `transformMap`.
@@ -14,7 +14,7 @@ const js_lib_1 = require("@naturalcycles/js-lib");
14
14
  */
15
15
  function transformMapSimple(mapper, opt = {}) {
16
16
  let index = -1;
17
- const { errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY } = opt;
17
+ const { errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, logger = console } = opt;
18
18
  return new stream_1.Transform({
19
19
  objectMode: true,
20
20
  transform(chunk, _encoding, cb) {
@@ -22,7 +22,7 @@ function transformMapSimple(mapper, opt = {}) {
22
22
  cb(null, mapper(chunk, ++index));
23
23
  }
24
24
  catch (err) {
25
- console.error(err);
25
+ logger.error(err);
26
26
  if (errorMode === js_lib_1.ErrorMode.SUPPRESS) {
27
27
  cb(); // suppress the error
28
28
  }
@@ -1,4 +1,4 @@
1
- import { ErrorMode, Mapper, Predicate } from '@naturalcycles/js-lib';
1
+ import { CommonLogger, ErrorMode, Mapper, Predicate } from '@naturalcycles/js-lib';
2
2
  import { TransformTyped } from '../stream.model';
3
3
  export interface TransformMapSyncOptions<IN = any, OUT = IN> {
4
4
  /**
@@ -34,6 +34,7 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
34
34
  * @default `stream`
35
35
  */
36
36
  metric?: string;
37
+ logger?: CommonLogger;
37
38
  }
38
39
  /**
39
40
  * Sync (not async) version of transformMap.
@@ -11,7 +11,7 @@ const transformMap_1 = require("./transformMap");
11
11
  */
12
12
  function transformMapSync(mapper, opt = {}) {
13
13
  let index = -1;
14
- const { predicate = transformMap_1.notNullishPredicate, errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput = false, onError, metric = 'stream', objectMode = true, } = opt;
14
+ const { predicate = transformMap_1.notNullishPredicate, errorMode = js_lib_1.ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput = false, onError, metric = 'stream', objectMode = true, logger = console, } = opt;
15
15
  let isRejected = false;
16
16
  let errors = 0;
17
17
  const collectedErrors = []; // only used if errorMode == THROW_AGGREGATED
@@ -39,7 +39,7 @@ function transformMapSync(mapper, opt = {}) {
39
39
  }
40
40
  }
41
41
  catch (err) {
42
- console.error(err);
42
+ logger.error(err);
43
43
  errors++;
44
44
  logErrorStats();
45
45
  if (onError) {
@@ -75,7 +75,7 @@ function transformMapSync(mapper, opt = {}) {
75
75
  function logErrorStats(final = false) {
76
76
  if (!errors)
77
77
  return;
78
- console.log(`${metric} ${final ? 'final ' : ''}errors: ${(0, colors_1.yellow)(errors)}`);
78
+ logger.log(`${metric} ${final ? 'final ' : ''}errors: ${(0, colors_1.yellow)(errors)}`);
79
79
  }
80
80
  }
81
81
  exports.transformMapSync = transformMapSync;
@@ -1,9 +1,12 @@
1
- import { AsyncMapper } from '@naturalcycles/js-lib';
1
+ import { AsyncMapper, CommonLogger } from '@naturalcycles/js-lib';
2
2
  import { TransformOptions, TransformTyped } from '../stream.model';
3
+ export interface TransformTapOptions extends TransformOptions {
4
+ logger?: CommonLogger;
5
+ }
3
6
  /**
4
7
  * Similar to RxJS `tap` - allows to run a function for each stream item, without affecting the result.
5
8
  * Item is passed through to the output.
6
9
  *
7
10
  * Can also act as a counter, since `index` is passed to `fn`
8
11
  */
9
- export declare function transformTap<IN>(fn: AsyncMapper<IN, any>, opt?: TransformOptions): TransformTyped<IN, IN>;
12
+ export declare function transformTap<IN>(fn: AsyncMapper<IN, any>, opt?: TransformTapOptions): TransformTyped<IN, IN>;
@@ -9,6 +9,7 @@ const stream_1 = require("stream");
9
9
  * Can also act as a counter, since `index` is passed to `fn`
10
10
  */
11
11
  function transformTap(fn, opt = {}) {
12
+ const { logger = console } = opt;
12
13
  let index = 0;
13
14
  return new stream_1.Transform({
14
15
  objectMode: true,
@@ -19,7 +20,7 @@ function transformTap(fn, opt = {}) {
19
20
  await fn(chunk, index++);
20
21
  }
21
22
  catch (err) {
22
- console.error(err);
23
+ logger.error(err);
23
24
  // suppressed error
24
25
  }
25
26
  cb(null, chunk); // pass through the item
@@ -1,7 +1,11 @@
1
- import { AsyncMapper } from '@naturalcycles/js-lib';
1
+ import { AsyncMapper, Mapper } from '@naturalcycles/js-lib';
2
2
  import { TransformMapOptions } from '../..';
3
3
  import { WritableTyped } from '../stream.model';
4
4
  /**
5
5
  * Just an alias to transformMap that declares OUT as void.
6
6
  */
7
7
  export declare function writableForEach<IN = any>(mapper: AsyncMapper<IN, void>, opt?: TransformMapOptions<IN, void>): WritableTyped<IN>;
8
+ /**
9
+ * Just an alias to transformMap that declares OUT as void.
10
+ */
11
+ export declare function writableForEachSync<IN = any>(mapper: Mapper<IN, void>, opt?: TransformMapOptions<IN, void>): WritableTyped<IN>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writableForEach = void 0;
3
+ exports.writableForEachSync = exports.writableForEach = void 0;
4
4
  const js_lib_1 = require("@naturalcycles/js-lib");
5
5
  const __1 = require("../..");
6
6
  /**
@@ -10,3 +10,10 @@ function writableForEach(mapper, opt = {}) {
10
10
  return (0, __1.transformMap)(mapper, { ...opt, predicate: js_lib_1._passNothingPredicate });
11
11
  }
12
12
  exports.writableForEach = writableForEach;
13
+ /**
14
+ * Just an alias to transformMap that declares OUT as void.
15
+ */
16
+ function writableForEachSync(mapper, opt = {}) {
17
+ return (0, __1.transformMapSync)(mapper, { ...opt, predicate: js_lib_1._passNothingPredicate });
18
+ }
19
+ exports.writableForEachSync = writableForEachSync;
@@ -5,5 +5,7 @@ import { TransformOptions, WritableTyped } from '../stream.model';
5
5
  * Currently does NOT (!) maintain backpressure.
6
6
  * Error in the forked pipeline will propagate up to the main pipeline (and log error, to be sure).
7
7
  * Will wait until all forked pipelines are completed before completing the stream.
8
+ *
9
+ * @experimental
8
10
  */
9
11
  export declare function writableFork<T>(chains: NodeJS.WritableStream[][], opt?: TransformOptions): WritableTyped<T>;
@@ -8,6 +8,8 @@ const __1 = require("../..");
8
8
  * Currently does NOT (!) maintain backpressure.
9
9
  * Error in the forked pipeline will propagate up to the main pipeline (and log error, to be sure).
10
10
  * Will wait until all forked pipelines are completed before completing the stream.
11
+ *
12
+ * @experimental
11
13
  */
12
14
  function writableFork(chains, opt) {
13
15
  const readables = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.55.1",
3
+ "version": "12.58.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
package/src/index.ts CHANGED
@@ -104,7 +104,7 @@ import {
104
104
  TransformMultiThreadedOptions,
105
105
  } from './stream/transform/worker/transformMultiThreaded'
106
106
  import { WorkerInput, WorkerOutput } from './stream/transform/worker/transformMultiThreaded.model'
107
- import { writableForEach } from './stream/writable/writableForEach'
107
+ export * from './stream/writable/writableForEach'
108
108
  import { writableFork } from './stream/writable/writableFork'
109
109
  import { writablePushToArray } from './stream/writable/writablePushToArray'
110
110
  import { writableVoid } from './stream/writable/writableVoid'
@@ -327,7 +327,6 @@ export {
327
327
  transformMapSync,
328
328
  transformMapSimple,
329
329
  transformNoOp,
330
- writableForEach,
331
330
  writablePushToArray,
332
331
  transformSplit,
333
332
  transformToString,
@@ -1,4 +1,4 @@
1
- import { writableForEach } from '../..'
1
+ import { writablePushToArray } from '../..'
2
2
  import { pipelineFromNDJsonFile, PipelineFromNDJsonFileOptions } from './pipelineFromNDJsonFile'
3
3
 
4
4
  /**
@@ -9,7 +9,7 @@ export async function ndJsonFileRead<OUT = any>(
9
9
  ): Promise<OUT[]> {
10
10
  const res: OUT[] = []
11
11
 
12
- await pipelineFromNDJsonFile([writableForEach(r => void res.push(r))], opt)
12
+ await pipelineFromNDJsonFile([writablePushToArray(res)], opt)
13
13
 
14
14
  return res
15
15
  }