@openforis/arena-core 2.16.9 → 2.16.11
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/esm/utils/_objects/difference.js +4 -9
- package/dist/esm/utils/_objects/difference.js.map +1 -1
- package/dist/esm/utils/_objects/fromPairs.js +1 -1
- package/dist/esm/utils/_objects/fromPairs.js.map +1 -1
- package/dist/esm/utils/_objects/toPairs.js +1 -1
- package/dist/esm/utils/_objects/toPairs.js.map +1 -1
- package/dist/esm/utils/fileProcessor.js +28 -1
- package/dist/esm/utils/fileProcessor.js.map +1 -1
- package/dist/esm/utils/retryProcessor.js +1 -0
- package/dist/esm/utils/retryProcessor.js.map +1 -1
- package/dist/utils/_objects/difference.d.ts +3 -0
- package/dist/utils/_objects/difference.js +4 -12
- package/dist/utils/_objects/difference.js.map +1 -1
- package/dist/utils/_objects/fromPairs.d.ts +1 -1
- package/dist/utils/_objects/fromPairs.js +2 -5
- package/dist/utils/_objects/fromPairs.js.map +1 -1
- package/dist/utils/_objects/index.d.ts +4 -8
- package/dist/utils/_objects/toPairs.d.ts +1 -1
- package/dist/utils/_objects/toPairs.js +2 -5
- package/dist/utils/_objects/toPairs.js.map +1 -1
- package/dist/utils/fileProcessor.d.ts +3 -0
- package/dist/utils/fileProcessor.js +28 -1
- package/dist/utils/fileProcessor.js.map +1 -1
- package/dist/utils/retryProcessor.js +1 -0
- package/dist/utils/retryProcessor.js.map +1 -1
- package/package.json +1 -7
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import differenceWith from 'lodash.differencewith';
|
|
2
1
|
import { isEqual } from './isEqual';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const pairsObject = toPairs(object);
|
|
8
|
-
const pairsDifference = differenceWith(pairsOther, pairsObject, isEqual);
|
|
9
|
-
return fromPairs(pairsDifference);
|
|
10
|
-
};
|
|
2
|
+
/**
|
|
3
|
+
* Returns the props of otherObject missing in object or with a different value.
|
|
4
|
+
*/
|
|
5
|
+
export const difference = (object, otherObject) => Object.fromEntries(Object.entries(otherObject !== null && otherObject !== void 0 ? otherObject : {}).filter(([key, value]) => !(object && Object.prototype.hasOwnProperty.call(object, key) && isEqual(object[key], value))));
|
|
11
6
|
//# sourceMappingURL=difference.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"difference.js","sourceRoot":"","sources":["../../../../src/utils/_objects/difference.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"difference.js","sourceRoot":"","sources":["../../../../src/utils/_objects/difference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAW,EAAE,WAAgB,EAAoB,EAAE,CAC5E,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,EAAE,CAAC,CAAC,MAAM,CACtC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAChH,CACF,CAAA","sourcesContent":["import { isEqual } from './isEqual'\n\n/**\n * Returns the props of otherObject missing in object or with a different value.\n */\nexport const difference = (object: any, otherObject: any): Record<any, any> =>\n Object.fromEntries(\n Object.entries(otherObject ?? {}).filter(\n ([key, value]) => !(object && Object.prototype.hasOwnProperty.call(object, key) && isEqual(object[key], value))\n )\n )\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const fromPairs = (pairs) => Object.fromEntries(pairs !== null && pairs !== void 0 ? pairs : []);
|
|
2
2
|
//# sourceMappingURL=fromPairs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fromPairs.js","sourceRoot":"","sources":["../../../../src/utils/_objects/fromPairs.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"fromPairs.js","sourceRoot":"","sources":["../../../../src/utils/_objects/fromPairs.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAA+D,EAAuB,EAAE,CAChH,MAAM,CAAC,WAAW,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAA","sourcesContent":["export const fromPairs = (pairs: Iterable<readonly [PropertyKey, any]> | null | undefined): Record<string, any> =>\n Object.fromEntries(pairs ?? [])\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const toPairs = (object) => Object.entries(object !== null && object !== void 0 ? object : {});
|
|
2
2
|
//# sourceMappingURL=toPairs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toPairs.js","sourceRoot":"","sources":["../../../../src/utils/_objects/toPairs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"toPairs.js","sourceRoot":"","sources":["../../../../src/utils/_objects/toPairs.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAW,EAAmB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAC,CAAA","sourcesContent":["export const toPairs = (object: any): [string, any][] => Object.entries(object ?? {})\n"]}
|
|
@@ -9,6 +9,8 @@ export class FileProcessor {
|
|
|
9
9
|
// true while a chunk is being processed (resume must not start a second processing chain)
|
|
10
10
|
this.processingChunk = false;
|
|
11
11
|
this.completed = false;
|
|
12
|
+
// incremented when a processing run is stopped: callbacks of the chunks of previous runs are ignored
|
|
13
|
+
this.runId = 0;
|
|
12
14
|
this.file = file;
|
|
13
15
|
this.filePath = filePath;
|
|
14
16
|
this.chunkProcessor = chunkProcessor;
|
|
@@ -22,7 +24,14 @@ export class FileProcessor {
|
|
|
22
24
|
}
|
|
23
25
|
this.reset();
|
|
24
26
|
}
|
|
27
|
+
cancelCurrentRun() {
|
|
28
|
+
var _a;
|
|
29
|
+
this.runId += 1;
|
|
30
|
+
(_a = this.retryProcessor) === null || _a === void 0 ? void 0 : _a.stop();
|
|
31
|
+
this.retryProcessor = undefined;
|
|
32
|
+
}
|
|
25
33
|
reset() {
|
|
34
|
+
this.cancelCurrentRun();
|
|
26
35
|
this.running = false;
|
|
27
36
|
this.totalChunks = 0;
|
|
28
37
|
this.currentChunkNumber = 0;
|
|
@@ -47,14 +56,19 @@ export class FileProcessor {
|
|
|
47
56
|
return Promise.resolve(file.slice((currentChunkNumber - 1) * chunkSize, currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize));
|
|
48
57
|
}
|
|
49
58
|
processNextChunk() {
|
|
50
|
-
const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay } = this;
|
|
59
|
+
const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay, runId } = this;
|
|
60
|
+
const isStale = () => runId !== this.runId;
|
|
51
61
|
this.processingChunk = true;
|
|
52
62
|
this.extractCurrentFileChunk()
|
|
53
63
|
.then((content) => {
|
|
64
|
+
if (isStale())
|
|
65
|
+
return;
|
|
54
66
|
const retryProcessor = new RetryProcessor({
|
|
55
67
|
processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),
|
|
56
68
|
onSuccess: (chunkResult) => {
|
|
57
69
|
var _a;
|
|
70
|
+
if (isStale())
|
|
71
|
+
return;
|
|
58
72
|
this.processingChunk = false;
|
|
59
73
|
if (this.currentChunkNumber < totalChunks) {
|
|
60
74
|
// move to the next chunk also when paused: resume will continue from it
|
|
@@ -71,6 +85,8 @@ export class FileProcessor {
|
|
|
71
85
|
}
|
|
72
86
|
},
|
|
73
87
|
onFail: (error) => {
|
|
88
|
+
if (isStale())
|
|
89
|
+
return;
|
|
74
90
|
this.processingChunk = false;
|
|
75
91
|
this.onFail(error);
|
|
76
92
|
this.running = false;
|
|
@@ -78,20 +94,29 @@ export class FileProcessor {
|
|
|
78
94
|
maxTryings,
|
|
79
95
|
retryDelay,
|
|
80
96
|
});
|
|
97
|
+
this.retryProcessor = retryProcessor;
|
|
81
98
|
retryProcessor.start();
|
|
82
99
|
})
|
|
83
100
|
.catch((error) => {
|
|
101
|
+
if (isStale())
|
|
102
|
+
return;
|
|
84
103
|
this.processingChunk = false;
|
|
85
104
|
this.onFail(error);
|
|
86
105
|
this.running = false;
|
|
87
106
|
});
|
|
88
107
|
}
|
|
89
108
|
start(startFromChunk = 1) {
|
|
109
|
+
// a previous run still in progress must not continue in parallel
|
|
110
|
+
this.cancelCurrentRun();
|
|
111
|
+
const { runId } = this;
|
|
112
|
+
this.processingChunk = false;
|
|
90
113
|
this.running = true;
|
|
91
114
|
this.completed = false;
|
|
92
115
|
this.currentChunkNumber = startFromChunk;
|
|
93
116
|
this.calculateFileSize()
|
|
94
117
|
.then((fileSize) => {
|
|
118
|
+
if (runId !== this.runId)
|
|
119
|
+
return;
|
|
95
120
|
this.totalFileSize = fileSize;
|
|
96
121
|
this.totalChunks = Math.ceil(fileSize / this.chunkSize);
|
|
97
122
|
if (this.totalChunks > 0) {
|
|
@@ -99,6 +124,8 @@ export class FileProcessor {
|
|
|
99
124
|
}
|
|
100
125
|
})
|
|
101
126
|
.catch((error) => {
|
|
127
|
+
if (runId !== this.runId)
|
|
128
|
+
return;
|
|
102
129
|
this.onFail(error);
|
|
103
130
|
this.running = false;
|
|
104
131
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileProcessor.js","sourceRoot":"","sources":["../../../src/utils/fileProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { RetryProcessor } from './retryProcessor'\n\ntype ChunkProcessor = (args: {\n chunk: number\n content: Blob | string | Uint8Array\n totalChunks: number\n totalFileSize: number\n}) => Promise<any>\n\nexport type FileProcessorConstructorArgs = {\n file?: File\n filePath?: string\n chunkProcessor: ChunkProcessor\n onError?: (error: Error) => void\n onComplete?: (result: any) => void\n chunkSize?: number\n maxTryings?: number\n /**\n * Delay (in milliseconds) before retrying a failed chunk, doubled at every further retry.\n */\n retryDelay?: number\n}\n\nexport class FileProcessor {\n static readonly defaultChunkSize = 1024 * 1024 * 10 // 10MB\n static readonly defaultMaxTryings = 5\n static readonly defaultRetryDelay = 1000 // 1s, then 2s, 4s...\n\n private readonly file?: File\n private readonly filePath?: string\n private readonly chunkProcessor: ChunkProcessor\n private readonly chunkSize: number\n private readonly maxTryings: number\n private readonly retryDelay: number\n private readonly onError?: (error: Error) => void\n private readonly onComplete?: (result?: any) => void\n\n // State properties\n protected totalFileSize: number = 0\n protected running: boolean = false\n protected totalChunks: number = 0\n protected currentChunkNumber: number = 0\n // true while a chunk is being processed (resume must not start a second processing chain)\n protected processingChunk: boolean = false\n protected completed: boolean = false\n\n constructor({\n file,\n filePath,\n chunkProcessor,\n onError,\n onComplete,\n chunkSize = FileProcessor.defaultChunkSize,\n maxTryings = FileProcessor.defaultMaxTryings,\n retryDelay = FileProcessor.defaultRetryDelay,\n }: FileProcessorConstructorArgs) {\n this.file = file\n this.filePath = filePath\n this.chunkProcessor = chunkProcessor\n this.chunkSize = chunkSize\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n this.onError = onError\n this.onComplete = onComplete\n\n if (!this.file && !this.filePath) {\n throw new Error('File or filePath not specified')\n }\n\n this.reset()\n }\n\n protected reset(): void {\n this.running = false\n this.totalChunks = 0\n this.currentChunkNumber = 0\n this.totalFileSize = 0\n this.processingChunk = false\n this.completed = false\n }\n\n protected calculateFileSize(): Promise<number> {\n return Promise.resolve(this.file?.size ?? 0)\n }\n\n protected onFail(error: Error): void {\n this.onError?.(error)\n }\n\n protected extractCurrentFileChunk(): Promise<Blob | string | Uint8Array> {\n const { file, currentChunkNumber, totalChunks, chunkSize } = this\n if (!file) {\n return Promise.reject(new Error('File property not initialized'))\n }\n return Promise.resolve(\n file.slice(\n (currentChunkNumber - 1) * chunkSize,\n currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize\n )\n )\n }\n\n protected processNextChunk(): void {\n const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay } = this\n\n this.processingChunk = true\n this.extractCurrentFileChunk()\n .then((content) => {\n const retryProcessor = new RetryProcessor<any>({\n processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),\n onSuccess: (chunkResult) => {\n this.processingChunk = false\n if (this.currentChunkNumber < totalChunks) {\n // move to the next chunk also when paused: resume will continue from it\n this.currentChunkNumber += 1\n if (this.running) {\n this.processNextChunk()\n }\n } else {\n this.running = false\n this.completed = true\n // called outside the retried processor: if it throws, the last chunk is not processed again\n this.onComplete?.(chunkResult)\n }\n },\n onFail: (error: Error) => {\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n },\n maxTryings,\n retryDelay,\n })\n retryProcessor.start()\n })\n .catch((error) => {\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n })\n }\n\n start(startFromChunk: number = 1): void {\n this.running = true\n this.completed = false\n this.currentChunkNumber = startFromChunk\n this.calculateFileSize()\n .then((fileSize) => {\n this.totalFileSize = fileSize\n this.totalChunks = Math.ceil(fileSize / this.chunkSize)\n if (this.totalChunks > 0) {\n this.processNextChunk()\n }\n })\n .catch((error) => {\n this.onFail(error)\n this.running = false\n })\n }\n\n stop(): void {\n this.reset()\n }\n\n pause(): void {\n this.running = false\n }\n\n resume(): void {\n if (this.running || this.completed) return\n this.running = true\n // if a chunk is still being processed, processing continues when it completes\n if (!this.processingChunk && this.totalChunks > 0) {\n this.processNextChunk()\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fileProcessor.js","sourceRoot":"","sources":["../../../src/utils/fileProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { RetryProcessor } from './retryProcessor'\n\ntype ChunkProcessor = (args: {\n chunk: number\n content: Blob | string | Uint8Array\n totalChunks: number\n totalFileSize: number\n}) => Promise<any>\n\nexport type FileProcessorConstructorArgs = {\n file?: File\n filePath?: string\n chunkProcessor: ChunkProcessor\n onError?: (error: Error) => void\n onComplete?: (result: any) => void\n chunkSize?: number\n maxTryings?: number\n /**\n * Delay (in milliseconds) before retrying a failed chunk, doubled at every further retry.\n */\n retryDelay?: number\n}\n\nexport class FileProcessor {\n static readonly defaultChunkSize = 1024 * 1024 * 10 // 10MB\n static readonly defaultMaxTryings = 5\n static readonly defaultRetryDelay = 1000 // 1s, then 2s, 4s...\n\n private readonly file?: File\n private readonly filePath?: string\n private readonly chunkProcessor: ChunkProcessor\n private readonly chunkSize: number\n private readonly maxTryings: number\n private readonly retryDelay: number\n private readonly onError?: (error: Error) => void\n private readonly onComplete?: (result?: any) => void\n\n // State properties\n protected totalFileSize: number = 0\n protected running: boolean = false\n protected totalChunks: number = 0\n protected currentChunkNumber: number = 0\n // true while a chunk is being processed (resume must not start a second processing chain)\n protected processingChunk: boolean = false\n protected completed: boolean = false\n // incremented when a processing run is stopped: callbacks of the chunks of previous runs are ignored\n private runId: number = 0\n private retryProcessor?: RetryProcessor<any>\n\n constructor({\n file,\n filePath,\n chunkProcessor,\n onError,\n onComplete,\n chunkSize = FileProcessor.defaultChunkSize,\n maxTryings = FileProcessor.defaultMaxTryings,\n retryDelay = FileProcessor.defaultRetryDelay,\n }: FileProcessorConstructorArgs) {\n this.file = file\n this.filePath = filePath\n this.chunkProcessor = chunkProcessor\n this.chunkSize = chunkSize\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n this.onError = onError\n this.onComplete = onComplete\n\n if (!this.file && !this.filePath) {\n throw new Error('File or filePath not specified')\n }\n\n this.reset()\n }\n\n private cancelCurrentRun(): void {\n this.runId += 1\n this.retryProcessor?.stop()\n this.retryProcessor = undefined\n }\n\n protected reset(): void {\n this.cancelCurrentRun()\n this.running = false\n this.totalChunks = 0\n this.currentChunkNumber = 0\n this.totalFileSize = 0\n this.processingChunk = false\n this.completed = false\n }\n\n protected calculateFileSize(): Promise<number> {\n return Promise.resolve(this.file?.size ?? 0)\n }\n\n protected onFail(error: Error): void {\n this.onError?.(error)\n }\n\n protected extractCurrentFileChunk(): Promise<Blob | string | Uint8Array> {\n const { file, currentChunkNumber, totalChunks, chunkSize } = this\n if (!file) {\n return Promise.reject(new Error('File property not initialized'))\n }\n return Promise.resolve(\n file.slice(\n (currentChunkNumber - 1) * chunkSize,\n currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize\n )\n )\n }\n\n protected processNextChunk(): void {\n const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay, runId } = this\n const isStale = () => runId !== this.runId\n\n this.processingChunk = true\n this.extractCurrentFileChunk()\n .then((content) => {\n if (isStale()) return\n const retryProcessor = new RetryProcessor<any>({\n processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),\n onSuccess: (chunkResult) => {\n if (isStale()) return\n this.processingChunk = false\n if (this.currentChunkNumber < totalChunks) {\n // move to the next chunk also when paused: resume will continue from it\n this.currentChunkNumber += 1\n if (this.running) {\n this.processNextChunk()\n }\n } else {\n this.running = false\n this.completed = true\n // called outside the retried processor: if it throws, the last chunk is not processed again\n this.onComplete?.(chunkResult)\n }\n },\n onFail: (error: Error) => {\n if (isStale()) return\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n },\n maxTryings,\n retryDelay,\n })\n this.retryProcessor = retryProcessor\n retryProcessor.start()\n })\n .catch((error) => {\n if (isStale()) return\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n })\n }\n\n start(startFromChunk: number = 1): void {\n // a previous run still in progress must not continue in parallel\n this.cancelCurrentRun()\n const { runId } = this\n this.processingChunk = false\n this.running = true\n this.completed = false\n this.currentChunkNumber = startFromChunk\n this.calculateFileSize()\n .then((fileSize) => {\n if (runId !== this.runId) return\n this.totalFileSize = fileSize\n this.totalChunks = Math.ceil(fileSize / this.chunkSize)\n if (this.totalChunks > 0) {\n this.processNextChunk()\n }\n })\n .catch((error) => {\n if (runId !== this.runId) return\n this.onFail(error)\n this.running = false\n })\n }\n\n stop(): void {\n this.reset()\n }\n\n pause(): void {\n this.running = false\n }\n\n resume(): void {\n if (this.running || this.completed) return\n this.running = true\n // if a chunk is still being processed, processing continues when it completes\n if (!this.processingChunk && this.totalChunks > 0) {\n this.processNextChunk()\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryProcessor.js","sourceRoot":"","sources":["../../../src/utils/retryProcessor.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,GAAG,CAAC,KAAc,EAAS,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAEtG,MAAM,OAAO,cAAc;IAWzB,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAuC;QAJjH,mBAAmB;QACX,kBAAa,GAAW,CAAC,CAAA;QACzB,YAAO,GAAY,KAAK,CAAA;QAG9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAES,KAAK;QACb,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAA;QAEvB,2FAA2F;QAC3F,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACnB,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EACtC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CACrD,CAAA;IACH,CAAC;IAEO,aAAa,CAAC,MAAuB;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAY;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,kCAAkC;YAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,SAAA,CAAC,EAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA,CAAA;QAC7D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,OAAM;QACR,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAA;IACX,CAAC;IAED,iBAAiB;IACjB,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;CACF","sourcesContent":["interface RetryProcessorArgs<ProcessorResult> {\n processor: () => Promise<ProcessorResult>\n onSuccess: (result: ProcessorResult) => void\n onFail: (error: Error) => void\n maxTryings?: number\n /**\n * Delay (in milliseconds) before the first retry, doubled at every further retry (exponential backoff).\n * Defaults to 0 (immediate retry).\n */\n retryDelay?: number\n}\n\nconst toError = (error: unknown): Error => (error instanceof Error ? error : new Error(String(error)))\n\nexport class RetryProcessor<ProcessorResult> {\n private readonly processor: () => Promise<ProcessorResult>\n private readonly onSuccess: (result: ProcessorResult) => void\n private readonly onFail: (error: Error) => void\n private readonly maxTryings: number\n private readonly retryDelay: number\n\n // State properties\n private currentTrying: number = 0\n private running: boolean = false\n\n constructor({ processor, onSuccess, onFail, maxTryings = 2, retryDelay = 0 }: RetryProcessorArgs<ProcessorResult>) {\n this.processor = processor\n this.onSuccess = onSuccess\n this.onFail = onFail\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n }\n\n protected reset() {\n this.currentTrying = 0\n this.running = false\n }\n\n protected processNext(): void {\n this.currentTrying += 1\n\n // onSuccess runs outside the retried chain: if it throws, the processor must not run again\n this.processor().then(\n (result) => this.handleSuccess(result),\n (error) => this.handleProcessorError(toError(error))\n )\n }\n\n private handleSuccess(result: ProcessorResult): void {\n try {\n this.onSuccess(result)\n } catch (error) {\n this.onFail(toError(error))\n }\n }\n\n private handleProcessorError(error: Error): void {\n if (!this.running || this.currentTrying >= this.maxTryings) {\n // stopped or max attempts reached\n this.onFail(error)\n return\n }\n const delay = this.retryDelay * 2 ** (this.currentTrying - 1)\n if (delay <= 0) {\n this.processNext()\n return\n }\n setTimeout(() => {\n if (this.running) {\n this.processNext()\n } else {\n this.onFail(error)\n }\n }, delay)\n }\n\n // Public methods\n start(): void {\n this.running = true\n this.processNext()\n }\n\n stop(): void {\n this.reset()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retryProcessor.js","sourceRoot":"","sources":["../../../src/utils/retryProcessor.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,GAAG,CAAC,KAAc,EAAS,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAEtG,MAAM,OAAO,cAAc;IAWzB,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAuC;QAJjH,mBAAmB;QACX,kBAAa,GAAW,CAAC,CAAA;QACzB,YAAO,GAAY,KAAK,CAAA;QAG9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAES,KAAK;QACb,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAA;QAEvB,2FAA2F;QAC3F,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACnB,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EACtC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CACrD,CAAA;IACH,CAAC;IAEO,aAAa,CAAC,MAAuB;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAY;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,kCAAkC;YAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,SAAA,CAAC,EAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA,CAAA;QAC7D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,OAAM;QACR,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAA;IACX,CAAC;IAED,iBAAiB;IACjB,KAAK;QACH,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;CACF","sourcesContent":["interface RetryProcessorArgs<ProcessorResult> {\n processor: () => Promise<ProcessorResult>\n onSuccess: (result: ProcessorResult) => void\n onFail: (error: Error) => void\n maxTryings?: number\n /**\n * Delay (in milliseconds) before the first retry, doubled at every further retry (exponential backoff).\n * Defaults to 0 (immediate retry).\n */\n retryDelay?: number\n}\n\nconst toError = (error: unknown): Error => (error instanceof Error ? error : new Error(String(error)))\n\nexport class RetryProcessor<ProcessorResult> {\n private readonly processor: () => Promise<ProcessorResult>\n private readonly onSuccess: (result: ProcessorResult) => void\n private readonly onFail: (error: Error) => void\n private readonly maxTryings: number\n private readonly retryDelay: number\n\n // State properties\n private currentTrying: number = 0\n private running: boolean = false\n\n constructor({ processor, onSuccess, onFail, maxTryings = 2, retryDelay = 0 }: RetryProcessorArgs<ProcessorResult>) {\n this.processor = processor\n this.onSuccess = onSuccess\n this.onFail = onFail\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n }\n\n protected reset() {\n this.currentTrying = 0\n this.running = false\n }\n\n protected processNext(): void {\n this.currentTrying += 1\n\n // onSuccess runs outside the retried chain: if it throws, the processor must not run again\n this.processor().then(\n (result) => this.handleSuccess(result),\n (error) => this.handleProcessorError(toError(error))\n )\n }\n\n private handleSuccess(result: ProcessorResult): void {\n try {\n this.onSuccess(result)\n } catch (error) {\n this.onFail(toError(error))\n }\n }\n\n private handleProcessorError(error: Error): void {\n if (!this.running || this.currentTrying >= this.maxTryings) {\n // stopped or max attempts reached\n this.onFail(error)\n return\n }\n const delay = this.retryDelay * 2 ** (this.currentTrying - 1)\n if (delay <= 0) {\n this.processNext()\n return\n }\n setTimeout(() => {\n if (this.running) {\n this.processNext()\n } else {\n this.onFail(error)\n }\n }, delay)\n }\n\n // Public methods\n start(): void {\n this.currentTrying = 0\n this.running = true\n this.processNext()\n }\n\n stop(): void {\n this.reset()\n }\n}\n"]}
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.difference = void 0;
|
|
7
|
-
const lodash_differencewith_1 = __importDefault(require("lodash.differencewith"));
|
|
8
4
|
const isEqual_1 = require("./isEqual");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const pairsObject = (0, toPairs_1.toPairs)(object);
|
|
14
|
-
const pairsDifference = (0, lodash_differencewith_1.default)(pairsOther, pairsObject, isEqual_1.isEqual);
|
|
15
|
-
return (0, fromPairs_1.fromPairs)(pairsDifference);
|
|
16
|
-
};
|
|
5
|
+
/**
|
|
6
|
+
* Returns the props of otherObject missing in object or with a different value.
|
|
7
|
+
*/
|
|
8
|
+
const difference = (object, otherObject) => Object.fromEntries(Object.entries(otherObject !== null && otherObject !== void 0 ? otherObject : {}).filter(([key, value]) => !(object && Object.prototype.hasOwnProperty.call(object, key) && (0, isEqual_1.isEqual)(object[key], value))));
|
|
17
9
|
exports.difference = difference;
|
|
18
10
|
//# sourceMappingURL=difference.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"difference.js","sourceRoot":"","sources":["../../../src/utils/_objects/difference.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"difference.js","sourceRoot":"","sources":["../../../src/utils/_objects/difference.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AAEnC;;GAEG;AACI,MAAM,UAAU,GAAG,CAAC,MAAW,EAAE,WAAgB,EAAoB,EAAE,CAC5E,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,EAAE,CAAC,CAAC,MAAM,CACtC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAA,iBAAO,EAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAChH,CACF,CAAA;AALU,QAAA,UAAU,GAAV,UAAU,CAKpB","sourcesContent":["import { isEqual } from './isEqual'\n\n/**\n * Returns the props of otherObject missing in object or with a different value.\n */\nexport const difference = (object: any, otherObject: any): Record<any, any> =>\n Object.fromEntries(\n Object.entries(otherObject ?? {}).filter(\n ([key, value]) => !(object && Object.prototype.hasOwnProperty.call(object, key) && isEqual(object[key], value))\n )\n )\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const fromPairs: (pairs: Iterable<readonly [PropertyKey, any]> | null | undefined) => Record<string, any>;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.fromPairs = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const fromPairs = (pairs) => Object.fromEntries(pairs !== null && pairs !== void 0 ? pairs : []);
|
|
5
|
+
exports.fromPairs = fromPairs;
|
|
9
6
|
//# sourceMappingURL=fromPairs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fromPairs.js","sourceRoot":"","sources":["../../../src/utils/_objects/fromPairs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fromPairs.js","sourceRoot":"","sources":["../../../src/utils/_objects/fromPairs.ts"],"names":[],"mappings":";;;AAAO,MAAM,SAAS,GAAG,CAAC,KAA+D,EAAuB,EAAE,CAChH,MAAM,CAAC,WAAW,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAA;AADpB,QAAA,SAAS,GAAT,SAAS,CACW","sourcesContent":["export const fromPairs = (pairs: Iterable<readonly [PropertyKey, any]> | null | undefined): Record<string, any> =>\n Object.fromEntries(pairs ?? [])\n"]}
|
|
@@ -7,6 +7,7 @@ import { deleteEmptyProps } from './deleteEmptyProps';
|
|
|
7
7
|
import { dissoc } from './dissoc';
|
|
8
8
|
import { dissocPath } from './dissocPath';
|
|
9
9
|
import { dissocPathIfEmpty } from './dissocPathIfEmpty';
|
|
10
|
+
import { fromPairs } from './fromPairs';
|
|
10
11
|
import { isEmpty } from './isEmpty';
|
|
11
12
|
import { isNotEmpty } from './isNotEmpty';
|
|
12
13
|
import { isNil } from './isNil';
|
|
@@ -15,6 +16,7 @@ import { path } from './path';
|
|
|
15
16
|
import { propertyOf } from './propertyOf';
|
|
16
17
|
import { setInPath } from './setInPath';
|
|
17
18
|
import { stringify } from './stringify';
|
|
19
|
+
import { toPairs } from './toPairs';
|
|
18
20
|
export declare const Objects: {
|
|
19
21
|
assoc: typeof assoc;
|
|
20
22
|
assocPath: typeof assocPath;
|
|
@@ -25,10 +27,7 @@ export declare const Objects: {
|
|
|
25
27
|
dissoc: typeof dissoc;
|
|
26
28
|
dissocPath: typeof dissocPath;
|
|
27
29
|
dissocPathIfEmpty: typeof dissocPathIfEmpty;
|
|
28
|
-
fromPairs:
|
|
29
|
-
<T>(pairs: import("lodash").List<[import("lodash").PropertyName, T]> | null | undefined): import("lodash").Dictionary<T>;
|
|
30
|
-
(pairs: import("lodash").List<any[]> | null | undefined): import("lodash").Dictionary<any>;
|
|
31
|
-
};
|
|
30
|
+
fromPairs: typeof fromPairs;
|
|
32
31
|
isEmpty: typeof isEmpty;
|
|
33
32
|
isEqual: (value: any, other: any) => boolean;
|
|
34
33
|
isNil: typeof isNil;
|
|
@@ -38,8 +37,5 @@ export declare const Objects: {
|
|
|
38
37
|
propertyOf: typeof propertyOf;
|
|
39
38
|
setInPath: typeof setInPath;
|
|
40
39
|
stringify: typeof stringify;
|
|
41
|
-
toPairs:
|
|
42
|
-
<T>(object?: import("lodash").Dictionary<T> | import("lodash").NumericDictionary<T>): Array<[string, T]>;
|
|
43
|
-
(object?: object): Array<[string, any]>;
|
|
44
|
-
};
|
|
40
|
+
toPairs: typeof toPairs;
|
|
45
41
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare const toPairs: (object: any) => [string, any][];
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.toPairs = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const toPairs = (object) => Object.entries(object !== null && object !== void 0 ? object : {});
|
|
5
|
+
exports.toPairs = toPairs;
|
|
9
6
|
//# sourceMappingURL=toPairs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toPairs.js","sourceRoot":"","sources":["../../../src/utils/_objects/toPairs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"toPairs.js","sourceRoot":"","sources":["../../../src/utils/_objects/toPairs.ts"],"names":[],"mappings":";;;AAAO,MAAM,OAAO,GAAG,CAAC,MAAW,EAAmB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAC,CAAA;AAAxE,QAAA,OAAO,GAAP,OAAO,CAAiE","sourcesContent":["export const toPairs = (object: any): [string, any][] => Object.entries(object ?? {})\n"]}
|
|
@@ -35,7 +35,10 @@ export declare class FileProcessor {
|
|
|
35
35
|
protected currentChunkNumber: number;
|
|
36
36
|
protected processingChunk: boolean;
|
|
37
37
|
protected completed: boolean;
|
|
38
|
+
private runId;
|
|
39
|
+
private retryProcessor?;
|
|
38
40
|
constructor({ file, filePath, chunkProcessor, onError, onComplete, chunkSize, maxTryings, retryDelay, }: FileProcessorConstructorArgs);
|
|
41
|
+
private cancelCurrentRun;
|
|
39
42
|
protected reset(): void;
|
|
40
43
|
protected calculateFileSize(): Promise<number>;
|
|
41
44
|
protected onFail(error: Error): void;
|
|
@@ -12,6 +12,8 @@ class FileProcessor {
|
|
|
12
12
|
// true while a chunk is being processed (resume must not start a second processing chain)
|
|
13
13
|
this.processingChunk = false;
|
|
14
14
|
this.completed = false;
|
|
15
|
+
// incremented when a processing run is stopped: callbacks of the chunks of previous runs are ignored
|
|
16
|
+
this.runId = 0;
|
|
15
17
|
this.file = file;
|
|
16
18
|
this.filePath = filePath;
|
|
17
19
|
this.chunkProcessor = chunkProcessor;
|
|
@@ -25,7 +27,14 @@ class FileProcessor {
|
|
|
25
27
|
}
|
|
26
28
|
this.reset();
|
|
27
29
|
}
|
|
30
|
+
cancelCurrentRun() {
|
|
31
|
+
var _a;
|
|
32
|
+
this.runId += 1;
|
|
33
|
+
(_a = this.retryProcessor) === null || _a === void 0 ? void 0 : _a.stop();
|
|
34
|
+
this.retryProcessor = undefined;
|
|
35
|
+
}
|
|
28
36
|
reset() {
|
|
37
|
+
this.cancelCurrentRun();
|
|
29
38
|
this.running = false;
|
|
30
39
|
this.totalChunks = 0;
|
|
31
40
|
this.currentChunkNumber = 0;
|
|
@@ -50,14 +59,19 @@ class FileProcessor {
|
|
|
50
59
|
return Promise.resolve(file.slice((currentChunkNumber - 1) * chunkSize, currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize));
|
|
51
60
|
}
|
|
52
61
|
processNextChunk() {
|
|
53
|
-
const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay } = this;
|
|
62
|
+
const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay, runId } = this;
|
|
63
|
+
const isStale = () => runId !== this.runId;
|
|
54
64
|
this.processingChunk = true;
|
|
55
65
|
this.extractCurrentFileChunk()
|
|
56
66
|
.then((content) => {
|
|
67
|
+
if (isStale())
|
|
68
|
+
return;
|
|
57
69
|
const retryProcessor = new retryProcessor_1.RetryProcessor({
|
|
58
70
|
processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),
|
|
59
71
|
onSuccess: (chunkResult) => {
|
|
60
72
|
var _a;
|
|
73
|
+
if (isStale())
|
|
74
|
+
return;
|
|
61
75
|
this.processingChunk = false;
|
|
62
76
|
if (this.currentChunkNumber < totalChunks) {
|
|
63
77
|
// move to the next chunk also when paused: resume will continue from it
|
|
@@ -74,6 +88,8 @@ class FileProcessor {
|
|
|
74
88
|
}
|
|
75
89
|
},
|
|
76
90
|
onFail: (error) => {
|
|
91
|
+
if (isStale())
|
|
92
|
+
return;
|
|
77
93
|
this.processingChunk = false;
|
|
78
94
|
this.onFail(error);
|
|
79
95
|
this.running = false;
|
|
@@ -81,20 +97,29 @@ class FileProcessor {
|
|
|
81
97
|
maxTryings,
|
|
82
98
|
retryDelay,
|
|
83
99
|
});
|
|
100
|
+
this.retryProcessor = retryProcessor;
|
|
84
101
|
retryProcessor.start();
|
|
85
102
|
})
|
|
86
103
|
.catch((error) => {
|
|
104
|
+
if (isStale())
|
|
105
|
+
return;
|
|
87
106
|
this.processingChunk = false;
|
|
88
107
|
this.onFail(error);
|
|
89
108
|
this.running = false;
|
|
90
109
|
});
|
|
91
110
|
}
|
|
92
111
|
start(startFromChunk = 1) {
|
|
112
|
+
// a previous run still in progress must not continue in parallel
|
|
113
|
+
this.cancelCurrentRun();
|
|
114
|
+
const { runId } = this;
|
|
115
|
+
this.processingChunk = false;
|
|
93
116
|
this.running = true;
|
|
94
117
|
this.completed = false;
|
|
95
118
|
this.currentChunkNumber = startFromChunk;
|
|
96
119
|
this.calculateFileSize()
|
|
97
120
|
.then((fileSize) => {
|
|
121
|
+
if (runId !== this.runId)
|
|
122
|
+
return;
|
|
98
123
|
this.totalFileSize = fileSize;
|
|
99
124
|
this.totalChunks = Math.ceil(fileSize / this.chunkSize);
|
|
100
125
|
if (this.totalChunks > 0) {
|
|
@@ -102,6 +127,8 @@ class FileProcessor {
|
|
|
102
127
|
}
|
|
103
128
|
})
|
|
104
129
|
.catch((error) => {
|
|
130
|
+
if (runId !== this.runId)
|
|
131
|
+
return;
|
|
105
132
|
this.onFail(error);
|
|
106
133
|
this.running = false;
|
|
107
134
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileProcessor.js","sourceRoot":"","sources":["../../src/utils/fileProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { RetryProcessor } from './retryProcessor'\n\ntype ChunkProcessor = (args: {\n chunk: number\n content: Blob | string | Uint8Array\n totalChunks: number\n totalFileSize: number\n}) => Promise<any>\n\nexport type FileProcessorConstructorArgs = {\n file?: File\n filePath?: string\n chunkProcessor: ChunkProcessor\n onError?: (error: Error) => void\n onComplete?: (result: any) => void\n chunkSize?: number\n maxTryings?: number\n /**\n * Delay (in milliseconds) before retrying a failed chunk, doubled at every further retry.\n */\n retryDelay?: number\n}\n\nexport class FileProcessor {\n static readonly defaultChunkSize = 1024 * 1024 * 10 // 10MB\n static readonly defaultMaxTryings = 5\n static readonly defaultRetryDelay = 1000 // 1s, then 2s, 4s...\n\n private readonly file?: File\n private readonly filePath?: string\n private readonly chunkProcessor: ChunkProcessor\n private readonly chunkSize: number\n private readonly maxTryings: number\n private readonly retryDelay: number\n private readonly onError?: (error: Error) => void\n private readonly onComplete?: (result?: any) => void\n\n // State properties\n protected totalFileSize: number = 0\n protected running: boolean = false\n protected totalChunks: number = 0\n protected currentChunkNumber: number = 0\n // true while a chunk is being processed (resume must not start a second processing chain)\n protected processingChunk: boolean = false\n protected completed: boolean = false\n\n constructor({\n file,\n filePath,\n chunkProcessor,\n onError,\n onComplete,\n chunkSize = FileProcessor.defaultChunkSize,\n maxTryings = FileProcessor.defaultMaxTryings,\n retryDelay = FileProcessor.defaultRetryDelay,\n }: FileProcessorConstructorArgs) {\n this.file = file\n this.filePath = filePath\n this.chunkProcessor = chunkProcessor\n this.chunkSize = chunkSize\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n this.onError = onError\n this.onComplete = onComplete\n\n if (!this.file && !this.filePath) {\n throw new Error('File or filePath not specified')\n }\n\n this.reset()\n }\n\n protected reset(): void {\n this.running = false\n this.totalChunks = 0\n this.currentChunkNumber = 0\n this.totalFileSize = 0\n this.processingChunk = false\n this.completed = false\n }\n\n protected calculateFileSize(): Promise<number> {\n return Promise.resolve(this.file?.size ?? 0)\n }\n\n protected onFail(error: Error): void {\n this.onError?.(error)\n }\n\n protected extractCurrentFileChunk(): Promise<Blob | string | Uint8Array> {\n const { file, currentChunkNumber, totalChunks, chunkSize } = this\n if (!file) {\n return Promise.reject(new Error('File property not initialized'))\n }\n return Promise.resolve(\n file.slice(\n (currentChunkNumber - 1) * chunkSize,\n currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize\n )\n )\n }\n\n protected processNextChunk(): void {\n const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay } = this\n\n this.processingChunk = true\n this.extractCurrentFileChunk()\n .then((content) => {\n const retryProcessor = new RetryProcessor<any>({\n processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),\n onSuccess: (chunkResult) => {\n this.processingChunk = false\n if (this.currentChunkNumber < totalChunks) {\n // move to the next chunk also when paused: resume will continue from it\n this.currentChunkNumber += 1\n if (this.running) {\n this.processNextChunk()\n }\n } else {\n this.running = false\n this.completed = true\n // called outside the retried processor: if it throws, the last chunk is not processed again\n this.onComplete?.(chunkResult)\n }\n },\n onFail: (error: Error) => {\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n },\n maxTryings,\n retryDelay,\n })\n retryProcessor.start()\n })\n .catch((error) => {\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n })\n }\n\n start(startFromChunk: number = 1): void {\n this.running = true\n this.completed = false\n this.currentChunkNumber = startFromChunk\n this.calculateFileSize()\n .then((fileSize) => {\n this.totalFileSize = fileSize\n this.totalChunks = Math.ceil(fileSize / this.chunkSize)\n if (this.totalChunks > 0) {\n this.processNextChunk()\n }\n })\n .catch((error) => {\n this.onFail(error)\n this.running = false\n })\n }\n\n stop(): void {\n this.reset()\n }\n\n pause(): void {\n this.running = false\n }\n\n resume(): void {\n if (this.running || this.completed) return\n this.running = true\n // if a chunk is still being processed, processing continues when it completes\n if (!this.processingChunk && this.totalChunks > 0) {\n this.processNextChunk()\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fileProcessor.js","sourceRoot":"","sources":["../../src/utils/fileProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { RetryProcessor } from './retryProcessor'\n\ntype ChunkProcessor = (args: {\n chunk: number\n content: Blob | string | Uint8Array\n totalChunks: number\n totalFileSize: number\n}) => Promise<any>\n\nexport type FileProcessorConstructorArgs = {\n file?: File\n filePath?: string\n chunkProcessor: ChunkProcessor\n onError?: (error: Error) => void\n onComplete?: (result: any) => void\n chunkSize?: number\n maxTryings?: number\n /**\n * Delay (in milliseconds) before retrying a failed chunk, doubled at every further retry.\n */\n retryDelay?: number\n}\n\nexport class FileProcessor {\n static readonly defaultChunkSize = 1024 * 1024 * 10 // 10MB\n static readonly defaultMaxTryings = 5\n static readonly defaultRetryDelay = 1000 // 1s, then 2s, 4s...\n\n private readonly file?: File\n private readonly filePath?: string\n private readonly chunkProcessor: ChunkProcessor\n private readonly chunkSize: number\n private readonly maxTryings: number\n private readonly retryDelay: number\n private readonly onError?: (error: Error) => void\n private readonly onComplete?: (result?: any) => void\n\n // State properties\n protected totalFileSize: number = 0\n protected running: boolean = false\n protected totalChunks: number = 0\n protected currentChunkNumber: number = 0\n // true while a chunk is being processed (resume must not start a second processing chain)\n protected processingChunk: boolean = false\n protected completed: boolean = false\n // incremented when a processing run is stopped: callbacks of the chunks of previous runs are ignored\n private runId: number = 0\n private retryProcessor?: RetryProcessor<any>\n\n constructor({\n file,\n filePath,\n chunkProcessor,\n onError,\n onComplete,\n chunkSize = FileProcessor.defaultChunkSize,\n maxTryings = FileProcessor.defaultMaxTryings,\n retryDelay = FileProcessor.defaultRetryDelay,\n }: FileProcessorConstructorArgs) {\n this.file = file\n this.filePath = filePath\n this.chunkProcessor = chunkProcessor\n this.chunkSize = chunkSize\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n this.onError = onError\n this.onComplete = onComplete\n\n if (!this.file && !this.filePath) {\n throw new Error('File or filePath not specified')\n }\n\n this.reset()\n }\n\n private cancelCurrentRun(): void {\n this.runId += 1\n this.retryProcessor?.stop()\n this.retryProcessor = undefined\n }\n\n protected reset(): void {\n this.cancelCurrentRun()\n this.running = false\n this.totalChunks = 0\n this.currentChunkNumber = 0\n this.totalFileSize = 0\n this.processingChunk = false\n this.completed = false\n }\n\n protected calculateFileSize(): Promise<number> {\n return Promise.resolve(this.file?.size ?? 0)\n }\n\n protected onFail(error: Error): void {\n this.onError?.(error)\n }\n\n protected extractCurrentFileChunk(): Promise<Blob | string | Uint8Array> {\n const { file, currentChunkNumber, totalChunks, chunkSize } = this\n if (!file) {\n return Promise.reject(new Error('File property not initialized'))\n }\n return Promise.resolve(\n file.slice(\n (currentChunkNumber - 1) * chunkSize,\n currentChunkNumber === totalChunks ? undefined : currentChunkNumber * chunkSize\n )\n )\n }\n\n protected processNextChunk(): void {\n const { chunkProcessor, currentChunkNumber, totalFileSize, totalChunks, maxTryings, retryDelay, runId } = this\n const isStale = () => runId !== this.runId\n\n this.processingChunk = true\n this.extractCurrentFileChunk()\n .then((content) => {\n if (isStale()) return\n const retryProcessor = new RetryProcessor<any>({\n processor: () => chunkProcessor({ chunk: currentChunkNumber, totalFileSize, totalChunks, content }),\n onSuccess: (chunkResult) => {\n if (isStale()) return\n this.processingChunk = false\n if (this.currentChunkNumber < totalChunks) {\n // move to the next chunk also when paused: resume will continue from it\n this.currentChunkNumber += 1\n if (this.running) {\n this.processNextChunk()\n }\n } else {\n this.running = false\n this.completed = true\n // called outside the retried processor: if it throws, the last chunk is not processed again\n this.onComplete?.(chunkResult)\n }\n },\n onFail: (error: Error) => {\n if (isStale()) return\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n },\n maxTryings,\n retryDelay,\n })\n this.retryProcessor = retryProcessor\n retryProcessor.start()\n })\n .catch((error) => {\n if (isStale()) return\n this.processingChunk = false\n this.onFail(error)\n this.running = false\n })\n }\n\n start(startFromChunk: number = 1): void {\n // a previous run still in progress must not continue in parallel\n this.cancelCurrentRun()\n const { runId } = this\n this.processingChunk = false\n this.running = true\n this.completed = false\n this.currentChunkNumber = startFromChunk\n this.calculateFileSize()\n .then((fileSize) => {\n if (runId !== this.runId) return\n this.totalFileSize = fileSize\n this.totalChunks = Math.ceil(fileSize / this.chunkSize)\n if (this.totalChunks > 0) {\n this.processNextChunk()\n }\n })\n .catch((error) => {\n if (runId !== this.runId) return\n this.onFail(error)\n this.running = false\n })\n }\n\n stop(): void {\n this.reset()\n }\n\n pause(): void {\n this.running = false\n }\n\n resume(): void {\n if (this.running || this.completed) return\n this.running = true\n // if a chunk is still being processed, processing continues when it completes\n if (!this.processingChunk && this.totalChunks > 0) {\n this.processNextChunk()\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retryProcessor.js","sourceRoot":"","sources":["../../src/utils/retryProcessor.ts"],"names":[],"mappings":";;;AAYA,MAAM,OAAO,GAAG,CAAC,KAAc,EAAS,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAEtG;IAWE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAuC;QAJjH,mBAAmB;QACX,kBAAa,GAAW,CAAC,CAAA;QACzB,YAAO,GAAY,KAAK,CAAA;QAG9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAES,KAAK;QACb,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAA;QAEvB,2FAA2F;QAC3F,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACnB,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EACtC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CACrD,CAAA;IACH,CAAC;IAEO,aAAa,CAAC,MAAuB;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAY;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,kCAAkC;YAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,SAAA,CAAC,EAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA,CAAA;QAC7D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,OAAM;QACR,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAA;IACX,CAAC;IAED,iBAAiB;IACjB,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;CACF","sourcesContent":["interface RetryProcessorArgs<ProcessorResult> {\n processor: () => Promise<ProcessorResult>\n onSuccess: (result: ProcessorResult) => void\n onFail: (error: Error) => void\n maxTryings?: number\n /**\n * Delay (in milliseconds) before the first retry, doubled at every further retry (exponential backoff).\n * Defaults to 0 (immediate retry).\n */\n retryDelay?: number\n}\n\nconst toError = (error: unknown): Error => (error instanceof Error ? error : new Error(String(error)))\n\nexport class RetryProcessor<ProcessorResult> {\n private readonly processor: () => Promise<ProcessorResult>\n private readonly onSuccess: (result: ProcessorResult) => void\n private readonly onFail: (error: Error) => void\n private readonly maxTryings: number\n private readonly retryDelay: number\n\n // State properties\n private currentTrying: number = 0\n private running: boolean = false\n\n constructor({ processor, onSuccess, onFail, maxTryings = 2, retryDelay = 0 }: RetryProcessorArgs<ProcessorResult>) {\n this.processor = processor\n this.onSuccess = onSuccess\n this.onFail = onFail\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n }\n\n protected reset() {\n this.currentTrying = 0\n this.running = false\n }\n\n protected processNext(): void {\n this.currentTrying += 1\n\n // onSuccess runs outside the retried chain: if it throws, the processor must not run again\n this.processor().then(\n (result) => this.handleSuccess(result),\n (error) => this.handleProcessorError(toError(error))\n )\n }\n\n private handleSuccess(result: ProcessorResult): void {\n try {\n this.onSuccess(result)\n } catch (error) {\n this.onFail(toError(error))\n }\n }\n\n private handleProcessorError(error: Error): void {\n if (!this.running || this.currentTrying >= this.maxTryings) {\n // stopped or max attempts reached\n this.onFail(error)\n return\n }\n const delay = this.retryDelay * 2 ** (this.currentTrying - 1)\n if (delay <= 0) {\n this.processNext()\n return\n }\n setTimeout(() => {\n if (this.running) {\n this.processNext()\n } else {\n this.onFail(error)\n }\n }, delay)\n }\n\n // Public methods\n start(): void {\n this.running = true\n this.processNext()\n }\n\n stop(): void {\n this.reset()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retryProcessor.js","sourceRoot":"","sources":["../../src/utils/retryProcessor.ts"],"names":[],"mappings":";;;AAYA,MAAM,OAAO,GAAG,CAAC,KAAc,EAAS,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAEtG;IAWE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,CAAC,EAAuC;QAJjH,mBAAmB;QACX,kBAAa,GAAW,CAAC,CAAA;QACzB,YAAO,GAAY,KAAK,CAAA;QAG9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAES,KAAK;QACb,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAA;QAEvB,2FAA2F;QAC3F,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACnB,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EACtC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CACrD,CAAA;IACH,CAAC;IAEO,aAAa,CAAC,MAAuB;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAY;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,kCAAkC;YAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,SAAA,CAAC,EAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA,CAAA;QAC7D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,OAAM;QACR,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAA;IACX,CAAC;IAED,iBAAiB;IACjB,KAAK;QACH,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;CACF","sourcesContent":["interface RetryProcessorArgs<ProcessorResult> {\n processor: () => Promise<ProcessorResult>\n onSuccess: (result: ProcessorResult) => void\n onFail: (error: Error) => void\n maxTryings?: number\n /**\n * Delay (in milliseconds) before the first retry, doubled at every further retry (exponential backoff).\n * Defaults to 0 (immediate retry).\n */\n retryDelay?: number\n}\n\nconst toError = (error: unknown): Error => (error instanceof Error ? error : new Error(String(error)))\n\nexport class RetryProcessor<ProcessorResult> {\n private readonly processor: () => Promise<ProcessorResult>\n private readonly onSuccess: (result: ProcessorResult) => void\n private readonly onFail: (error: Error) => void\n private readonly maxTryings: number\n private readonly retryDelay: number\n\n // State properties\n private currentTrying: number = 0\n private running: boolean = false\n\n constructor({ processor, onSuccess, onFail, maxTryings = 2, retryDelay = 0 }: RetryProcessorArgs<ProcessorResult>) {\n this.processor = processor\n this.onSuccess = onSuccess\n this.onFail = onFail\n this.maxTryings = maxTryings\n this.retryDelay = retryDelay\n }\n\n protected reset() {\n this.currentTrying = 0\n this.running = false\n }\n\n protected processNext(): void {\n this.currentTrying += 1\n\n // onSuccess runs outside the retried chain: if it throws, the processor must not run again\n this.processor().then(\n (result) => this.handleSuccess(result),\n (error) => this.handleProcessorError(toError(error))\n )\n }\n\n private handleSuccess(result: ProcessorResult): void {\n try {\n this.onSuccess(result)\n } catch (error) {\n this.onFail(toError(error))\n }\n }\n\n private handleProcessorError(error: Error): void {\n if (!this.running || this.currentTrying >= this.maxTryings) {\n // stopped or max attempts reached\n this.onFail(error)\n return\n }\n const delay = this.retryDelay * 2 ** (this.currentTrying - 1)\n if (delay <= 0) {\n this.processNext()\n return\n }\n setTimeout(() => {\n if (this.running) {\n this.processNext()\n } else {\n this.onFail(error)\n }\n }, delay)\n }\n\n // Public methods\n start(): void {\n this.currentTrying = 0\n this.running = true\n this.processNext()\n }\n\n stop(): void {\n this.reset()\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"name": "OpenForis",
|
|
5
5
|
"email": "openforis.arena@gmail.com"
|
|
6
6
|
},
|
|
7
|
-
"version": "2.16.
|
|
7
|
+
"version": "2.16.11",
|
|
8
8
|
"description": "Arena core module",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -23,10 +23,7 @@
|
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@jest/globals": "^30.5.2",
|
|
25
25
|
"@types/jest": "^30.0.0",
|
|
26
|
-
"@types/lodash.differencewith": "^4.5.9",
|
|
27
|
-
"@types/lodash.frompairs": "^4.0.9",
|
|
28
26
|
"@types/lodash.isequal": "^4.5.8",
|
|
29
|
-
"@types/lodash.topairs": "^4.3.9",
|
|
30
27
|
"@types/node": "^26.6.5",
|
|
31
28
|
"@types/proj4": "^2.19.0",
|
|
32
29
|
"@typescript-eslint/eslint-plugin": "^8",
|
|
@@ -54,10 +51,7 @@
|
|
|
54
51
|
"change-case": "^5.4.4",
|
|
55
52
|
"dayjs": "^1.11.23",
|
|
56
53
|
"jsep": "^1.6.0",
|
|
57
|
-
"lodash.differencewith": "^4.5.0",
|
|
58
|
-
"lodash.frompairs": "^4.0.1",
|
|
59
54
|
"lodash.isequal": "^4.5.0",
|
|
60
|
-
"lodash.topairs": "^4.3.0",
|
|
61
55
|
"n2words": "^6.3.0",
|
|
62
56
|
"proj4": "^2.22.0",
|
|
63
57
|
"uuid": "^14.0.3"
|