@jsreport/jsreport-core 3.4.1 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/lib/main/blobStorage/blobStorage.js +8 -0
- package/lib/main/logger.js +3 -0
- package/lib/main/optionsLoad.js +10 -2
- package/lib/main/optionsSchema.js +21 -3
- package/lib/main/profiler.js +166 -75
- package/lib/main/reporter.js +113 -78
- package/lib/main/schemaValidator.js +30 -0
- package/lib/main/settings.js +1 -2
- package/lib/main/store/collection.js +10 -8
- package/lib/main/store/documentStore.js +19 -0
- package/lib/main/store/setupValidateId.js +7 -1
- package/lib/main/store/setupValidateShortid.js +4 -0
- package/lib/shared/normalizeMetaFromLogs.js +1 -1
- package/lib/shared/reporter.js +16 -0
- package/lib/worker/render/executeEngine.js +108 -27
- package/lib/worker/render/moduleHelper.js +4 -4
- package/lib/worker/render/profiler.js +20 -13
- package/lib/worker/render/render.js +0 -4
- package/lib/worker/reporter.js +6 -4
- package/lib/worker/sandbox/{safeSandbox.js → createSandbox.js} +85 -52
- package/lib/worker/sandbox/runInSandbox.js +38 -16
- package/package.json +9 -9
- package/lib/main/monitoring.js +0 -92
package/lib/main/reporter.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
const path = require('path')
|
|
7
7
|
const { Readable } = require('stream')
|
|
8
|
-
const Reaper = require('
|
|
8
|
+
const Reaper = require('@jsreport/reap')
|
|
9
9
|
const optionsLoad = require('./optionsLoad')
|
|
10
10
|
const { createLogger, configureLogger, silentLogs } = require('./logger')
|
|
11
11
|
const checkEntityName = require('./validateEntityName')
|
|
@@ -28,10 +28,10 @@ const Reporter = require('../shared/reporter')
|
|
|
28
28
|
const Request = require('./request')
|
|
29
29
|
const generateRequestId = require('../shared/generateRequestId')
|
|
30
30
|
const Profiler = require('./profiler')
|
|
31
|
-
const Monitoring = require('./monitoring')
|
|
32
31
|
const migrateXlsxTemplatesToAssets = require('./migration/xlsxTemplatesToAssets')
|
|
33
32
|
const migrateResourcesToAssets = require('./migration/resourcesToAssets')
|
|
34
33
|
const semver = require('semver')
|
|
34
|
+
let reportCounter = 0
|
|
35
35
|
|
|
36
36
|
class MainReporter extends Reporter {
|
|
37
37
|
constructor (options, defaults) {
|
|
@@ -69,6 +69,7 @@ class MainReporter extends Reporter {
|
|
|
69
69
|
|
|
70
70
|
this.logger = createLogger()
|
|
71
71
|
this.beforeMainActionListeners = this.createListenerCollection('beforeMainAction')
|
|
72
|
+
this.beforeRenderWorkerAllocatedListeners = this.createListenerCollection('beforeRenderWorkerAllocated')
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
discover () {
|
|
@@ -89,8 +90,8 @@ class MainReporter extends Reporter {
|
|
|
89
90
|
return this
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
async extensionsLoad (
|
|
93
|
-
const appliedConfigFile = await optionsLoad({
|
|
93
|
+
async extensionsLoad (_opts = {}) {
|
|
94
|
+
const [explicitOptions, appliedConfigFile] = await optionsLoad({
|
|
94
95
|
defaults: this.defaults,
|
|
95
96
|
options: this.options,
|
|
96
97
|
validator: this.optionsValidator,
|
|
@@ -105,6 +106,8 @@ class MainReporter extends Reporter {
|
|
|
105
106
|
silentLogs(this.logger)
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
const { onConfigDetails, ...opts } = _opts
|
|
110
|
+
|
|
108
111
|
this.logger.info(`Initializing jsreport (version: ${this.version}, configuration file: ${appliedConfigFile || 'none'}, nodejs: ${process.versions.node})`)
|
|
109
112
|
|
|
110
113
|
await this.extensionsManager.load(opts)
|
|
@@ -129,6 +132,10 @@ class MainReporter extends Reporter {
|
|
|
129
132
|
throw new Error(`options contain values that does not match the defined full root schema. ${rootOptionsValidation.fullErrorMessage}`)
|
|
130
133
|
}
|
|
131
134
|
|
|
135
|
+
if (typeof onConfigDetails === 'function') {
|
|
136
|
+
onConfigDetails(explicitOptions)
|
|
137
|
+
}
|
|
138
|
+
|
|
132
139
|
return this
|
|
133
140
|
}
|
|
134
141
|
|
|
@@ -156,6 +163,7 @@ class MainReporter extends Reporter {
|
|
|
156
163
|
*/
|
|
157
164
|
async init () {
|
|
158
165
|
this.closing = this.closed = false
|
|
166
|
+
|
|
159
167
|
if (this._initialized || this._initializing) {
|
|
160
168
|
throw new Error('jsreport already initialized or just initializing. Make sure init is called only once')
|
|
161
169
|
}
|
|
@@ -165,14 +173,23 @@ class MainReporter extends Reporter {
|
|
|
165
173
|
this._initializing = true
|
|
166
174
|
|
|
167
175
|
if (this.compilation) {
|
|
168
|
-
this.compilation.resource('
|
|
169
|
-
this.compilation.resource('
|
|
170
|
-
this.compilation.resource('
|
|
176
|
+
this.compilation.resource('vm2-events.js', require.resolve('vm2/lib/events.js'))
|
|
177
|
+
this.compilation.resource('vm2-resolver-compat.js', require.resolve('vm2/lib/resolver-compat.js'))
|
|
178
|
+
this.compilation.resource('vm2-resolver.js', require.resolve('vm2/lib/resolver.js'))
|
|
179
|
+
this.compilation.resource('vm2-setup-node-sandbox.js', require.resolve('vm2/lib/setup-node-sandbox.js'))
|
|
180
|
+
this.compilation.resource('vm2-setup-sandbox.js', require.resolve('vm2/lib/setup-sandbox.js'))
|
|
171
181
|
}
|
|
172
182
|
|
|
173
183
|
try {
|
|
174
184
|
this._registerLogMainAction()
|
|
175
|
-
|
|
185
|
+
|
|
186
|
+
let explicitOptions
|
|
187
|
+
|
|
188
|
+
await this.extensionsLoad({
|
|
189
|
+
onConfigDetails: (_explicitOptions) => {
|
|
190
|
+
explicitOptions = _explicitOptions
|
|
191
|
+
}
|
|
192
|
+
})
|
|
176
193
|
|
|
177
194
|
this.documentStore = DocumentStore(Object.assign({}, this.options, { logger: this.logger }), this.entityTypeValidator, this.encryption)
|
|
178
195
|
documentStoreActions(this)
|
|
@@ -180,7 +197,6 @@ class MainReporter extends Reporter {
|
|
|
180
197
|
blobStorageActions(this)
|
|
181
198
|
Templates(this)
|
|
182
199
|
Profiler(this)
|
|
183
|
-
Monitoring(this)
|
|
184
200
|
|
|
185
201
|
this.folders = Object.assign(this.folders, Folders(this))
|
|
186
202
|
|
|
@@ -198,6 +214,14 @@ class MainReporter extends Reporter {
|
|
|
198
214
|
|
|
199
215
|
await this.extensionsManager.init()
|
|
200
216
|
|
|
217
|
+
if (this.options.trustUserCode) {
|
|
218
|
+
this.logger.info('Code sandboxing is disabled, users can potentially penetrate the local system if you allow code from external users to be part of your reports')
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (explicitOptions.trustUserCode == null && explicitOptions.allowLocalFilesAccess != null) {
|
|
222
|
+
this.logger.warn('options.allowLocalFilesAccess is deprecated, use options.trustUserCode instead')
|
|
223
|
+
}
|
|
224
|
+
|
|
201
225
|
this.logger.info(`Using general timeout for rendering (reportTimeout: ${this.options.reportTimeout})`)
|
|
202
226
|
|
|
203
227
|
if (this.options.store.provider === 'memory') {
|
|
@@ -267,8 +291,6 @@ class MainReporter extends Reporter {
|
|
|
267
291
|
name: 'none'
|
|
268
292
|
})
|
|
269
293
|
|
|
270
|
-
this.monitoring.init()
|
|
271
|
-
|
|
272
294
|
this.logger.info('reporter initialized')
|
|
273
295
|
this._initialized = true
|
|
274
296
|
this._initExecution.resolve()
|
|
@@ -306,6 +328,34 @@ class MainReporter extends Reporter {
|
|
|
306
328
|
await validateReservedName(this, c, doc)
|
|
307
329
|
}
|
|
308
330
|
|
|
331
|
+
async _handleRenderError (req, res, err) {
|
|
332
|
+
if (err.code === 'WORKER_TIMEOUT') {
|
|
333
|
+
err.message = 'Report timeout'
|
|
334
|
+
if (req.context.profiling?.lastOperation != null && req.context.profiling?.entity != null) {
|
|
335
|
+
err.message += `. Last profiler operation: (${req.context.profiling.lastOperation.subtype}) ${req.context.profiling.lastOperation.name}`
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (req.context.http != null) {
|
|
339
|
+
const profileUrl = `${req.context.http.baseUrl}/studio/profiles/${req.context.profiling.entity._id}`
|
|
340
|
+
err.message += `. You can inspect and find more details here: ${profileUrl}`
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
err.weak = true
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (err.code === 'WORKER_ABORTED') {
|
|
347
|
+
err.message = 'Report cancelled'
|
|
348
|
+
err.weak = true
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!err.logged) {
|
|
352
|
+
const logFn = err.weak ? this.logger.warn : this.logger.error
|
|
353
|
+
logFn(`Report render failed: ${err.message}${err.stack != null ? ' ' + err.stack : ''}`, req)
|
|
354
|
+
}
|
|
355
|
+
await this.renderErrorListeners.fire(req, res, err)
|
|
356
|
+
throw err
|
|
357
|
+
}
|
|
358
|
+
|
|
309
359
|
/**
|
|
310
360
|
* Main method for invoking rendering
|
|
311
361
|
* render({ template: { content: 'foo', engine: 'none', recipe: 'html' }, data: { foo: 'hello' } })
|
|
@@ -324,23 +374,30 @@ class MainReporter extends Reporter {
|
|
|
324
374
|
req.context = Object.assign({}, req.context)
|
|
325
375
|
req.context.rootId = req.context.rootId || generateRequestId()
|
|
326
376
|
req.context.id = req.context.rootId
|
|
377
|
+
req.context.reportCounter = ++reportCounter
|
|
378
|
+
req.context.startTimestamp = new Date().getTime()
|
|
327
379
|
|
|
328
|
-
|
|
329
|
-
timeout: this.options.reportTimeout
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
let keepWorker
|
|
380
|
+
let worker
|
|
333
381
|
let workerAborted
|
|
382
|
+
let dontCloseProcessing
|
|
383
|
+
const res = { meta: {} }
|
|
384
|
+
try {
|
|
385
|
+
await this.beforeRenderWorkerAllocatedListeners.fire(req)
|
|
334
386
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
workerAborted = true
|
|
338
|
-
worker.release(req).catch((e) => this.logger.error('Failed to release worker ' + e))
|
|
387
|
+
worker = await this._workersManager.allocate(req, {
|
|
388
|
+
timeout: this.getReportTimeout(req)
|
|
339
389
|
})
|
|
340
|
-
}
|
|
341
390
|
|
|
342
|
-
|
|
343
|
-
|
|
391
|
+
if (options.abortEmitter) {
|
|
392
|
+
options.abortEmitter.once('abort', () => {
|
|
393
|
+
if (workerAborted) {
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
workerAborted = true
|
|
397
|
+
worker.release(req).catch((e) => this.logger.error('Failed to release worker ' + e))
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
|
|
344
401
|
if (workerAborted) {
|
|
345
402
|
throw this.createError('Request aborted by client')
|
|
346
403
|
}
|
|
@@ -351,7 +408,7 @@ class MainReporter extends Reporter {
|
|
|
351
408
|
req,
|
|
352
409
|
data: {}
|
|
353
410
|
}, {
|
|
354
|
-
timeout: this.
|
|
411
|
+
timeout: this.getReportTimeout(req)
|
|
355
412
|
})
|
|
356
413
|
req = result
|
|
357
414
|
}
|
|
@@ -369,39 +426,40 @@ class MainReporter extends Reporter {
|
|
|
369
426
|
}
|
|
370
427
|
}
|
|
371
428
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (
|
|
375
|
-
this.options.enableRequestReportTimeout &&
|
|
376
|
-
req.options &&
|
|
377
|
-
req.options.timeout != null
|
|
378
|
-
) {
|
|
379
|
-
reportTimeout = req.options.timeout
|
|
380
|
-
}
|
|
429
|
+
const reportTimeout = this.getReportTimeout(req)
|
|
381
430
|
|
|
382
431
|
await this.beforeRenderListeners.fire(req, res, { worker })
|
|
383
432
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
433
|
+
if (workerAborted) {
|
|
434
|
+
throw this.createError('Request aborted by client')
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (req.context.clientNotification) {
|
|
438
|
+
process.nextTick(async () => {
|
|
439
|
+
try {
|
|
440
|
+
const responseResult = await this.executeWorkerAction('render', {}, {
|
|
441
|
+
timeout: reportTimeout + this.options.reportTimeoutMargin,
|
|
442
|
+
worker
|
|
443
|
+
}, req)
|
|
444
|
+
|
|
445
|
+
Object.assign(res, responseResult)
|
|
446
|
+
await this.afterRenderListeners.fire(req, res)
|
|
447
|
+
} catch (err) {
|
|
448
|
+
await this._handleRenderError(req, res, err).catch((e) => {})
|
|
449
|
+
} finally {
|
|
450
|
+
if (!workerAborted) {
|
|
451
|
+
await worker.release(req)
|
|
452
|
+
}
|
|
402
453
|
}
|
|
403
|
-
}
|
|
404
|
-
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
dontCloseProcessing = true
|
|
457
|
+
const r = {
|
|
458
|
+
...req.context.clientNotification,
|
|
459
|
+
stream: Readable.from(req.context.clientNotification.content)
|
|
460
|
+
}
|
|
461
|
+
delete req.context.clientNotification
|
|
462
|
+
return r
|
|
405
463
|
}
|
|
406
464
|
|
|
407
465
|
if (workerAborted) {
|
|
@@ -418,33 +476,10 @@ class MainReporter extends Reporter {
|
|
|
418
476
|
res.stream = Readable.from(res.content)
|
|
419
477
|
return res
|
|
420
478
|
} catch (err) {
|
|
421
|
-
|
|
422
|
-
err.message = 'Report timeout'
|
|
423
|
-
if (req.context.profiling?.lastOperation != null && req.context.profiling?.entity != null) {
|
|
424
|
-
err.message += `. Last profiler operation: (${req.context.profiling.lastOperation.subtype}) ${req.context.profiling.lastOperation.name}`
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (req.context.http != null) {
|
|
428
|
-
const profileUrl = `${req.context.http.baseUrl}/studio/profiles/${req.context.profiling.entity._id}`
|
|
429
|
-
err.message += `. You can inspect and find more details here: ${profileUrl}`
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
err.weak = true
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (err.code === 'WORKER_ABORTED') {
|
|
436
|
-
err.message = 'Report cancelled'
|
|
437
|
-
err.weak = true
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (!err.logged) {
|
|
441
|
-
const logFn = err.weak ? this.logger.warn : this.logger.error
|
|
442
|
-
logFn(`Report render failed: ${err.message}${err.stack != null ? ' ' + err.stack : ''}`, req)
|
|
443
|
-
}
|
|
444
|
-
await this.renderErrorListeners.fire(req, res, err)
|
|
479
|
+
await this._handleRenderError(req, res, err)
|
|
445
480
|
throw err
|
|
446
481
|
} finally {
|
|
447
|
-
if (!workerAborted && !
|
|
482
|
+
if (worker && !workerAborted && !dontCloseProcessing) {
|
|
448
483
|
await worker.release(req)
|
|
449
484
|
}
|
|
450
485
|
}
|
|
@@ -3,6 +3,7 @@ const set = require('lodash.set')
|
|
|
3
3
|
const hasOwn = require('has-own-deep')
|
|
4
4
|
const unsetValue = require('unset-value')
|
|
5
5
|
const ms = require('ms')
|
|
6
|
+
const bytes = require('bytes')
|
|
6
7
|
const Ajv = require('ajv')
|
|
7
8
|
|
|
8
9
|
const validatorCollection = new WeakMap()
|
|
@@ -126,6 +127,35 @@ class SchemaValidator {
|
|
|
126
127
|
}
|
|
127
128
|
})
|
|
128
129
|
|
|
130
|
+
validator.addKeyword('$jsreport-acceptsSize', {
|
|
131
|
+
modifying: true,
|
|
132
|
+
compile: (sch) => {
|
|
133
|
+
if (sch !== true) {
|
|
134
|
+
return () => true
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return (data, dataPath, parentData, parentDataProperty) => {
|
|
138
|
+
if (typeof data !== 'string' && typeof data !== 'number') {
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (typeof data === 'number') {
|
|
143
|
+
return true
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const newData = bytes(data)
|
|
147
|
+
|
|
148
|
+
if (newData == null) {
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
parentData[parentDataProperty] = newData
|
|
153
|
+
|
|
154
|
+
return true
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
|
|
129
159
|
let rootValidate
|
|
130
160
|
|
|
131
161
|
if (options.rootSchema != null) {
|
package/lib/main/settings.js
CHANGED
|
@@ -25,7 +25,7 @@ Settings.prototype.get = function (key) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
Settings.prototype.findValue = async function (key, req) {
|
|
28
|
-
const res = await this.documentStore.collection('settings').find({ key: key }, req)
|
|
28
|
+
const res = await this.documentStore.collection('settings').find({ key: key }, localReqWithoutAuthorization(req))
|
|
29
29
|
if (res.length !== 1) {
|
|
30
30
|
return null
|
|
31
31
|
}
|
|
@@ -49,7 +49,6 @@ Settings.prototype.addOrSet = async function (key, avalue, req) {
|
|
|
49
49
|
const value = typeof avalue !== 'string' ? JSON.stringify(avalue) : avalue
|
|
50
50
|
|
|
51
51
|
const updateCount = await this.documentStore.collection('settings').update({ key }, { $set: { key: key, value: value } }, localReqWithoutAuthorization(req))
|
|
52
|
-
|
|
53
52
|
if (updateCount === 0) {
|
|
54
53
|
await this.documentStore.collection('settings').insert({ key: key, value: value }, localReqWithoutAuthorization(req))
|
|
55
54
|
return 1
|
|
@@ -86,16 +86,18 @@ module.exports = (entitySet, provider, model, validator, encryption, transaction
|
|
|
86
86
|
validateEntityName(data.name)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
if (req == null || req.context.skipValidationFor !== data) {
|
|
90
|
+
const entityType = model.entitySets[entitySet] ? model.entitySets[entitySet].normalizedEntityTypeName : null
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
if (entityType != null && validator.getSchema(entityType) != null) {
|
|
93
|
+
const validationResult = validator.validate(entityType, data)
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
if (!validationResult.valid) {
|
|
96
|
+
throw createError(`Error when trying to insert into "${entitySet}" collection. input contain values that does not match the schema. ${validationResult.fullErrorMessage}`, {
|
|
97
|
+
weak: true,
|
|
98
|
+
statusCode: 400
|
|
99
|
+
})
|
|
100
|
+
}
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -372,6 +372,10 @@ const DocumentStore = (options, validator, encryption) => {
|
|
|
372
372
|
},
|
|
373
373
|
|
|
374
374
|
async beginTransaction (req) {
|
|
375
|
+
if (this.options.store?.transactions?.enabled === false) {
|
|
376
|
+
return
|
|
377
|
+
}
|
|
378
|
+
|
|
375
379
|
if (req.context.storeTransaction && transactions.has(req.context.storeTransaction)) {
|
|
376
380
|
throw new Error('Can not call store.beginTransaction when an active transaction already exists, make sure you are not calling store.beginTransaction more than once')
|
|
377
381
|
}
|
|
@@ -386,6 +390,10 @@ const DocumentStore = (options, validator, encryption) => {
|
|
|
386
390
|
},
|
|
387
391
|
|
|
388
392
|
async commitTransaction (req) {
|
|
393
|
+
if (this.options.store?.transactions?.enabled === false) {
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
|
|
389
397
|
const tranId = req.context.storeTransaction
|
|
390
398
|
const tran = transactions.get(tranId)
|
|
391
399
|
|
|
@@ -400,6 +408,10 @@ const DocumentStore = (options, validator, encryption) => {
|
|
|
400
408
|
},
|
|
401
409
|
|
|
402
410
|
async rollbackTransaction (req) {
|
|
411
|
+
if (this.options.store?.transactions?.enabled === false) {
|
|
412
|
+
return
|
|
413
|
+
}
|
|
414
|
+
|
|
403
415
|
const tranId = req.context.storeTransaction
|
|
404
416
|
const tran = transactions.get(tranId)
|
|
405
417
|
|
|
@@ -411,6 +423,13 @@ const DocumentStore = (options, validator, encryption) => {
|
|
|
411
423
|
|
|
412
424
|
transactions.delete(tranId)
|
|
413
425
|
delete req.context.storeTransaction
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
generateId () {
|
|
429
|
+
if (this.provider.generateId) {
|
|
430
|
+
return this.provider.generateId()
|
|
431
|
+
}
|
|
432
|
+
return uuidv4()
|
|
414
433
|
}
|
|
415
434
|
}
|
|
416
435
|
|
|
@@ -3,10 +3,16 @@ module.exports = (reporter) => {
|
|
|
3
3
|
reporter.initializeListeners.add('core-validate-id', () => {
|
|
4
4
|
for (const c of Object.keys(reporter.documentStore.collections)) {
|
|
5
5
|
reporter.documentStore.collection(c).beforeInsertListeners.add('validate-id', (doc, req) => {
|
|
6
|
-
|
|
6
|
+
if (req == null || req.context.skipValidationFor !== doc) {
|
|
7
|
+
return validateIdForStoreChange(reporter, c, doc._id, undefined, req)
|
|
8
|
+
}
|
|
7
9
|
})
|
|
8
10
|
|
|
9
11
|
reporter.documentStore.collection(c).beforeUpdateListeners.add('validate-id', async (q, update, opts, req) => {
|
|
12
|
+
if (req != null && req.context.skipValidationFor === update) {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
if (update.$set && opts && opts.upsert === true) {
|
|
11
17
|
await validateIdForStoreChange(reporter, c, update.$set._id, undefined, req)
|
|
12
18
|
}
|
|
@@ -31,6 +31,10 @@ module.exports = (reporter) => {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function validateShortid (reporter, collectionName, doc, originalIdValue, req) {
|
|
34
|
+
if (req != null && req.context.skipValidationFor === doc) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
const shortid = doc.shortid
|
|
35
39
|
|
|
36
40
|
if (!shortid) {
|
|
@@ -13,7 +13,7 @@ module.exports = (level, msg, meta) => {
|
|
|
13
13
|
|
|
14
14
|
// TODO adding cancel looks bad, its before script is adding req.cancel()
|
|
15
15
|
// excluding non relevant properties for the log
|
|
16
|
-
const newMeta = Object.assign({}, omit(meta, ['template', 'options', 'data', 'context', 'timestamp', 'cancel']))
|
|
16
|
+
const newMeta = Object.assign({}, omit(meta, ['rawContent', 'template', 'options', 'data', 'context', 'timestamp', 'cancel']))
|
|
17
17
|
|
|
18
18
|
if (newMeta.rootId == null && meta.context.rootId != null) {
|
|
19
19
|
newMeta.rootId = meta.context.rootId
|
package/lib/shared/reporter.js
CHANGED
|
@@ -51,6 +51,22 @@ class Reporter extends EventEmitter {
|
|
|
51
51
|
return generateRequestId()
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @public Ensures that we get the proper report timeout in case when custom timeout per request was enabled
|
|
56
|
+
*/
|
|
57
|
+
getReportTimeout (req) {
|
|
58
|
+
const elapsedTime = req.context.startTimestamp ? (new Date().getTime() - req.context.startTimestamp) : 0
|
|
59
|
+
if (
|
|
60
|
+
this.options.enableRequestReportTimeout &&
|
|
61
|
+
req.options != null &&
|
|
62
|
+
req.options.timeout != null
|
|
63
|
+
) {
|
|
64
|
+
return Math.max(0, req.options.timeout - elapsedTime)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Math.max(0, this.options.reportTimeout - elapsedTime)
|
|
68
|
+
}
|
|
69
|
+
|
|
54
70
|
/**
|
|
55
71
|
* Ensures that the jsreport auto-cleanup temp directory (options.tempAutoCleanupDirectory) exists by doing a mkdir call
|
|
56
72
|
*
|