@researchdatabox/redbox-core 0.0.1-beta.9700 → 0.0.1-beta.9873
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/HarvestRunService.d.ts +49 -0
- package/dist/HarvestRunService.d.ts.map +1 -0
- package/dist/HarvestRunService.js +13 -0
- package/dist/api-routes/groups/harvest-runs.d.ts +5 -0
- package/dist/api-routes/groups/harvest-runs.d.ts.map +1 -0
- package/dist/api-routes/groups/harvest-runs.js +79 -0
- package/dist/api-routes/groups/named-query.d.ts +8 -0
- package/dist/api-routes/groups/named-query.d.ts.map +1 -0
- package/dist/api-routes/groups/named-query.js +54 -0
- package/dist/api-routes/groups/records.d.ts.map +1 -1
- package/dist/api-routes/groups/records.js +6 -2
- package/dist/api-routes/groups/reports.d.ts +6 -0
- package/dist/api-routes/groups/reports.d.ts.map +1 -1
- package/dist/api-routes/groups/reports.js +45 -2
- package/dist/api-routes/groups/users.js +3 -3
- package/dist/api-routes/index.d.ts +2 -0
- package/dist/api-routes/index.d.ts.map +1 -1
- package/dist/api-routes/index.js +3 -1
- package/dist/api-routes/openapi.d.ts +0 -1
- package/dist/api-routes/openapi.d.ts.map +1 -1
- package/dist/api-routes/openapi.js +27 -8
- package/dist/api-routes/route-registry.d.ts.map +1 -1
- package/dist/api-routes/route-registry.js +5 -1
- package/dist/api-routes/route-resolution.d.ts.map +1 -1
- package/dist/api-routes/route-resolution.js +15 -1
- package/dist/api-routes/schemas/common.d.ts +1 -2
- package/dist/api-routes/schemas/common.d.ts.map +1 -1
- package/dist/api-routes/schemas/common.js +10 -11
- package/dist/api-routes/schemas/responses.d.ts +6635 -1887
- package/dist/api-routes/schemas/responses.d.ts.map +1 -1
- package/dist/api-routes/schemas/responses.js +364 -269
- package/dist/api-routes/zod-openapi.d.ts +3 -0
- package/dist/api-routes/zod-openapi.d.ts.map +1 -0
- package/dist/api-routes/zod-openapi.js +8 -0
- package/dist/bootstrap.js +3 -3
- package/dist/config/auth.config.d.ts.map +1 -1
- package/dist/config/auth.config.js +8 -1
- package/dist/config/brandingConfigurationDefaults.config.d.ts.map +1 -1
- package/dist/config/brandingConfigurationDefaults.config.js +4 -2
- package/dist/config/harvestRuns.config.d.ts +9 -0
- package/dist/config/harvestRuns.config.d.ts.map +1 -0
- package/dist/config/harvestRuns.config.js +11 -0
- package/dist/config/index.d.ts +4 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +4 -3
- package/dist/config/namedQuery.config.d.ts +16 -2
- package/dist/config/namedQuery.config.d.ts.map +1 -1
- package/dist/config/namedQuery.config.js +7 -350
- package/dist/config/report.config.d.ts +2 -11
- package/dist/config/report.config.d.ts.map +1 -1
- package/dist/config/report.config.js +3 -49
- package/dist/config/reusableContributorFormDefinitions.config.d.ts.map +1 -1
- package/dist/config/reusableContributorFormDefinitions.config.js +10 -4
- package/dist/config/routes.config.d.ts.map +1 -1
- package/dist/config/routes.config.js +15 -1
- package/dist/configmodels/AdminSidebarConfig.d.ts.map +1 -1
- package/dist/configmodels/AdminSidebarConfig.js +2 -1
- package/dist/controllers/AdminController.d.ts +1 -0
- package/dist/controllers/AdminController.d.ts.map +1 -1
- package/dist/controllers/AdminController.js +5 -1
- package/dist/controllers/NamedQueryController.d.ts +8 -0
- package/dist/controllers/NamedQueryController.d.ts.map +1 -0
- package/dist/controllers/NamedQueryController.js +17 -0
- package/dist/controllers/ReportController.d.ts +7 -0
- package/dist/controllers/ReportController.d.ts.map +1 -1
- package/dist/controllers/ReportController.js +75 -2
- package/dist/controllers/ReportsController.d.ts +1 -0
- package/dist/controllers/ReportsController.d.ts.map +1 -1
- package/dist/controllers/ReportsController.js +12 -2
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js +10 -1
- package/dist/controllers/webservice/HarvestRunController.d.ts +13 -0
- package/dist/controllers/webservice/HarvestRunController.d.ts.map +1 -0
- package/dist/controllers/webservice/HarvestRunController.js +148 -0
- package/dist/controllers/webservice/NamedQueryController.d.ts +17 -0
- package/dist/controllers/webservice/NamedQueryController.d.ts.map +1 -0
- package/dist/controllers/webservice/NamedQueryController.js +127 -0
- package/dist/controllers/webservice/RecordController.d.ts.map +1 -1
- package/dist/controllers/webservice/RecordController.js +30 -74
- package/dist/controllers/webservice/ReportController.d.ts +7 -0
- package/dist/controllers/webservice/ReportController.d.ts.map +1 -1
- package/dist/controllers/webservice/ReportController.js +111 -3
- package/dist/form-config/dataRecord-1.0-draft.js +3 -3
- package/dist/form-config/default-1.0-draft.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/model/config/ReportConfig.d.ts +1 -1
- package/dist/model/config/ReportConfig.d.ts.map +1 -1
- package/dist/model/config/ReportConfig.js +2 -2
- package/dist/model/storage/HarvestRunModel.d.ts +140 -0
- package/dist/model/storage/HarvestRunModel.d.ts.map +1 -0
- package/dist/model/storage/HarvestRunModel.js +110 -0
- package/dist/model/storage/ReportModel.d.ts +1 -0
- package/dist/model/storage/ReportModel.d.ts.map +1 -1
- package/dist/model/storage/index.d.ts +1 -0
- package/dist/model/storage/index.d.ts.map +1 -1
- package/dist/model/storage/index.js +10 -2
- package/dist/services/HarvestRunService.d.ts +73 -0
- package/dist/services/HarvestRunService.d.ts.map +1 -0
- package/dist/services/HarvestRunService.js +1317 -0
- package/dist/services/NamedQueryService.d.ts +25 -4
- package/dist/services/NamedQueryService.d.ts.map +1 -1
- package/dist/services/NamedQueryService.js +444 -115
- package/dist/services/ReportsService.d.ts +57 -1
- package/dist/services/ReportsService.d.ts.map +1 -1
- package/dist/services/ReportsService.js +252 -34
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +7 -2
- package/dist/visitor/construct.visitor.d.ts.map +1 -1
- package/dist/visitor/construct.visitor.js +8 -3
- package/dist/waterline-models/HarvestRecordEvent.d.ts +43 -0
- package/dist/waterline-models/HarvestRecordEvent.d.ts.map +1 -0
- package/dist/waterline-models/HarvestRecordEvent.js +107 -0
- package/dist/waterline-models/HarvestRun.d.ts +51 -0
- package/dist/waterline-models/HarvestRun.d.ts.map +1 -0
- package/dist/waterline-models/HarvestRun.js +125 -0
- package/dist/waterline-models/HarvestRunChunk.d.ts +57 -0
- package/dist/waterline-models/HarvestRunChunk.d.ts.map +1 -0
- package/dist/waterline-models/HarvestRunChunk.js +140 -0
- package/dist/waterline-models/index.d.ts +6 -0
- package/dist/waterline-models/index.d.ts.map +1 -1
- package/dist/waterline-models/index.js +10 -1
- package/package.json +27 -27
|
@@ -0,0 +1,1317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Services = void 0;
|
|
37
|
+
const _ = __importStar(require("lodash"));
|
|
38
|
+
const node_crypto_1 = require("node:crypto");
|
|
39
|
+
const rxjs_1 = require("rxjs");
|
|
40
|
+
const CoreService_1 = require("../CoreService");
|
|
41
|
+
const HarvestRunService_1 = require("../HarvestRunService");
|
|
42
|
+
const APIHarvestResponse_1 = require("../model/APIHarvestResponse");
|
|
43
|
+
const HarvestRunModel_1 = require("../model/storage/HarvestRunModel");
|
|
44
|
+
require("../waterline-models/types");
|
|
45
|
+
var Services;
|
|
46
|
+
(function (Services) {
|
|
47
|
+
class HarvestRunService extends CoreService_1.Services.Core.Service {
|
|
48
|
+
_exportedMethods = [
|
|
49
|
+
'submitCompatibilityRecords',
|
|
50
|
+
'submitLegacyRecords',
|
|
51
|
+
'submitChunk',
|
|
52
|
+
'listRuns',
|
|
53
|
+
'getRun',
|
|
54
|
+
'runExists',
|
|
55
|
+
'listRunEvents',
|
|
56
|
+
];
|
|
57
|
+
constructor() {
|
|
58
|
+
super();
|
|
59
|
+
this.logHeader = 'HarvestRunService::';
|
|
60
|
+
}
|
|
61
|
+
asError(error) {
|
|
62
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
63
|
+
}
|
|
64
|
+
resolveBrandId(brand) {
|
|
65
|
+
if (typeof brand === 'string') {
|
|
66
|
+
return brand.trim();
|
|
67
|
+
}
|
|
68
|
+
return String(brand?.id ?? brand?.name ?? '').trim();
|
|
69
|
+
}
|
|
70
|
+
resolveRecordTypeName(recordTypeModel) {
|
|
71
|
+
return String(recordTypeModel?.name ?? '').trim();
|
|
72
|
+
}
|
|
73
|
+
nowIso() {
|
|
74
|
+
return new Date().toISOString();
|
|
75
|
+
}
|
|
76
|
+
parsePositiveInt(value, fallback) {
|
|
77
|
+
const parsed = Number.parseInt(String(value ?? ''), 10);
|
|
78
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
79
|
+
}
|
|
80
|
+
harvestRunConfig() {
|
|
81
|
+
const configured = (_.isPlainObject(sails.config?.harvestRuns) ? sails.config.harvestRuns : {});
|
|
82
|
+
return {
|
|
83
|
+
maxRecordsPerChunk: this.parsePositiveInt(configured.maxRecordsPerChunk, 250),
|
|
84
|
+
maxChunkBytes: this.parsePositiveInt(configured.maxChunkBytes, 5_000_000),
|
|
85
|
+
processingChunkTimeoutMinutes: this.parsePositiveInt(configured.processingChunkTimeoutMinutes, 30),
|
|
86
|
+
eventCreateBatchSize: this.parsePositiveInt(configured.eventCreateBatchSize, 250),
|
|
87
|
+
failedSnapshotMaxBytes: this.parsePositiveInt(configured.failedSnapshotMaxBytes, 32 * 1024),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
isProcessingChunkStale(chunk) {
|
|
91
|
+
const submittedAt = new Date(String(chunk.submittedAt ?? '')).getTime();
|
|
92
|
+
if (Number.isNaN(submittedAt)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return Date.now() - submittedAt > this.harvestRunConfig().processingChunkTimeoutMinutes * 60 * 1000;
|
|
96
|
+
}
|
|
97
|
+
normalizeTrackedOperation(value) {
|
|
98
|
+
switch (String(value ?? HarvestRunModel_1.HarvestOperation.upsert).trim()) {
|
|
99
|
+
case HarvestRunModel_1.HarvestOperation.create:
|
|
100
|
+
return HarvestRunModel_1.HarvestOperation.create;
|
|
101
|
+
case HarvestRunModel_1.HarvestOperation.update:
|
|
102
|
+
return HarvestRunModel_1.HarvestOperation.update;
|
|
103
|
+
case HarvestRunModel_1.HarvestOperation.upsert:
|
|
104
|
+
return HarvestRunModel_1.HarvestOperation.upsert;
|
|
105
|
+
case HarvestRunModel_1.HarvestOperation.delete:
|
|
106
|
+
return HarvestRunModel_1.HarvestOperation.delete;
|
|
107
|
+
default:
|
|
108
|
+
return 'invalid';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
normalizeTrackedUpdateStrategy(value) {
|
|
112
|
+
switch (String(value ?? 'replace').trim()) {
|
|
113
|
+
case 'merge':
|
|
114
|
+
return 'merge';
|
|
115
|
+
case 'ignoreIfExists':
|
|
116
|
+
return 'ignoreIfExists';
|
|
117
|
+
default:
|
|
118
|
+
return 'replace';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
buildEmptyCounters() {
|
|
122
|
+
return {
|
|
123
|
+
totalProcessed: 0,
|
|
124
|
+
created: 0,
|
|
125
|
+
updated: 0,
|
|
126
|
+
deleted: 0,
|
|
127
|
+
unchanged: 0,
|
|
128
|
+
failed: 0,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
incrementCounters(counters, outcome) {
|
|
132
|
+
counters.totalProcessed += 1;
|
|
133
|
+
switch (outcome) {
|
|
134
|
+
case HarvestRunModel_1.HarvestOutcome.created:
|
|
135
|
+
counters.created += 1;
|
|
136
|
+
break;
|
|
137
|
+
case HarvestRunModel_1.HarvestOutcome.updated:
|
|
138
|
+
counters.updated += 1;
|
|
139
|
+
break;
|
|
140
|
+
case HarvestRunModel_1.HarvestOutcome.deleted:
|
|
141
|
+
counters.deleted += 1;
|
|
142
|
+
break;
|
|
143
|
+
case HarvestRunModel_1.HarvestOutcome.unchanged:
|
|
144
|
+
counters.unchanged += 1;
|
|
145
|
+
break;
|
|
146
|
+
case HarvestRunModel_1.HarvestOutcome.failed:
|
|
147
|
+
default:
|
|
148
|
+
counters.failed += 1;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
normalizeMetadata(recordRequest) {
|
|
153
|
+
const metadata = _.get(recordRequest, 'metadata');
|
|
154
|
+
if (_.isPlainObject(metadata)) {
|
|
155
|
+
return metadata;
|
|
156
|
+
}
|
|
157
|
+
return (_.isPlainObject(recordRequest) ? recordRequest : {});
|
|
158
|
+
}
|
|
159
|
+
isMetadataEqual(meta1, meta2) {
|
|
160
|
+
return _.isEqual(meta1, meta2);
|
|
161
|
+
}
|
|
162
|
+
async updateRunWithOptimisticRetry(run, criteriaFields, buildUpdates) {
|
|
163
|
+
const runId = String(run.id ?? '').trim();
|
|
164
|
+
if (_.isEmpty(runId)) {
|
|
165
|
+
throw new Error('Harvest run identifier is required to persist counters.');
|
|
166
|
+
}
|
|
167
|
+
let currentRun = run;
|
|
168
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
169
|
+
const criteria = { id: runId };
|
|
170
|
+
for (const field of criteriaFields) {
|
|
171
|
+
if (!_.isUndefined(currentRun[field])) {
|
|
172
|
+
criteria[field] = currentRun[field];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const updates = buildUpdates(currentRun);
|
|
176
|
+
const updated = await HarvestRun.updateOne(criteria).set(updates);
|
|
177
|
+
if (updated) {
|
|
178
|
+
return updated;
|
|
179
|
+
}
|
|
180
|
+
const reloaded = await HarvestRun.findOne({ id: runId });
|
|
181
|
+
if (!reloaded) {
|
|
182
|
+
return { ...currentRun, ...updates };
|
|
183
|
+
}
|
|
184
|
+
if (_.isMatch(reloaded, updates)) {
|
|
185
|
+
return reloaded;
|
|
186
|
+
}
|
|
187
|
+
currentRun = reloaded;
|
|
188
|
+
}
|
|
189
|
+
throw new Error(`Harvest run ${runId} was modified concurrently and could not be updated safely.`);
|
|
190
|
+
}
|
|
191
|
+
getHarvestRunCollection() {
|
|
192
|
+
const datastore = typeof HarvestRun.getDatastore === 'function'
|
|
193
|
+
? HarvestRun.getDatastore()
|
|
194
|
+
: null;
|
|
195
|
+
if (!datastore?.manager || typeof datastore.manager.collection !== 'function') {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return datastore.manager.collection('harvestrun');
|
|
199
|
+
}
|
|
200
|
+
toNativeRunId(runId, collection) {
|
|
201
|
+
if (!runId || _.isEmpty(runId)) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const createPk = collection?.s?.pkFactory?.createPk;
|
|
205
|
+
if (typeof createPk !== 'function') {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const sampleId = createPk();
|
|
209
|
+
if (!sampleId || typeof sampleId !== 'object') {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
const ObjectIdConstructor = sampleId.constructor;
|
|
213
|
+
if (!ObjectIdConstructor || typeof ObjectIdConstructor !== 'function') {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
if (typeof ObjectIdConstructor.isValid === 'function' && !ObjectIdConstructor.isValid(runId)) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
const nativeRunId = new ObjectIdConstructor(runId);
|
|
221
|
+
return typeof nativeRunId.toHexString === 'function' ? nativeRunId : null;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
extractUpdatedRun(result) {
|
|
228
|
+
if (_.isNil(result)) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const normalizeRow = (row) => {
|
|
232
|
+
if (_.isNil(row)) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const rawId = row._id;
|
|
236
|
+
if (_.isNil(row.id) && !_.isNil(rawId)) {
|
|
237
|
+
return {
|
|
238
|
+
...row,
|
|
239
|
+
id: String(rawId),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return row;
|
|
243
|
+
};
|
|
244
|
+
if (_.isPlainObject(result) && 'value' in result) {
|
|
245
|
+
return normalizeRow(result.value);
|
|
246
|
+
}
|
|
247
|
+
return normalizeRow(result);
|
|
248
|
+
}
|
|
249
|
+
buildAtomicRunCounterUpdate(counters, completedAt, finalChunk) {
|
|
250
|
+
const failedExpression = {
|
|
251
|
+
$add: [{ $ifNull: ['$failed', 0] }, counters.failed],
|
|
252
|
+
};
|
|
253
|
+
const updateStage = {
|
|
254
|
+
lastChunkAt: completedAt,
|
|
255
|
+
totalProcessed: { $add: [{ $ifNull: ['$totalProcessed', 0] }, counters.totalProcessed] },
|
|
256
|
+
created: { $add: [{ $ifNull: ['$created', 0] }, counters.created] },
|
|
257
|
+
updated: { $add: [{ $ifNull: ['$updated', 0] }, counters.updated] },
|
|
258
|
+
deleted: { $add: [{ $ifNull: ['$deleted', 0] }, counters.deleted] },
|
|
259
|
+
unchanged: { $add: [{ $ifNull: ['$unchanged', 0] }, counters.unchanged] },
|
|
260
|
+
failed: failedExpression,
|
|
261
|
+
chunksProcessed: { $add: [{ $ifNull: ['$chunksProcessed', 0] }, 1] },
|
|
262
|
+
};
|
|
263
|
+
if (finalChunk) {
|
|
264
|
+
updateStage.status = {
|
|
265
|
+
$cond: [
|
|
266
|
+
{ $gt: [failedExpression, 0] },
|
|
267
|
+
HarvestRunModel_1.HarvestRunStatus.completedWithErrors,
|
|
268
|
+
HarvestRunModel_1.HarvestRunStatus.completed,
|
|
269
|
+
],
|
|
270
|
+
};
|
|
271
|
+
updateStage.completedAt = completedAt;
|
|
272
|
+
}
|
|
273
|
+
else if (counters.failed > 0) {
|
|
274
|
+
updateStage.status = {
|
|
275
|
+
$cond: [
|
|
276
|
+
{ $eq: ['$status', HarvestRunModel_1.HarvestRunStatus.completed] },
|
|
277
|
+
HarvestRunModel_1.HarvestRunStatus.completedWithErrors,
|
|
278
|
+
'$status',
|
|
279
|
+
],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
return [{ $set: updateStage }];
|
|
283
|
+
}
|
|
284
|
+
toRunModel(row) {
|
|
285
|
+
return new HarvestRunModel_1.HarvestRunModel({
|
|
286
|
+
id: row.id,
|
|
287
|
+
sourceRunId: String(row.sourceRunId ?? ''),
|
|
288
|
+
brandId: String(row.brandId ?? ''),
|
|
289
|
+
recordType: String(row.recordType ?? ''),
|
|
290
|
+
sourceName: String(row.sourceName ?? ''),
|
|
291
|
+
sourceUri: row.sourceUri ? String(row.sourceUri) : undefined,
|
|
292
|
+
status: row.status ?? HarvestRunModel_1.HarvestRunStatus.running,
|
|
293
|
+
startedAt: String(row.startedAt ?? ''),
|
|
294
|
+
completedAt: row.completedAt ? String(row.completedAt) : undefined,
|
|
295
|
+
startedBy: row.startedBy ? String(row.startedBy) : undefined,
|
|
296
|
+
lastChunkAt: row.lastChunkAt ? String(row.lastChunkAt) : undefined,
|
|
297
|
+
totalProcessed: Number(row.totalProcessed ?? 0),
|
|
298
|
+
created: Number(row.created ?? 0),
|
|
299
|
+
updated: Number(row.updated ?? 0),
|
|
300
|
+
deleted: Number(row.deleted ?? 0),
|
|
301
|
+
unchanged: Number(row.unchanged ?? 0),
|
|
302
|
+
failed: Number(row.failed ?? 0),
|
|
303
|
+
chunksProcessed: Number(row.chunksProcessed ?? 0),
|
|
304
|
+
duplicateChunks: Number(row.duplicateChunks ?? 0),
|
|
305
|
+
metadata: row.metadata ?? undefined,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
toChunkModel(row, duplicateOverride) {
|
|
309
|
+
return new HarvestRunModel_1.HarvestRunChunkModel({
|
|
310
|
+
id: row.id,
|
|
311
|
+
runId: String(row.runId ?? ''),
|
|
312
|
+
brandId: String(row.brandId ?? ''),
|
|
313
|
+
recordType: String(row.recordType ?? ''),
|
|
314
|
+
sourceRunId: String(row.sourceRunId ?? ''),
|
|
315
|
+
contentHash: String(row.contentHash ?? ''),
|
|
316
|
+
attempt: Number(row.attempt ?? 1),
|
|
317
|
+
chunkIndex: row.chunkIndex == null ? undefined : Number(row.chunkIndex),
|
|
318
|
+
chunkLabel: row.chunkLabel ? String(row.chunkLabel) : undefined,
|
|
319
|
+
totalExpected: row.totalExpected == null ? undefined : Number(row.totalExpected),
|
|
320
|
+
status: row.status ?? HarvestRunModel_1.HarvestChunkStatus.processed,
|
|
321
|
+
recordCount: Number(row.recordCount ?? 0),
|
|
322
|
+
totalProcessed: Number(row.totalProcessed ?? 0),
|
|
323
|
+
created: Number(row.created ?? 0),
|
|
324
|
+
updated: Number(row.updated ?? 0),
|
|
325
|
+
deleted: Number(row.deleted ?? 0),
|
|
326
|
+
unchanged: Number(row.unchanged ?? 0),
|
|
327
|
+
failed: Number(row.failed ?? 0),
|
|
328
|
+
duplicate: duplicateOverride ?? Boolean(row.duplicate),
|
|
329
|
+
submittedAt: String(row.submittedAt ?? ''),
|
|
330
|
+
completedAt: row.completedAt ? String(row.completedAt) : undefined,
|
|
331
|
+
errorMessage: row.errorMessage ? String(row.errorMessage) : undefined,
|
|
332
|
+
responseSummary: row.responseSummary ?? undefined,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
toEventModel(row) {
|
|
336
|
+
const outcome = row.outcome ?? HarvestRunModel_1.HarvestOutcome.failed;
|
|
337
|
+
return new HarvestRunModel_1.HarvestRecordEventModel({
|
|
338
|
+
id: row.id,
|
|
339
|
+
runId: String(row.runId ?? ''),
|
|
340
|
+
chunkId: String(row.chunkId ?? ''),
|
|
341
|
+
brandId: String(row.brandId ?? ''),
|
|
342
|
+
recordType: String(row.recordType ?? ''),
|
|
343
|
+
sourceRunId: String(row.sourceRunId ?? ''),
|
|
344
|
+
harvestId: String(row.harvestId ?? ''),
|
|
345
|
+
oid: row.oid ? String(row.oid) : undefined,
|
|
346
|
+
operation: row.operation ?? HarvestRunModel_1.HarvestOperation.upsert,
|
|
347
|
+
outcome,
|
|
348
|
+
status: row.status == null ? outcome !== HarvestRunModel_1.HarvestOutcome.failed : Boolean(row.status),
|
|
349
|
+
message: row.message ? String(row.message) : undefined,
|
|
350
|
+
details: row.details ? String(row.details) : undefined,
|
|
351
|
+
errorCode: row.errorCode ? String(row.errorCode) : undefined,
|
|
352
|
+
recordSnapshot: row.recordSnapshot ?? undefined,
|
|
353
|
+
createdAt: String(row.createdAt ?? ''),
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
async findExistingHarvestRecord(harvestId, recordType) {
|
|
357
|
+
return await Record.find({
|
|
358
|
+
harvestId,
|
|
359
|
+
'metaMetadata.type': recordType,
|
|
360
|
+
}).meta({
|
|
361
|
+
enableExperimentalDeepTargets: true,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
async findExistingTrackedHarvestRecordsBatch(brandId, harvestIds, recordType) {
|
|
365
|
+
const uniqueHarvestIds = _.uniq(harvestIds.filter(harvestId => !_.isEmpty(harvestId)));
|
|
366
|
+
if (uniqueHarvestIds.length === 0) {
|
|
367
|
+
return new Map();
|
|
368
|
+
}
|
|
369
|
+
const rows = await Record.find({
|
|
370
|
+
harvestId: { in: uniqueHarvestIds },
|
|
371
|
+
'metaMetadata.type': recordType,
|
|
372
|
+
'metaMetadata.brandId': brandId,
|
|
373
|
+
}).meta({
|
|
374
|
+
enableExperimentalDeepTargets: true,
|
|
375
|
+
});
|
|
376
|
+
const byHarvestId = new Map();
|
|
377
|
+
for (const row of rows) {
|
|
378
|
+
const harvestId = String(row.harvestId ?? '').trim();
|
|
379
|
+
if (_.isEmpty(harvestId)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const matches = byHarvestId.get(harvestId) ?? [];
|
|
383
|
+
matches.push(row);
|
|
384
|
+
byHarvestId.set(harvestId, matches);
|
|
385
|
+
}
|
|
386
|
+
return byHarvestId;
|
|
387
|
+
}
|
|
388
|
+
async legacyUpdateHarvestRecord(brand, recordTypeModel, updateMode, body, oid, harvestId, user) {
|
|
389
|
+
const shouldMerge = updateMode === 'merge';
|
|
390
|
+
try {
|
|
391
|
+
const record = await RecordsService.getMeta(oid);
|
|
392
|
+
if (_.isEmpty(record)) {
|
|
393
|
+
return new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, false, `Failed to update meta, cannot find existing record with oid: ${oid}`);
|
|
394
|
+
}
|
|
395
|
+
if (shouldMerge) {
|
|
396
|
+
record['metadata'] = _.mergeWith(record.metadata, body, (objValue, srcValue) => {
|
|
397
|
+
if (_.isArray(objValue)) {
|
|
398
|
+
return objValue.concat(srcValue);
|
|
399
|
+
}
|
|
400
|
+
return undefined;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
record['metadata'] = body;
|
|
405
|
+
}
|
|
406
|
+
const sourceMetadata = body?.['sourceMetadata'];
|
|
407
|
+
if (!_.isEmpty(sourceMetadata)) {
|
|
408
|
+
record['metaMetadata']['sourceMetadata'] = `${sourceMetadata}`;
|
|
409
|
+
}
|
|
410
|
+
await RecordsService.updateMeta(brand, oid, record, user);
|
|
411
|
+
return new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, true, shouldMerge ? 'Record merged successfully' : 'Record updated successfully');
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
const result = new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, false, error instanceof Error ? error.message : 'Failed to update meta');
|
|
415
|
+
this.logger.error(`${this.logHeader} Failed to update harvest record ${oid}`, error);
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
async legacyCreateHarvestRecord(brand, recordTypeModel, body, harvestId, updateMode, user) {
|
|
420
|
+
const metadata = body?.['metadata'];
|
|
421
|
+
const workflowStage = body?.['workflowStage'];
|
|
422
|
+
const request = {};
|
|
423
|
+
if (updateMode !== 'create') {
|
|
424
|
+
request['harvestId'] = harvestId;
|
|
425
|
+
}
|
|
426
|
+
request['metadata'] = metadata == null ? body : metadata;
|
|
427
|
+
try {
|
|
428
|
+
const response = await RecordsService.create(brand, request, recordTypeModel, user);
|
|
429
|
+
if (workflowStage) {
|
|
430
|
+
try {
|
|
431
|
+
const wfStep = await (0, rxjs_1.firstValueFrom)(WorkflowStepsService.get(recordTypeModel, String(workflowStage)));
|
|
432
|
+
RecordsService.setWorkflowStepRelatedMetadata(request, wfStep);
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
this.logger.warn(`${this.logHeader} Failed to resolve workflow step ${String(workflowStage)}`, error);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (response.isSuccessful()) {
|
|
439
|
+
return new APIHarvestResponse_1.APIHarvestResponse(harvestId, response.oid, true, 'Record created successfully');
|
|
440
|
+
}
|
|
441
|
+
this.logger.error(`${this.logHeader} Record creation failed for harvestId ${harvestId}`);
|
|
442
|
+
return new APIHarvestResponse_1.APIHarvestResponse(harvestId, '', false, 'Record creation failed');
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
this.logger.error(`${this.logHeader} Exception creating harvest record ${harvestId}`, error);
|
|
446
|
+
return new APIHarvestResponse_1.APIHarvestResponse(harvestId, '', false, String(error));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
buildTrackedFailureResponse(harvestId, operation, message, details = '', oid = '') {
|
|
450
|
+
return {
|
|
451
|
+
harvestId,
|
|
452
|
+
oid,
|
|
453
|
+
operation: String(operation),
|
|
454
|
+
outcome: HarvestRunModel_1.HarvestOutcome.failed,
|
|
455
|
+
status: false,
|
|
456
|
+
message,
|
|
457
|
+
details,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
async createTrackedRecord(brand, recordTypeModel, recordRequest, harvestId, user) {
|
|
461
|
+
const request = {
|
|
462
|
+
harvestId,
|
|
463
|
+
metadata: this.normalizeMetadata(recordRequest),
|
|
464
|
+
};
|
|
465
|
+
try {
|
|
466
|
+
const response = await RecordsService.create(brand, request, recordTypeModel, user);
|
|
467
|
+
if (response.isSuccessful()) {
|
|
468
|
+
return {
|
|
469
|
+
harvestId,
|
|
470
|
+
oid: String(response.oid ?? ''),
|
|
471
|
+
operation: HarvestRunModel_1.HarvestOperation.create,
|
|
472
|
+
outcome: HarvestRunModel_1.HarvestOutcome.created,
|
|
473
|
+
status: true,
|
|
474
|
+
message: 'Record created successfully',
|
|
475
|
+
details: '',
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
return this.buildTrackedFailureResponse(harvestId, HarvestRunModel_1.HarvestOperation.create, String(response.message ?? 'Record creation failed'), typeof response.details === 'string' ? response.details : '');
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
return this.buildTrackedFailureResponse(harvestId, HarvestRunModel_1.HarvestOperation.create, this.asError(error).message);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async updateTrackedRecord(brand, recordTypeModel, metadata, oid, user, strategy) {
|
|
485
|
+
const shouldMerge = strategy === 'merge';
|
|
486
|
+
try {
|
|
487
|
+
const record = await RecordsService.getMeta(oid);
|
|
488
|
+
if (_.isEmpty(record)) {
|
|
489
|
+
return {
|
|
490
|
+
success: false,
|
|
491
|
+
message: `Failed to update meta, cannot find existing record with oid: ${oid}`,
|
|
492
|
+
details: '',
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
const previousRecord = _.cloneDeep(record);
|
|
496
|
+
if (shouldMerge) {
|
|
497
|
+
record['metadata'] = _.mergeWith(record.metadata, metadata, (objValue, srcValue) => {
|
|
498
|
+
if (_.isArray(objValue)) {
|
|
499
|
+
return objValue.concat(srcValue);
|
|
500
|
+
}
|
|
501
|
+
return undefined;
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
record['metadata'] = metadata;
|
|
506
|
+
}
|
|
507
|
+
const sourceMetadata = metadata['sourceMetadata'];
|
|
508
|
+
if (!_.isEmpty(sourceMetadata)) {
|
|
509
|
+
record['metaMetadata']['sourceMetadata'] = `${sourceMetadata}`;
|
|
510
|
+
}
|
|
511
|
+
const response = await RecordsService.updateMeta(brand, oid, record, user);
|
|
512
|
+
if (!response.isSuccessful()) {
|
|
513
|
+
return {
|
|
514
|
+
success: false,
|
|
515
|
+
message: String(response.message ?? 'Failed to update meta'),
|
|
516
|
+
details: typeof response.details === 'string' ? response.details : '',
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
return {
|
|
520
|
+
success: true,
|
|
521
|
+
message: shouldMerge ? 'Record merged successfully' : 'Record updated successfully',
|
|
522
|
+
details: '',
|
|
523
|
+
previousRecord,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
return {
|
|
528
|
+
success: false,
|
|
529
|
+
message: this.asError(error).message,
|
|
530
|
+
details: '',
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async rollbackCreatedTrackedRecord(oid, recordTypeModel, user) {
|
|
535
|
+
const currentRecord = await RecordsService.getMeta(oid);
|
|
536
|
+
const response = await RecordsService.delete(oid, false, currentRecord, recordTypeModel, user);
|
|
537
|
+
if (!response.isSuccessful()) {
|
|
538
|
+
throw new Error(String(response.message ?? `Failed to rollback created record ${oid}.`));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
async rollbackUpdatedTrackedRecord(brand, oid, previousRecord, user) {
|
|
542
|
+
const response = await RecordsService.updateMeta(brand, oid, _.cloneDeep(previousRecord), user);
|
|
543
|
+
if (!response.isSuccessful()) {
|
|
544
|
+
throw new Error(String(response.message ?? `Failed to rollback updated record ${oid}.`));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async rollbackDeletedTrackedRecord(oid, user) {
|
|
548
|
+
const response = await RecordsService.restoreRecord(oid, user);
|
|
549
|
+
if (!response.isSuccessful()) {
|
|
550
|
+
throw new Error(String(response.message ?? `Failed to rollback deleted record ${oid}.`));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
captureRecordSnapshot(record) {
|
|
554
|
+
const snapshot = {
|
|
555
|
+
harvestId: String(record.harvestId ?? ''),
|
|
556
|
+
operation: String(record.operation ?? HarvestRunModel_1.HarvestOperation.upsert),
|
|
557
|
+
updateStrategy: String(record.updateStrategy ?? 'replace'),
|
|
558
|
+
reason: record.reason,
|
|
559
|
+
recordRequest: _.isPlainObject(record.recordRequest) ? record.recordRequest : undefined,
|
|
560
|
+
};
|
|
561
|
+
const serialized = JSON.stringify(snapshot);
|
|
562
|
+
const maxBytes = this.harvestRunConfig().failedSnapshotMaxBytes;
|
|
563
|
+
if (Buffer.byteLength(serialized, 'utf8') <= maxBytes) {
|
|
564
|
+
return snapshot;
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
truncated: true,
|
|
568
|
+
sizeBytes: Buffer.byteLength(serialized, 'utf8'),
|
|
569
|
+
preview: serialized.slice(0, maxBytes),
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
buildTrackedEvent(run, chunk, recordTypeName, request, response, errorCode) {
|
|
573
|
+
return {
|
|
574
|
+
runId: String(run.id ?? ''),
|
|
575
|
+
chunkId: String(chunk.id ?? ''),
|
|
576
|
+
brandId: String(run.brandId ?? ''),
|
|
577
|
+
recordType: recordTypeName,
|
|
578
|
+
sourceRunId: String(run.sourceRunId ?? ''),
|
|
579
|
+
harvestId: response.harvestId,
|
|
580
|
+
oid: response.oid || undefined,
|
|
581
|
+
operation: response.operation,
|
|
582
|
+
outcome: response.outcome,
|
|
583
|
+
status: response.status,
|
|
584
|
+
message: response.message || undefined,
|
|
585
|
+
details: response.details || undefined,
|
|
586
|
+
errorCode,
|
|
587
|
+
recordSnapshot: response.status ? undefined : this.captureRecordSnapshot(request),
|
|
588
|
+
createdAt: this.nowIso(),
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, errorCode) {
|
|
592
|
+
context.events.push(this.buildTrackedEvent(run, chunk, recordTypeName, request, response, errorCode));
|
|
593
|
+
}
|
|
594
|
+
async persistTrackedEvents(events) {
|
|
595
|
+
if (events.length === 0) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const batchSize = this.harvestRunConfig().eventCreateBatchSize;
|
|
599
|
+
for (let index = 0; index < events.length; index += batchSize) {
|
|
600
|
+
await HarvestRecordEvent.createEach(events.slice(index, index + batchSize));
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
buildCountersFromTrackedEvents(events) {
|
|
604
|
+
const counters = this.buildEmptyCounters();
|
|
605
|
+
for (const event of events) {
|
|
606
|
+
this.incrementCounters(counters, (event.outcome ?? HarvestRunModel_1.HarvestOutcome.failed));
|
|
607
|
+
}
|
|
608
|
+
return counters;
|
|
609
|
+
}
|
|
610
|
+
async listCheckpointedChunkEvents(runId, brandId, chunkIds) {
|
|
611
|
+
const resolvedChunkIds = _.uniq(chunkIds.filter(chunkId => !_.isEmpty(chunkId)));
|
|
612
|
+
if (_.isEmpty(runId) || resolvedChunkIds.length === 0) {
|
|
613
|
+
return [];
|
|
614
|
+
}
|
|
615
|
+
return await HarvestRecordEvent.find({
|
|
616
|
+
runId,
|
|
617
|
+
brandId,
|
|
618
|
+
chunkId: { in: resolvedChunkIds },
|
|
619
|
+
}).sort('createdAt ASC');
|
|
620
|
+
}
|
|
621
|
+
async checkpointChunkProgress(chunkId, recordCount, counters) {
|
|
622
|
+
if (_.isEmpty(chunkId)) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
await HarvestRunChunk.updateOne({ id: chunkId }).set({
|
|
626
|
+
recordCount,
|
|
627
|
+
totalProcessed: counters.totalProcessed,
|
|
628
|
+
created: counters.created,
|
|
629
|
+
updated: counters.updated,
|
|
630
|
+
deleted: counters.deleted,
|
|
631
|
+
unchanged: counters.unchanged,
|
|
632
|
+
failed: counters.failed,
|
|
633
|
+
responseSummary: this.buildChunkResponseSummary(counters),
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
canonicalizeValue(value, seen = new WeakSet()) {
|
|
637
|
+
if (value === undefined) {
|
|
638
|
+
return undefined;
|
|
639
|
+
}
|
|
640
|
+
if (value === null || typeof value === 'boolean') {
|
|
641
|
+
return value;
|
|
642
|
+
}
|
|
643
|
+
if (typeof value === 'string') {
|
|
644
|
+
return value.normalize('NFC');
|
|
645
|
+
}
|
|
646
|
+
if (typeof value === 'number') {
|
|
647
|
+
if (!Number.isFinite(value)) {
|
|
648
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest payload contains an invalid number value.', 400);
|
|
649
|
+
}
|
|
650
|
+
return Object.is(value, -0) ? 0 : value;
|
|
651
|
+
}
|
|
652
|
+
if (typeof value === 'bigint' || typeof value === 'function' || typeof value === 'symbol') {
|
|
653
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest payload contains a non-serializable value.', 400);
|
|
654
|
+
}
|
|
655
|
+
if (Array.isArray(value)) {
|
|
656
|
+
return value.map(entry => this.canonicalizeValue(entry, seen));
|
|
657
|
+
}
|
|
658
|
+
if (value instanceof Date) {
|
|
659
|
+
return value.toISOString();
|
|
660
|
+
}
|
|
661
|
+
if (typeof value === 'object') {
|
|
662
|
+
if (seen.has(value)) {
|
|
663
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest payload contains circular data.', 400);
|
|
664
|
+
}
|
|
665
|
+
seen.add(value);
|
|
666
|
+
const result = Object.keys(value)
|
|
667
|
+
.sort((left, right) => left.localeCompare(right))
|
|
668
|
+
.reduce((acc, key) => {
|
|
669
|
+
const normalized = this.canonicalizeValue(value[key], seen);
|
|
670
|
+
if (normalized !== undefined) {
|
|
671
|
+
acc[key] = normalized;
|
|
672
|
+
}
|
|
673
|
+
return acc;
|
|
674
|
+
}, {});
|
|
675
|
+
seen.delete(value);
|
|
676
|
+
return result;
|
|
677
|
+
}
|
|
678
|
+
return value;
|
|
679
|
+
}
|
|
680
|
+
buildChunkContentHash(brandId, recordTypeName, request) {
|
|
681
|
+
const payload = {
|
|
682
|
+
algorithm: 'redbox-harvest-chunk-v1',
|
|
683
|
+
brandId,
|
|
684
|
+
recordType: recordTypeName,
|
|
685
|
+
sourceName: request.sourceName,
|
|
686
|
+
sourceRunId: request.sourceRunId,
|
|
687
|
+
chunkIndex: request.chunk?.index,
|
|
688
|
+
records: this.canonicalizeValue(request.records),
|
|
689
|
+
};
|
|
690
|
+
return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(payload)).digest('hex');
|
|
691
|
+
}
|
|
692
|
+
validateTrackedChunkRequest(body) {
|
|
693
|
+
const request = (_.isPlainObject(body) ? body : {});
|
|
694
|
+
let serializedRequest;
|
|
695
|
+
try {
|
|
696
|
+
serializedRequest = JSON.stringify(request);
|
|
697
|
+
}
|
|
698
|
+
catch {
|
|
699
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest payload contains non-serializable data.', 400);
|
|
700
|
+
}
|
|
701
|
+
if (Buffer.byteLength(serializedRequest, 'utf8') > this.harvestRunConfig().maxChunkBytes) {
|
|
702
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest request exceeds the configured maximum payload size.', 413);
|
|
703
|
+
}
|
|
704
|
+
const sourceRunId = String(request.sourceRunId ?? '').trim();
|
|
705
|
+
const sourceName = String(request.sourceName ?? '').trim();
|
|
706
|
+
const records = Array.isArray(request.records) ? request.records : [];
|
|
707
|
+
const chunk = (_.isPlainObject(request.chunk) ? request.chunk : {});
|
|
708
|
+
const chunkIndex = chunk.index;
|
|
709
|
+
if (!sourceRunId || !sourceName || records.length === 0 || !Number.isInteger(chunkIndex) || Number(chunkIndex) < 0) {
|
|
710
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Invalid tracked harvest request body.', 400);
|
|
711
|
+
}
|
|
712
|
+
if (records.length > this.harvestRunConfig().maxRecordsPerChunk) {
|
|
713
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest request exceeds the configured maximum records per chunk.', 413);
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
sourceRunId,
|
|
717
|
+
sourceName,
|
|
718
|
+
sourceUri: request.sourceUri ? String(request.sourceUri) : undefined,
|
|
719
|
+
finalChunk: Boolean(request.finalChunk),
|
|
720
|
+
chunk: {
|
|
721
|
+
index: Number(chunkIndex),
|
|
722
|
+
label: chunk.label ? String(chunk.label) : undefined,
|
|
723
|
+
totalExpected: chunk.totalExpected == null ? undefined : Number(chunk.totalExpected),
|
|
724
|
+
},
|
|
725
|
+
records,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
async findOrCreateRun(brand, recordTypeModel, request, user) {
|
|
729
|
+
const brandId = this.resolveBrandId(brand);
|
|
730
|
+
const recordTypeName = this.resolveRecordTypeName(recordTypeModel);
|
|
731
|
+
const where = {
|
|
732
|
+
brandId,
|
|
733
|
+
recordType: recordTypeName,
|
|
734
|
+
sourceName: request.sourceName,
|
|
735
|
+
sourceRunId: request.sourceRunId,
|
|
736
|
+
};
|
|
737
|
+
const existing = await HarvestRun.findOne(where);
|
|
738
|
+
if (existing) {
|
|
739
|
+
return existing;
|
|
740
|
+
}
|
|
741
|
+
const now = this.nowIso();
|
|
742
|
+
try {
|
|
743
|
+
return await HarvestRun.create({
|
|
744
|
+
...where,
|
|
745
|
+
sourceUri: request.sourceUri,
|
|
746
|
+
status: HarvestRunModel_1.HarvestRunStatus.running,
|
|
747
|
+
startedAt: now,
|
|
748
|
+
lastChunkAt: now,
|
|
749
|
+
startedBy: String(user?.username ?? ''),
|
|
750
|
+
totalProcessed: 0,
|
|
751
|
+
created: 0,
|
|
752
|
+
updated: 0,
|
|
753
|
+
deleted: 0,
|
|
754
|
+
unchanged: 0,
|
|
755
|
+
failed: 0,
|
|
756
|
+
chunksProcessed: 0,
|
|
757
|
+
duplicateChunks: 0,
|
|
758
|
+
}).fetch();
|
|
759
|
+
}
|
|
760
|
+
catch (error) {
|
|
761
|
+
const recovered = await HarvestRun.findOne(where);
|
|
762
|
+
if (recovered) {
|
|
763
|
+
return recovered;
|
|
764
|
+
}
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
async updateRunAfterChunk(run, counters, finalChunk, completedAt) {
|
|
769
|
+
const collection = this.getHarvestRunCollection();
|
|
770
|
+
const nativeRunId = this.toNativeRunId(run.id, collection);
|
|
771
|
+
if (collection && nativeRunId) {
|
|
772
|
+
const updated = this.extractUpdatedRun(await collection.findOneAndUpdate({ _id: nativeRunId }, this.buildAtomicRunCounterUpdate(counters, completedAt, finalChunk), { returnDocument: 'after' }));
|
|
773
|
+
if (updated) {
|
|
774
|
+
return updated;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return await this.updateRunWithOptimisticRetry(run, ['totalProcessed', 'created', 'updated', 'deleted', 'unchanged', 'failed', 'chunksProcessed', 'status'], currentRun => {
|
|
778
|
+
const nextFailed = Number(currentRun.failed ?? 0) + counters.failed;
|
|
779
|
+
const updates = {
|
|
780
|
+
lastChunkAt: completedAt,
|
|
781
|
+
totalProcessed: Number(currentRun.totalProcessed ?? 0) + counters.totalProcessed,
|
|
782
|
+
created: Number(currentRun.created ?? 0) + counters.created,
|
|
783
|
+
updated: Number(currentRun.updated ?? 0) + counters.updated,
|
|
784
|
+
deleted: Number(currentRun.deleted ?? 0) + counters.deleted,
|
|
785
|
+
unchanged: Number(currentRun.unchanged ?? 0) + counters.unchanged,
|
|
786
|
+
failed: nextFailed,
|
|
787
|
+
chunksProcessed: Number(currentRun.chunksProcessed ?? 0) + 1,
|
|
788
|
+
};
|
|
789
|
+
if (finalChunk) {
|
|
790
|
+
updates.status = nextFailed > 0 ? HarvestRunModel_1.HarvestRunStatus.completedWithErrors : HarvestRunModel_1.HarvestRunStatus.completed;
|
|
791
|
+
updates.completedAt = completedAt;
|
|
792
|
+
}
|
|
793
|
+
else if (counters.failed > 0 && currentRun.status === HarvestRunModel_1.HarvestRunStatus.completed) {
|
|
794
|
+
updates.status = HarvestRunModel_1.HarvestRunStatus.completedWithErrors;
|
|
795
|
+
}
|
|
796
|
+
return updates;
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
async bumpDuplicateChunkCount(run) {
|
|
800
|
+
const collection = this.getHarvestRunCollection();
|
|
801
|
+
const nativeRunId = this.toNativeRunId(run.id, collection);
|
|
802
|
+
if (collection && nativeRunId) {
|
|
803
|
+
const updated = this.extractUpdatedRun(await collection.findOneAndUpdate({ _id: nativeRunId }, [{
|
|
804
|
+
$set: {
|
|
805
|
+
duplicateChunks: { $add: [{ $ifNull: ['$duplicateChunks', 0] }, 1] },
|
|
806
|
+
lastChunkAt: this.nowIso(),
|
|
807
|
+
},
|
|
808
|
+
}], { returnDocument: 'after' }));
|
|
809
|
+
if (updated) {
|
|
810
|
+
return updated;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
const updatedAt = this.nowIso();
|
|
814
|
+
return await this.updateRunWithOptimisticRetry(run, ['duplicateChunks'], currentRun => ({
|
|
815
|
+
duplicateChunks: Number(currentRun.duplicateChunks ?? 0) + 1,
|
|
816
|
+
lastChunkAt: updatedAt,
|
|
817
|
+
}));
|
|
818
|
+
}
|
|
819
|
+
async processTrackedRecord(brand, recordTypeModel, run, chunk, request, user, context) {
|
|
820
|
+
const recordTypeName = String(run.recordType ?? '');
|
|
821
|
+
const operation = this.normalizeTrackedOperation(request.operation);
|
|
822
|
+
const harvestId = String(request.harvestId ?? '').trim();
|
|
823
|
+
if (!harvestId) {
|
|
824
|
+
const response = this.buildTrackedFailureResponse('', HarvestRunModel_1.HarvestOperation.upsert, 'HarvestId was not specified');
|
|
825
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'missing-harvest-id');
|
|
826
|
+
return { response };
|
|
827
|
+
}
|
|
828
|
+
if (operation === 'invalid') {
|
|
829
|
+
const response = this.buildTrackedFailureResponse(harvestId, String(request.operation ?? ''), 'Invalid record operation supplied.');
|
|
830
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'invalid-operation');
|
|
831
|
+
return { response };
|
|
832
|
+
}
|
|
833
|
+
if (context.duplicateHarvestIds.has(harvestId)) {
|
|
834
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, `HarvestId ${harvestId} appears more than once in this chunk.`);
|
|
835
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'duplicate-harvest-id-in-chunk');
|
|
836
|
+
return { response };
|
|
837
|
+
}
|
|
838
|
+
const existingRecords = context.existingByHarvestId.get(harvestId) ?? [];
|
|
839
|
+
if (existingRecords.length > 1) {
|
|
840
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, `Multiple records were found for harvestId ${harvestId}.`);
|
|
841
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'duplicate-harvest-id');
|
|
842
|
+
return { response };
|
|
843
|
+
}
|
|
844
|
+
const recordRequest = (_.isPlainObject(request.recordRequest) ? request.recordRequest : {});
|
|
845
|
+
const metadata = this.normalizeMetadata(recordRequest);
|
|
846
|
+
const updateStrategy = this.normalizeTrackedUpdateStrategy(request.updateStrategy);
|
|
847
|
+
switch (operation) {
|
|
848
|
+
case HarvestRunModel_1.HarvestOperation.create: {
|
|
849
|
+
if (existingRecords.length > 0) {
|
|
850
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, `Record already exists for harvestId ${harvestId}.`, '', String(existingRecords[0]?.redboxOid ?? ''));
|
|
851
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'record-exists');
|
|
852
|
+
return { response };
|
|
853
|
+
}
|
|
854
|
+
const response = await this.createTrackedRecord(brand, recordTypeModel, recordRequest, harvestId, user);
|
|
855
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, response.status ? undefined : 'create-failed');
|
|
856
|
+
return {
|
|
857
|
+
response,
|
|
858
|
+
rollback: response.status && !_.isEmpty(response.oid)
|
|
859
|
+
? async () => await this.rollbackCreatedTrackedRecord(response.oid, recordTypeModel, user)
|
|
860
|
+
: undefined,
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
case HarvestRunModel_1.HarvestOperation.update: {
|
|
864
|
+
if (existingRecords.length === 0) {
|
|
865
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, `No record was found for harvestId ${harvestId}.`);
|
|
866
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'missing-record');
|
|
867
|
+
return { response };
|
|
868
|
+
}
|
|
869
|
+
const existingRecord = existingRecords[0];
|
|
870
|
+
const oid = String(existingRecord.redboxOid ?? '');
|
|
871
|
+
const existingMetadata = (existingRecord.metadata ?? {});
|
|
872
|
+
if (this.isMetadataEqual(metadata, existingMetadata)) {
|
|
873
|
+
const response = {
|
|
874
|
+
harvestId,
|
|
875
|
+
oid,
|
|
876
|
+
operation,
|
|
877
|
+
outcome: HarvestRunModel_1.HarvestOutcome.unchanged,
|
|
878
|
+
status: true,
|
|
879
|
+
message: `Record metadata is unchanged, skipping update. oid: ${oid}`,
|
|
880
|
+
details: '',
|
|
881
|
+
};
|
|
882
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response);
|
|
883
|
+
return { response };
|
|
884
|
+
}
|
|
885
|
+
const updateResult = await this.updateTrackedRecord(brand, recordTypeModel, metadata, oid, user, updateStrategy);
|
|
886
|
+
const response = {
|
|
887
|
+
harvestId,
|
|
888
|
+
oid,
|
|
889
|
+
operation,
|
|
890
|
+
outcome: updateResult.success ? HarvestRunModel_1.HarvestOutcome.updated : HarvestRunModel_1.HarvestOutcome.failed,
|
|
891
|
+
status: updateResult.success,
|
|
892
|
+
message: updateResult.message,
|
|
893
|
+
details: updateResult.details,
|
|
894
|
+
};
|
|
895
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, updateResult.success ? undefined : 'update-failed');
|
|
896
|
+
return {
|
|
897
|
+
response,
|
|
898
|
+
rollback: updateResult.success && updateResult.previousRecord
|
|
899
|
+
? async () => await this.rollbackUpdatedTrackedRecord(brand, oid, updateResult.previousRecord, user)
|
|
900
|
+
: undefined,
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
case HarvestRunModel_1.HarvestOperation.delete: {
|
|
904
|
+
if (existingRecords.length === 0) {
|
|
905
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, `No record was found for harvestId ${harvestId}.`);
|
|
906
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'missing-record');
|
|
907
|
+
return { response };
|
|
908
|
+
}
|
|
909
|
+
const existingRecord = existingRecords[0];
|
|
910
|
+
const oid = String(existingRecord.redboxOid ?? '');
|
|
911
|
+
try {
|
|
912
|
+
const deleteResponse = await RecordsService.delete(oid, false, existingRecord, recordTypeModel, user);
|
|
913
|
+
const response = {
|
|
914
|
+
harvestId,
|
|
915
|
+
oid,
|
|
916
|
+
operation,
|
|
917
|
+
outcome: deleteResponse.isSuccessful() ? HarvestRunModel_1.HarvestOutcome.deleted : HarvestRunModel_1.HarvestOutcome.failed,
|
|
918
|
+
status: deleteResponse.isSuccessful(),
|
|
919
|
+
message: deleteResponse.isSuccessful()
|
|
920
|
+
? 'Record deleted successfully'
|
|
921
|
+
: String(deleteResponse.message ?? 'Record deletion failed'),
|
|
922
|
+
details: typeof deleteResponse.details === 'string' ? deleteResponse.details : '',
|
|
923
|
+
};
|
|
924
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, response.status ? undefined : 'delete-failed');
|
|
925
|
+
return {
|
|
926
|
+
response,
|
|
927
|
+
rollback: response.status && !_.isEmpty(oid)
|
|
928
|
+
? async () => await this.rollbackDeletedTrackedRecord(oid, user)
|
|
929
|
+
: undefined,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
catch (error) {
|
|
933
|
+
const response = this.buildTrackedFailureResponse(harvestId, operation, this.asError(error).message, '', oid);
|
|
934
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, 'delete-failed');
|
|
935
|
+
return { response };
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
case HarvestRunModel_1.HarvestOperation.upsert:
|
|
939
|
+
default: {
|
|
940
|
+
if (existingRecords.length === 0) {
|
|
941
|
+
const response = await this.createTrackedRecord(brand, recordTypeModel, recordRequest, harvestId, user);
|
|
942
|
+
response.operation = HarvestRunModel_1.HarvestOperation.upsert;
|
|
943
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, response.status ? undefined : 'create-failed');
|
|
944
|
+
return {
|
|
945
|
+
response,
|
|
946
|
+
rollback: response.status && !_.isEmpty(response.oid)
|
|
947
|
+
? async () => await this.rollbackCreatedTrackedRecord(response.oid, recordTypeModel, user)
|
|
948
|
+
: undefined,
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
const existingRecord = existingRecords[0];
|
|
952
|
+
const oid = String(existingRecord.redboxOid ?? '');
|
|
953
|
+
if (updateStrategy === 'ignoreIfExists') {
|
|
954
|
+
const response = {
|
|
955
|
+
harvestId,
|
|
956
|
+
oid,
|
|
957
|
+
operation,
|
|
958
|
+
outcome: HarvestRunModel_1.HarvestOutcome.unchanged,
|
|
959
|
+
status: true,
|
|
960
|
+
message: `Record ignored as the record already exists. oid: ${oid}`,
|
|
961
|
+
details: '',
|
|
962
|
+
};
|
|
963
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response);
|
|
964
|
+
return { response };
|
|
965
|
+
}
|
|
966
|
+
const existingMetadata = (existingRecord.metadata ?? {});
|
|
967
|
+
if (this.isMetadataEqual(metadata, existingMetadata)) {
|
|
968
|
+
const response = {
|
|
969
|
+
harvestId,
|
|
970
|
+
oid,
|
|
971
|
+
operation,
|
|
972
|
+
outcome: HarvestRunModel_1.HarvestOutcome.unchanged,
|
|
973
|
+
status: true,
|
|
974
|
+
message: `Record metadata is unchanged, skipping update. oid: ${oid}`,
|
|
975
|
+
details: '',
|
|
976
|
+
};
|
|
977
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response);
|
|
978
|
+
return { response };
|
|
979
|
+
}
|
|
980
|
+
const updateResult = await this.updateTrackedRecord(brand, recordTypeModel, metadata, oid, user, updateStrategy);
|
|
981
|
+
const response = {
|
|
982
|
+
harvestId,
|
|
983
|
+
oid,
|
|
984
|
+
operation,
|
|
985
|
+
outcome: updateResult.success ? HarvestRunModel_1.HarvestOutcome.updated : HarvestRunModel_1.HarvestOutcome.failed,
|
|
986
|
+
status: updateResult.success,
|
|
987
|
+
message: updateResult.message,
|
|
988
|
+
details: updateResult.details,
|
|
989
|
+
};
|
|
990
|
+
this.bufferTrackedEvent(context, run, chunk, recordTypeName, request, response, updateResult.success ? undefined : 'update-failed');
|
|
991
|
+
return {
|
|
992
|
+
response,
|
|
993
|
+
rollback: updateResult.success && updateResult.previousRecord
|
|
994
|
+
? async () => await this.rollbackUpdatedTrackedRecord(brand, oid, updateResult.previousRecord, user)
|
|
995
|
+
: undefined,
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
async submitCompatibilityRecords(brand, recordTypeModel, body, updateMode, user) {
|
|
1001
|
+
if (body == null || _.isEmpty(body['records'])) {
|
|
1002
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Invalid request body', 400);
|
|
1003
|
+
}
|
|
1004
|
+
const recordType = this.resolveRecordTypeName(recordTypeModel);
|
|
1005
|
+
const records = body['records'];
|
|
1006
|
+
const recordResponses = [];
|
|
1007
|
+
for (const record of records) {
|
|
1008
|
+
const harvestId = String(record['harvestId'] ?? '');
|
|
1009
|
+
if (_.isEmpty(harvestId)) {
|
|
1010
|
+
recordResponses.push(new APIHarvestResponse_1.APIHarvestResponse(harvestId, '', false, 'HarvestId was not specified'));
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
const recordRequest = (_.isPlainObject(record['recordRequest']) ? record['recordRequest'] : undefined);
|
|
1014
|
+
const existingRecord = await this.findExistingHarvestRecord(harvestId, recordType);
|
|
1015
|
+
if (existingRecord.length === 0 || updateMode === 'create') {
|
|
1016
|
+
recordResponses.push(await this.legacyCreateHarvestRecord(brand, recordTypeModel, (recordRequest ?? {}), harvestId, updateMode, user));
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
const oid = String(existingRecord[0]?.redboxOid ?? '');
|
|
1020
|
+
if (updateMode === 'ignore') {
|
|
1021
|
+
recordResponses.push(new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, true, `Record ignored as the record already exists. oid: ${oid}`));
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
const newMetadata = this.normalizeMetadata(recordRequest);
|
|
1025
|
+
const existingMetadata = (existingRecord[0]?.metadata ?? {});
|
|
1026
|
+
if (this.isMetadataEqual(newMetadata, existingMetadata)) {
|
|
1027
|
+
recordResponses.push(new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, true, `Record metadata is unchanged, skipping update. oid: ${oid}`));
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
recordResponses.push(await this.legacyUpdateHarvestRecord(brand, recordTypeModel, updateMode, (recordRequest?.metadata ?? {}), oid, harvestId, user));
|
|
1031
|
+
}
|
|
1032
|
+
return recordResponses;
|
|
1033
|
+
}
|
|
1034
|
+
async submitLegacyRecords(brand, recordTypeModel, body, merge, user) {
|
|
1035
|
+
if (body == null || _.isEmpty(body['records'])) {
|
|
1036
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Invalid request body', 400);
|
|
1037
|
+
}
|
|
1038
|
+
const recordType = this.resolveRecordTypeName(recordTypeModel);
|
|
1039
|
+
const records = body['records'];
|
|
1040
|
+
const responses = [];
|
|
1041
|
+
for (const record of records) {
|
|
1042
|
+
const harvestId = String(record['harvest_id'] ?? '');
|
|
1043
|
+
if (_.isEmpty(harvestId)) {
|
|
1044
|
+
responses.push(new APIHarvestResponse_1.APIHarvestResponse(harvestId, '', false, 'HarvestId was not specified'));
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
const metadata = (_.isPlainObject(record['metadata']) ? record['metadata'] : undefined);
|
|
1048
|
+
const existingRecord = await this.findExistingHarvestRecord(harvestId, recordType);
|
|
1049
|
+
if (existingRecord.length === 0) {
|
|
1050
|
+
responses.push(await this.legacyCreateHarvestRecord(brand, recordTypeModel, (metadata?.data ?? {}), harvestId, 'update', user));
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
const updateMode = merge ? 'merge' : 'update';
|
|
1054
|
+
const oid = String(existingRecord[0]?.redboxOid ?? '');
|
|
1055
|
+
const oldMetadata = (existingRecord[0]?.metadata ?? {});
|
|
1056
|
+
const newMetadata = (metadata?.data ?? {});
|
|
1057
|
+
if (this.isMetadataEqual(newMetadata, oldMetadata)) {
|
|
1058
|
+
responses.push(new APIHarvestResponse_1.APIHarvestResponse(harvestId, oid, true, `skip update of harvestId ${harvestId} oid ${oid} metadata sent is equal to metadata in existing record`));
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
responses.push(await this.legacyUpdateHarvestRecord(brand, recordTypeModel, updateMode, newMetadata, oid, harvestId, user));
|
|
1062
|
+
}
|
|
1063
|
+
return responses;
|
|
1064
|
+
}
|
|
1065
|
+
getDuplicateHarvestIds(records) {
|
|
1066
|
+
const seen = new Set();
|
|
1067
|
+
const duplicates = new Set();
|
|
1068
|
+
for (const record of records) {
|
|
1069
|
+
const harvestId = String(record.harvestId ?? '').trim();
|
|
1070
|
+
if (_.isEmpty(harvestId)) {
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
if (seen.has(harvestId)) {
|
|
1074
|
+
duplicates.add(harvestId);
|
|
1075
|
+
}
|
|
1076
|
+
seen.add(harvestId);
|
|
1077
|
+
}
|
|
1078
|
+
return duplicates;
|
|
1079
|
+
}
|
|
1080
|
+
buildChunkResponseSummary(counters) {
|
|
1081
|
+
return {
|
|
1082
|
+
totalProcessed: counters.totalProcessed,
|
|
1083
|
+
created: counters.created,
|
|
1084
|
+
updated: counters.updated,
|
|
1085
|
+
deleted: counters.deleted,
|
|
1086
|
+
unchanged: counters.unchanged,
|
|
1087
|
+
failed: counters.failed,
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
async findMatchingChunks(runId, contentHash) {
|
|
1091
|
+
if (_.isEmpty(runId)) {
|
|
1092
|
+
return [];
|
|
1093
|
+
}
|
|
1094
|
+
return await HarvestRunChunk.find({
|
|
1095
|
+
runId,
|
|
1096
|
+
contentHash,
|
|
1097
|
+
}).sort('attempt DESC');
|
|
1098
|
+
}
|
|
1099
|
+
async submitChunk(brand, recordTypeModel, requestBody, user) {
|
|
1100
|
+
const request = this.validateTrackedChunkRequest(requestBody);
|
|
1101
|
+
const brandId = this.resolveBrandId(brand);
|
|
1102
|
+
const recordTypeName = this.resolveRecordTypeName(recordTypeModel);
|
|
1103
|
+
const run = await this.findOrCreateRun(brand, recordTypeModel, request, user);
|
|
1104
|
+
const contentHash = this.buildChunkContentHash(brandId, recordTypeName, request);
|
|
1105
|
+
const existingChunks = await this.findMatchingChunks(run.id, contentHash);
|
|
1106
|
+
const processedChunk = existingChunks.find(chunk => chunk.status === HarvestRunModel_1.HarvestChunkStatus.processed);
|
|
1107
|
+
if (processedChunk) {
|
|
1108
|
+
const updatedRun = await this.bumpDuplicateChunkCount(run);
|
|
1109
|
+
return {
|
|
1110
|
+
run: this.toRunModel(updatedRun),
|
|
1111
|
+
chunk: this.toChunkModel(processedChunk, true),
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
const processingChunk = existingChunks.find(chunk => chunk.status === HarvestRunModel_1.HarvestChunkStatus.processing);
|
|
1115
|
+
const resumeChunkIds = existingChunks
|
|
1116
|
+
.filter(chunk => chunk.status === HarvestRunModel_1.HarvestChunkStatus.failed || chunk.status === HarvestRunModel_1.HarvestChunkStatus.failedStale)
|
|
1117
|
+
.map(chunk => String(chunk.id ?? ''));
|
|
1118
|
+
if (processingChunk) {
|
|
1119
|
+
if (!this.isProcessingChunkStale(processingChunk)) {
|
|
1120
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Chunk is already processing', 409);
|
|
1121
|
+
}
|
|
1122
|
+
await HarvestRunChunk.updateOne({ id: processingChunk.id }).set({
|
|
1123
|
+
status: HarvestRunModel_1.HarvestChunkStatus.failedStale,
|
|
1124
|
+
completedAt: this.nowIso(),
|
|
1125
|
+
errorMessage: 'Processing chunk was marked stale before retry.',
|
|
1126
|
+
});
|
|
1127
|
+
resumeChunkIds.push(String(processingChunk.id ?? ''));
|
|
1128
|
+
}
|
|
1129
|
+
const checkpointedEvents = await this.listCheckpointedChunkEvents(run.id, brandId, resumeChunkIds);
|
|
1130
|
+
if (checkpointedEvents.length > request.records.length) {
|
|
1131
|
+
throw new HarvestRunService_1.HarvestRunServiceError('Tracked harvest retry state is inconsistent with the submitted payload.', 409);
|
|
1132
|
+
}
|
|
1133
|
+
const submittedAt = this.nowIso();
|
|
1134
|
+
const nextAttempt = existingChunks.reduce((maxAttempt, chunk) => Math.max(maxAttempt, Number(chunk.attempt ?? 1)), 0) + 1;
|
|
1135
|
+
const createdChunk = await HarvestRunChunk.create({
|
|
1136
|
+
runId: String(run.id ?? ''),
|
|
1137
|
+
brandId,
|
|
1138
|
+
recordType: recordTypeName,
|
|
1139
|
+
sourceRunId: request.sourceRunId,
|
|
1140
|
+
contentHash,
|
|
1141
|
+
attempt: nextAttempt,
|
|
1142
|
+
chunkIndex: request.chunk?.index,
|
|
1143
|
+
chunkLabel: request.chunk?.label,
|
|
1144
|
+
totalExpected: request.chunk?.totalExpected,
|
|
1145
|
+
status: HarvestRunModel_1.HarvestChunkStatus.processing,
|
|
1146
|
+
recordCount: request.records.length,
|
|
1147
|
+
totalProcessed: 0,
|
|
1148
|
+
created: 0,
|
|
1149
|
+
updated: 0,
|
|
1150
|
+
deleted: 0,
|
|
1151
|
+
unchanged: 0,
|
|
1152
|
+
failed: 0,
|
|
1153
|
+
duplicate: false,
|
|
1154
|
+
submittedAt,
|
|
1155
|
+
responseSummary: this.buildChunkResponseSummary(this.buildEmptyCounters()),
|
|
1156
|
+
}).fetch();
|
|
1157
|
+
const counters = this.buildCountersFromTrackedEvents(checkpointedEvents);
|
|
1158
|
+
try {
|
|
1159
|
+
const duplicateHarvestIds = this.getDuplicateHarvestIds(request.records);
|
|
1160
|
+
const existingByHarvestId = await this.findExistingTrackedHarvestRecordsBatch(brandId, request.records.map(record => String(record.harvestId ?? '').trim()), recordTypeName);
|
|
1161
|
+
const context = {
|
|
1162
|
+
duplicateHarvestIds,
|
|
1163
|
+
existingByHarvestId,
|
|
1164
|
+
events: [],
|
|
1165
|
+
};
|
|
1166
|
+
for (const record of request.records.slice(checkpointedEvents.length)) {
|
|
1167
|
+
const processed = await this.processTrackedRecord(brand, recordTypeModel, run, createdChunk, record, user, context);
|
|
1168
|
+
try {
|
|
1169
|
+
await this.persistTrackedEvents(context.events);
|
|
1170
|
+
}
|
|
1171
|
+
catch (error) {
|
|
1172
|
+
context.events = [];
|
|
1173
|
+
if (processed.rollback) {
|
|
1174
|
+
try {
|
|
1175
|
+
await processed.rollback();
|
|
1176
|
+
}
|
|
1177
|
+
catch (rollbackError) {
|
|
1178
|
+
throw new Error(`Failed to persist tracked harvest events: ${this.asError(error).message}. ` +
|
|
1179
|
+
`Record rollback also failed: ${this.asError(rollbackError).message}`);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
throw error;
|
|
1183
|
+
}
|
|
1184
|
+
context.events = [];
|
|
1185
|
+
this.incrementCounters(counters, processed.response.outcome);
|
|
1186
|
+
await this.checkpointChunkProgress(createdChunk.id, request.records.length, counters);
|
|
1187
|
+
}
|
|
1188
|
+
const completedAt = this.nowIso();
|
|
1189
|
+
const chunkUpdates = {
|
|
1190
|
+
status: HarvestRunModel_1.HarvestChunkStatus.processed,
|
|
1191
|
+
recordCount: request.records.length,
|
|
1192
|
+
totalProcessed: counters.totalProcessed,
|
|
1193
|
+
created: counters.created,
|
|
1194
|
+
updated: counters.updated,
|
|
1195
|
+
deleted: counters.deleted,
|
|
1196
|
+
unchanged: counters.unchanged,
|
|
1197
|
+
failed: counters.failed,
|
|
1198
|
+
completedAt,
|
|
1199
|
+
responseSummary: this.buildChunkResponseSummary(counters),
|
|
1200
|
+
};
|
|
1201
|
+
const updatedChunk = await HarvestRunChunk.updateOne({ id: createdChunk.id }).set(chunkUpdates);
|
|
1202
|
+
const updatedRun = await this.updateRunAfterChunk(run, counters, Boolean(request.finalChunk), completedAt);
|
|
1203
|
+
return {
|
|
1204
|
+
run: this.toRunModel(updatedRun),
|
|
1205
|
+
chunk: this.toChunkModel(updatedChunk ?? { ...createdChunk, ...chunkUpdates }),
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
catch (error) {
|
|
1209
|
+
await HarvestRunChunk.updateOne({ id: createdChunk.id }).set({
|
|
1210
|
+
status: HarvestRunModel_1.HarvestChunkStatus.failed,
|
|
1211
|
+
recordCount: request.records.length,
|
|
1212
|
+
totalProcessed: counters.totalProcessed,
|
|
1213
|
+
created: counters.created,
|
|
1214
|
+
updated: counters.updated,
|
|
1215
|
+
deleted: counters.deleted,
|
|
1216
|
+
unchanged: counters.unchanged,
|
|
1217
|
+
failed: counters.failed,
|
|
1218
|
+
completedAt: this.nowIso(),
|
|
1219
|
+
errorMessage: this.asError(error).message,
|
|
1220
|
+
responseSummary: this.buildChunkResponseSummary(counters),
|
|
1221
|
+
});
|
|
1222
|
+
throw error;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
async listRuns(brand, params) {
|
|
1226
|
+
const brandId = this.resolveBrandId(brand);
|
|
1227
|
+
const page = this.parsePositiveInt(params.page, 1);
|
|
1228
|
+
const pageSize = Math.min(100, this.parsePositiveInt(params.pageSize, 20));
|
|
1229
|
+
const skip = (page - 1) * pageSize;
|
|
1230
|
+
const where = { brandId };
|
|
1231
|
+
if (!_.isEmpty(params.status)) {
|
|
1232
|
+
where.status = String(params.status);
|
|
1233
|
+
}
|
|
1234
|
+
if (!_.isEmpty(params.recordType)) {
|
|
1235
|
+
where.recordType = String(params.recordType);
|
|
1236
|
+
}
|
|
1237
|
+
if (!_.isEmpty(params.sourceName)) {
|
|
1238
|
+
where.sourceName = String(params.sourceName);
|
|
1239
|
+
}
|
|
1240
|
+
const startedAtFilters = {};
|
|
1241
|
+
if (params.dateFrom instanceof Date && !Number.isNaN(params.dateFrom.getTime())) {
|
|
1242
|
+
startedAtFilters['>='] = params.dateFrom.toISOString();
|
|
1243
|
+
}
|
|
1244
|
+
if (params.dateTo instanceof Date && !Number.isNaN(params.dateTo.getTime())) {
|
|
1245
|
+
startedAtFilters['<='] = params.dateTo.toISOString();
|
|
1246
|
+
}
|
|
1247
|
+
if (!_.isEmpty(startedAtFilters)) {
|
|
1248
|
+
where.startedAt = startedAtFilters;
|
|
1249
|
+
}
|
|
1250
|
+
const total = await HarvestRun.count(where);
|
|
1251
|
+
const rows = await HarvestRun.find(where).sort('startedAt DESC').skip(skip).limit(pageSize);
|
|
1252
|
+
return {
|
|
1253
|
+
rows: rows.map(row => this.toRunModel(row)),
|
|
1254
|
+
total: Number(total ?? 0),
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
async getRun(brand, runId) {
|
|
1258
|
+
const brandId = this.resolveBrandId(brand);
|
|
1259
|
+
const run = await HarvestRun.findOne({ id: runId, brandId });
|
|
1260
|
+
if (!run) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
const chunks = await HarvestRunChunk.find({ runId, brandId }).sort('submittedAt ASC').limit(100);
|
|
1264
|
+
const events = await HarvestRecordEvent.find({ runId, brandId }).sort('createdAt DESC').limit(20);
|
|
1265
|
+
return {
|
|
1266
|
+
run: this.toRunModel(run),
|
|
1267
|
+
chunks: chunks.map(row => this.toChunkModel(row)),
|
|
1268
|
+
events: events.map(row => this.toEventModel(row)),
|
|
1269
|
+
aggregateCounts: {
|
|
1270
|
+
totalProcessed: Number(run.totalProcessed ?? 0),
|
|
1271
|
+
created: Number(run.created ?? 0),
|
|
1272
|
+
updated: Number(run.updated ?? 0),
|
|
1273
|
+
deleted: Number(run.deleted ?? 0),
|
|
1274
|
+
unchanged: Number(run.unchanged ?? 0),
|
|
1275
|
+
failed: Number(run.failed ?? 0),
|
|
1276
|
+
chunksProcessed: Number(run.chunksProcessed ?? 0),
|
|
1277
|
+
duplicateChunks: Number(run.duplicateChunks ?? 0),
|
|
1278
|
+
},
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
async runExists(brand, runId) {
|
|
1282
|
+
const brandId = this.resolveBrandId(brand);
|
|
1283
|
+
const run = await HarvestRun.findOne({ id: runId, brandId });
|
|
1284
|
+
return !_.isNil(run);
|
|
1285
|
+
}
|
|
1286
|
+
async listRunEvents(brand, runId, params) {
|
|
1287
|
+
const brandId = this.resolveBrandId(brand);
|
|
1288
|
+
const page = this.parsePositiveInt(params.page, 1);
|
|
1289
|
+
const pageSize = Math.min(100, this.parsePositiveInt(params.pageSize, 20));
|
|
1290
|
+
const skip = (page - 1) * pageSize;
|
|
1291
|
+
const where = {
|
|
1292
|
+
runId,
|
|
1293
|
+
brandId,
|
|
1294
|
+
};
|
|
1295
|
+
if (!_.isEmpty(params.outcome)) {
|
|
1296
|
+
where.outcome = String(params.outcome);
|
|
1297
|
+
}
|
|
1298
|
+
if (!_.isEmpty(params.operation)) {
|
|
1299
|
+
where.operation = String(params.operation);
|
|
1300
|
+
}
|
|
1301
|
+
if (!_.isEmpty(params.harvestId)) {
|
|
1302
|
+
where.harvestId = String(params.harvestId);
|
|
1303
|
+
}
|
|
1304
|
+
if (!_.isEmpty(params.oid)) {
|
|
1305
|
+
where.oid = String(params.oid);
|
|
1306
|
+
}
|
|
1307
|
+
const total = await HarvestRecordEvent.count(where);
|
|
1308
|
+
const rows = await HarvestRecordEvent.find(where).sort('createdAt DESC').skip(skip).limit(pageSize);
|
|
1309
|
+
return {
|
|
1310
|
+
rows: rows.map(row => this.toEventModel(row)),
|
|
1311
|
+
total: Number(total ?? 0),
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
Services.HarvestRunService = HarvestRunService;
|
|
1316
|
+
})(Services || (exports.Services = Services = {}));
|
|
1317
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSGFydmVzdFJ1blNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvSGFydmVzdFJ1blNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMENBQTRCO0FBQzVCLDZDQUF5QztBQUN6QywrQkFBa0Q7QUFFbEQsZ0RBQXNEO0FBRXRELDREQUFrTztBQUNsTyxvRUFBaUU7QUFLakUsc0VBYzBDO0FBSzFDLHFDQUFtQztBQTJDbkMsSUFBaUIsUUFBUSxDQWtsRHhCO0FBbGxERCxXQUFpQixRQUFRO0lBQ3ZCLE1BQWEsaUJBQWtCLFNBQVEsc0JBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTztRQUN2QyxnQkFBZ0IsR0FBYTtZQUM5Qyw0QkFBNEI7WUFDNUIscUJBQXFCO1lBQ3JCLGFBQWE7WUFDYixVQUFVO1lBQ1YsUUFBUTtZQUNSLFdBQVc7WUFDWCxlQUFlO1NBQ2hCLENBQUM7UUFFRjtZQUNFLEtBQUssRUFBRSxDQUFDO1lBQ1IsSUFBSSxDQUFDLFNBQVMsR0FBRyxxQkFBcUIsQ0FBQztRQUN6QyxDQUFDO1FBRU8sT0FBTyxDQUFDLEtBQWM7WUFDNUIsT0FBTyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFFTyxjQUFjLENBQUMsS0FBNkI7WUFDbEQsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDOUIsT0FBTyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdEIsQ0FBQztZQUNELE9BQU8sTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksS0FBSyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2RCxDQUFDO1FBRU8s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
|