@sera4/essentia 3.0.11 → 3.0.13-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/cache/index.d.ts +22 -0
  2. package/dist/cache/index.js +166 -0
  3. package/dist/cache/index.js.map +1 -0
  4. package/dist/constants/index.d.ts +6 -0
  5. package/dist/constants/index.js +9 -0
  6. package/dist/constants/index.js.map +1 -0
  7. package/dist/formatter/index.d.ts +37 -0
  8. package/dist/formatter/index.js +75 -0
  9. package/dist/formatter/index.js.map +1 -0
  10. package/dist/hal/index.d.ts +5 -0
  11. package/dist/hal/index.js +69 -0
  12. package/dist/hal/index.js.map +1 -0
  13. package/dist/health/health-logger.d.ts +9 -0
  14. package/dist/health/health-logger.js +34 -0
  15. package/dist/health/health-logger.js.map +1 -0
  16. package/dist/health/index.d.ts +19 -0
  17. package/dist/health/index.js +175 -0
  18. package/dist/health/index.js.map +1 -0
  19. package/dist/helpers/index.d.ts +1 -0
  20. package/dist/helpers/index.js +2 -0
  21. package/dist/helpers/index.js.map +1 -0
  22. package/dist/helpers/test-server-wrapper.d.ts +120 -0
  23. package/dist/helpers/test-server-wrapper.js +165 -0
  24. package/dist/helpers/test-server-wrapper.js.map +1 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +17 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/last-commit.d.ts +1 -0
  29. package/dist/last-commit.js.map +1 -0
  30. package/dist/last_commit/index.d.ts +7 -0
  31. package/dist/last_commit/index.js +83 -0
  32. package/dist/last_commit/index.js.map +1 -0
  33. package/dist/paginator/s4-pagination.d.ts +9 -0
  34. package/dist/paginator/s4-pagination.js +49 -0
  35. package/dist/paginator/s4-pagination.js.map +1 -0
  36. package/dist/paginator/sql-pagination.d.ts +27 -0
  37. package/dist/paginator/sql-pagination.js +166 -0
  38. package/dist/paginator/sql-pagination.js.map +1 -0
  39. package/dist/paper-trail/helpers.d.ts +11 -0
  40. package/dist/paper-trail/helpers.js +74 -0
  41. package/dist/paper-trail/helpers.js.map +1 -0
  42. package/dist/paper-trail/index.d.ts +13 -0
  43. package/dist/paper-trail/index.js +662 -0
  44. package/dist/paper-trail/index.js.map +1 -0
  45. package/dist/prompts/index.d.ts +14 -0
  46. package/dist/prompts/index.js +63 -0
  47. package/dist/prompts/index.js.map +1 -0
  48. package/dist/queue/index.d.ts +166 -0
  49. package/dist/queue/index.js +371 -0
  50. package/dist/queue/index.js.map +1 -0
  51. package/dist/queue/publisher.d.ts +31 -0
  52. package/dist/queue/publisher.js +84 -0
  53. package/dist/queue/publisher.js.map +1 -0
  54. package/dist/queue/queue-logger.d.ts +9 -0
  55. package/dist/queue/queue-logger.js +35 -0
  56. package/dist/queue/queue-logger.js.map +1 -0
  57. package/dist/queue/subscriber.d.ts +39 -0
  58. package/dist/queue/subscriber.js +97 -0
  59. package/dist/queue/subscriber.js.map +1 -0
  60. package/dist/safe_proxy/index.d.ts +13 -0
  61. package/dist/safe_proxy/index.js +54 -0
  62. package/dist/safe_proxy/index.js.map +1 -0
  63. package/dist/serializer/index.d.ts +5 -0
  64. package/dist/serializer/index.js +83 -0
  65. package/dist/serializer/index.js.map +1 -0
  66. package/dist/ts/logger/s4-logger.js +2 -0
  67. package/dist/ts/logger/s4-logger.js.map +1 -1
  68. package/dist/ts/queue/index.js +54 -65
  69. package/dist/ts/queue/index.js.map +1 -1
  70. package/dist/ts/task-scheduler/index.d.ts +130 -0
  71. package/dist/ts/task-scheduler/index.js +259 -0
  72. package/dist/ts/task-scheduler/index.js.map +1 -0
  73. package/package.json +9 -3
  74. package/scripts/publish.sh +46 -0
  75. package/package.tar.gz +0 -0
@@ -0,0 +1,662 @@
1
+ import * as jsdiff from 'diff';
2
+ import _ from 'lodash';
3
+ import helpers from './helpers.js';
4
+ import paginator from "../paginator/sql-pagination.js";
5
+ import { utils } from "../ts/utils/index.js";
6
+ const censorText = "**********";
7
+ let failHard = false;
8
+ let Sequelize = null;
9
+ const paperTrail = {};
10
+ paperTrail.init = (sequelize, sequelizePackage, optionsArg) => {
11
+ Sequelize = sequelizePackage;
12
+ // In case that options is being parsed as a readonly attribute.
13
+ // Or it is not passed at all
14
+ const optsArg = _.cloneDeep(optionsArg || {});
15
+ const defaultOptions = {
16
+ debug: false,
17
+ log: null,
18
+ exclude: [
19
+ 'id',
20
+ 'createdAt',
21
+ 'updatedAt',
22
+ 'deletedAt',
23
+ 'created_at',
24
+ 'updated_at',
25
+ 'deleted_at',
26
+ 'audit_source',
27
+ 'revision',
28
+ ],
29
+ // additional fields to exclude on a global basis
30
+ excludeExtras: [],
31
+ excludeVirtualAttributes: true, // by default do not record these
32
+ censor: ["password", "password_salt", "temp_secret", "mfa_totp_secret"],
33
+ revisionAttribute: 'revision',
34
+ revisionModel: 'Revision',
35
+ revisionChangeModel: 'RevisionChange',
36
+ enableRevisionChangeModel: false,
37
+ UUID: false,
38
+ // does this project use int's and UUIDs for some references (postgres)
39
+ mixedDocumentReference: false,
40
+ underscored: false,
41
+ underscoredAttributes: false,
42
+ // always store these keys in a reference value if seen
43
+ includeReferences: [],
44
+ defaultAttributes: {
45
+ documentId: 'documentId',
46
+ revisionId: 'revisionId',
47
+ autoGenerated: 'autoGenerated'
48
+ },
49
+ als: null,
50
+ userModel: false,
51
+ userModelAttribute: 'userId',
52
+ tenantModel: false,
53
+ tenantModelAttribute: 'tenantId',
54
+ enableCompression: false,
55
+ enableMigration: false,
56
+ enableStrictDiff: true,
57
+ continuationNamespace: null,
58
+ continuationKey: 'userId',
59
+ continuationTenantKey: 'tenantId',
60
+ metaDataFields: null,
61
+ metaDataContinuationKey: 'metaData',
62
+ mysql: false,
63
+ };
64
+ if (optsArg.mixedDocumentReference)
65
+ defaultOptions.defaultAttributes.documentUuid = "documentUuid";
66
+ if (optsArg.underscoredAttributes) {
67
+ helpers.toUnderscored(defaultOptions.defaultAttributes);
68
+ }
69
+ // deals with not wanting to overwrite the initial ones, just add some
70
+ if (optsArg.excludeExtras) {
71
+ if (optsArg.exclude) {
72
+ optsArg.exclude = [...optsArg.exclude, ...optsArg.excludeExtras];
73
+ }
74
+ else {
75
+ optsArg.exclude = [...defaultOptions.exclude, ...optsArg.excludeExtras];
76
+ }
77
+ }
78
+ const options = _.defaults(optsArg, defaultOptions);
79
+ const log = options.log || console.log;
80
+ function createBeforeHook(operation) {
81
+ const beforeHook = function beforeHook(instance, opt) {
82
+ if (options.debug) {
83
+ log('beforeHook called');
84
+ log('instance:', instance);
85
+ log('opt:', opt);
86
+ }
87
+ if (opt.noPaperTrail) {
88
+ if (options.debug) {
89
+ log('noPaperTrail opt: is true, not logging');
90
+ }
91
+ return;
92
+ }
93
+ const destroyOperation = operation === 'destroy';
94
+ const restoreOperation = operation === 'restore';
95
+ let previousVersion = _.cloneDeep(instance._previousDataValues);
96
+ let currentVersion = _.cloneDeep(instance.dataValues);
97
+ if (!destroyOperation && options.enableCompression) {
98
+ _.forEach(opt.fields, a => {
99
+ previousVersion[a] = instance._previousDataValues[a];
100
+ currentVersion[a] = instance.dataValues[a];
101
+ });
102
+ }
103
+ else {
104
+ previousVersion = instance._previousDataValues;
105
+ currentVersion = instance.dataValues;
106
+ }
107
+ const excludes = options.exclude.concat([...this.extraRevisionAttributesExclude]);
108
+ // Supported nested models, allowing JSONB objects.
109
+ previousVersion = _.omitBy(previousVersion, i => i != null && typeof i === 'object' && !(i instanceof Date || _.isPlainObject(i)));
110
+ previousVersion = _.omit(previousVersion, excludes);
111
+ currentVersion = _.omitBy(currentVersion, i => i != null && typeof i === 'object' && !(i instanceof Date || _.isPlainObject(i)));
112
+ currentVersion = _.omit(currentVersion, excludes);
113
+ // Disallow change of revision
114
+ instance.set(options.revisionAttribute, instance._previousDataValues[options.revisionAttribute]);
115
+ // Get diffs
116
+ const delta = helpers.calcDelta(previousVersion, currentVersion, options.exclude, options.enableStrictDiff);
117
+ const currentRevisionId = instance.get(options.revisionAttribute);
118
+ if (failHard && !currentRevisionId && opt.type === 'UPDATE') {
119
+ throw new Error('Revision Id was undefined');
120
+ }
121
+ if (options.debug) {
122
+ log('delta:', delta);
123
+ log('revisionId', currentRevisionId);
124
+ }
125
+ // Check if all required fields have been provided to the opts / ALS
126
+ if (options.metaDataFields) {
127
+ // get all required field keys as an array
128
+ const requiredFields = _.keys(_.pickBy(options.metaDataFields, function isMetaDataFieldRequired(required) {
129
+ return required;
130
+ }));
131
+ if (requiredFields && requiredFields.length) {
132
+ const store = options.als && options.als.getStore();
133
+ const metaData = (store && store.get(metaDataContinuationKey)) || opt.metaData;
134
+ const requiredFieldsProvided = _.filter(requiredFields, function isMetaDataFieldNonUndefined(field) {
135
+ return metaData[field] !== undefined;
136
+ });
137
+ if (requiredFieldsProvided.length !== requiredFields.length) {
138
+ log('Required fields: ', options.metaDataFields, requiredFields);
139
+ log('Required fields provided: ', metaData, requiredFieldsProvided);
140
+ throw new Error('Not all required fields are provided to paper trail!');
141
+ }
142
+ }
143
+ }
144
+ if (destroyOperation || restoreOperation || (delta && delta.length > 0)) {
145
+ const revisionId = (currentRevisionId || 0) + 1;
146
+ instance.set(options.revisionAttribute, revisionId);
147
+ if (!instance.context) {
148
+ instance.context = {};
149
+ }
150
+ instance.context.delta = delta;
151
+ }
152
+ if (options.debug) {
153
+ log('end of beforeHook');
154
+ }
155
+ };
156
+ return beforeHook;
157
+ }
158
+ function createAfterHook(operation) {
159
+ const afterHook = function afterHook(instance, opt) {
160
+ const store = options.als && options.als.getStore();
161
+ if (options.debug) {
162
+ log('afterHook called');
163
+ log('instance:', instance);
164
+ log('opt:', opt);
165
+ if (store) {
166
+ log(`ALS ${options.continuationKey}:`, store.get(options.continuationKey));
167
+ }
168
+ }
169
+ const destroyOperation = operation === 'destroy';
170
+ const createOperation = operation === 'create';
171
+ const restoreOperation = operation === 'restore';
172
+ if (instance.context &&
173
+ ((instance.context.delta &&
174
+ instance.context.delta.length > 0) ||
175
+ destroyOperation || restoreOperation)) {
176
+ const Revision = sequelize.model(options.revisionModel);
177
+ let RevisionChange;
178
+ if (options.enableRevisionChangeModel) {
179
+ RevisionChange = sequelize.model(options.revisionChangeModel);
180
+ }
181
+ const { delta } = instance.context;
182
+ let previousVersion = {};
183
+ let currentVersion = {};
184
+ if (!destroyOperation && options.enableCompression) {
185
+ opt.fields = opt.fields || instance._options.attributes;
186
+ _.forEach(opt.fields, a => {
187
+ previousVersion[a] = instance._previousDataValues[a];
188
+ currentVersion[a] = instance.dataValues[a];
189
+ });
190
+ }
191
+ else {
192
+ previousVersion = instance._previousDataValues;
193
+ currentVersion = instance.dataValues;
194
+ }
195
+ // we need to support nested Objects in a different way
196
+ // if the type of change is a nested object, we need to lookat the deltas and join the path with periods
197
+ // to get and show the differences.
198
+ // Supported nested models.
199
+ previousVersion = _.omitBy(previousVersion, value => {
200
+ if (value == null)
201
+ return false; // keep null/undefined
202
+ if (value instanceof Date)
203
+ return false; // keep Dates
204
+ if (_.isPlainObject(value))
205
+ return false; // keep plain objects (including nested objects)
206
+ return typeof value === 'object'; // omit if it's an object that's not plain or a Date
207
+ });
208
+ previousVersion = _.omit(previousVersion, options.exclude);
209
+ currentVersion = _.omitBy(currentVersion, value => {
210
+ if (value == null)
211
+ return false;
212
+ if (value instanceof Date)
213
+ return false;
214
+ if (_.isPlainObject(value))
215
+ return false;
216
+ return typeof value === 'object';
217
+ });
218
+ currentVersion = _.omit(currentVersion, options.exclude);
219
+ const store = options.als && options.als.getStore();
220
+ if (store && !store.has(options.continuationKey)) {
221
+ if (failHard)
222
+ throw new Error(`The ALS continuationKey ${options.continuationKey} was not defined.`);
223
+ }
224
+ let objectsChanged = new Set();
225
+ // if the previous version or new version contain objects; push them onto this list
226
+ _.forEach(previousVersion, (value, key) => {
227
+ if (typeof (value) === 'object') {
228
+ objectsChanged.add(key);
229
+ // blank it so we can set it equal to ONLY the values changed in the next segment
230
+ previousVersion[key] = {};
231
+ }
232
+ });
233
+ _.forEach(currentVersion, (value, key) => {
234
+ if (typeof (value) === 'object') {
235
+ objectsChanged.add(key);
236
+ currentVersion[key] = {};
237
+ }
238
+ });
239
+ // we don't want to see a full object; we want to see only
240
+ // x.y.z -> value
241
+ if (delta && objectsChanged.size > 0) {
242
+ // the format of these are A,E,D,N (added, edited, deleted, new) for the kind
243
+ // the array is either the key or key + subkeys ['options','subkey','subkey2'] etc.
244
+ // {kind: 'E', path: Array(2), lhs: false, rhs: true}
245
+ for (const difference of delta) {
246
+ // blank the currentVersion[difference.path[0]]
247
+ // and previousVersion[difference.path[0]]
248
+ _.set(currentVersion, difference.path, difference.rhs);
249
+ _.set(previousVersion, difference.path, difference.lhs);
250
+ }
251
+ ;
252
+ }
253
+ let document;
254
+ if (destroyOperation) {
255
+ document = { oldValues: currentVersion };
256
+ }
257
+ else if (createOperation || restoreOperation) {
258
+ // we want to print out the entire object as values MAY have changed when restoring
259
+ // and for NEW objects, we want the initial state
260
+ document = { newValues: currentVersion };
261
+ }
262
+ else {
263
+ document = { oldValues: previousVersion, newValues: currentVersion };
264
+ }
265
+ const references = _.pick(instance.dataValues, options.includeReferences);
266
+ if (Object.keys(references).length) {
267
+ document['references'] = references;
268
+ }
269
+ if (options.mysql) {
270
+ document = JSON.stringify(document);
271
+ }
272
+ // Build revision
273
+ const query = {
274
+ model: this.name,
275
+ document,
276
+ operation,
277
+ };
278
+ // Add all extra data fields to the query object
279
+ if (options.metaDataFields) {
280
+ const metaData = (store && store.get(options.metaDataContinuationKey)) ||
281
+ opt.metaData;
282
+ if (metaData) {
283
+ _.forEach(options.metaDataFields, function getMetaDataValues(required, field) {
284
+ const value = metaData[field];
285
+ if (options.debug) {
286
+ log(`Adding metaData field to Revision - ${field} => ${value}`);
287
+ }
288
+ if (!(field in query)) {
289
+ query[field] = value;
290
+ }
291
+ else if (options.debug) {
292
+ log(`Revision object already has a value at ${field} => ${query[field]}`);
293
+ log('Not overwriting the original value');
294
+ }
295
+ });
296
+ }
297
+ }
298
+ query[options.defaultAttributes.autoGenerated] = opt.autoGenerated;
299
+ // in case of custom user models that are not 'userId'
300
+ query[options.userModelAttribute] =
301
+ (store && store.get(options.continuationKey)) || opt.userId;
302
+ query[options.tenantModelAttribute] =
303
+ (store && store.get(options.continuationTenantKey)) || opt.tenantId;
304
+ if (options.mixedDocumentReference && utils.isValidUuidV4(instance.id)) {
305
+ query[options.defaultAttributes.documentUuid] = instance.id;
306
+ }
307
+ else {
308
+ query[options.defaultAttributes.documentId] = instance.id;
309
+ }
310
+ const revision = Revision.build(query);
311
+ revision[options.revisionAttribute] = instance.get(options.revisionAttribute);
312
+ return revision
313
+ .save({ transaction: opt.transaction })
314
+ .then(objectRevision => {
315
+ // Loop diffs and create a revision-diff for each
316
+ if (options.enableRevisionChangeModel) {
317
+ _.forEach(delta, difference => {
318
+ const o = helpers.diffToString(difference.item
319
+ ? difference.item.lhs
320
+ : difference.lhs);
321
+ const n = helpers.diffToString(difference.item
322
+ ? difference.item.rhs
323
+ : difference.rhs);
324
+ // let document = difference;
325
+ document = difference;
326
+ let diff = o || n ? jsdiff.diffChars(o, n) : [];
327
+ if (options.mysql) {
328
+ document = JSON.stringify(document);
329
+ diff = JSON.stringify(diff);
330
+ }
331
+ const d = RevisionChange.build({
332
+ path: difference.path[0],
333
+ document,
334
+ diff,
335
+ revisionId: objectRevision.id,
336
+ });
337
+ d.save({ transaction: opt.transaction })
338
+ .then(savedD => {
339
+ // Add diff to revision
340
+ objectRevision[`add${helpers.capitalizeFirstLetter(options.revisionChangeModel)}`](savedD);
341
+ return null;
342
+ })
343
+ .catch(err => {
344
+ log('RevisionChange save error', err);
345
+ throw err;
346
+ });
347
+ });
348
+ }
349
+ return null;
350
+ })
351
+ .catch(err => {
352
+ log('Revision save error', err);
353
+ throw err;
354
+ });
355
+ }
356
+ if (options.debug) {
357
+ log('end of afterHook');
358
+ }
359
+ return null;
360
+ };
361
+ return afterHook;
362
+ }
363
+ // order in which sequelize processes the hooks
364
+ // (1)
365
+ // beforeBulkCreate(instances, options, fn)
366
+ // beforeBulkDestroy(instances, options, fn)
367
+ // beforeBulkUpdate(instances, options, fn)
368
+ // (2)
369
+ // beforeValidate(instance, options, fn)
370
+ // (-)
371
+ // validate
372
+ // (3)
373
+ // afterValidate(instance, options, fn)
374
+ // - or -
375
+ // validationFailed(instance, options, error, fn)
376
+ // (4)
377
+ // beforeCreate(instance, options, fn)
378
+ // beforeDestroy(instance, options, fn)
379
+ // beforeUpdate(instance, options, fn)
380
+ // beforeRestore(instance, options, fn)
381
+ // (-)
382
+ // create
383
+ // destroy
384
+ // update
385
+ // (5)
386
+ // afterCreate(instance, options, fn)
387
+ // afterDestroy(instance, options, fn)
388
+ // afterUpdate(instance, options, fn)
389
+ // afterRestore(instance, options, fn)
390
+ // (6)
391
+ // afterBulkCreate(instances, options, fn)
392
+ // afterBulkDestroy(instances, options, fn)
393
+ // afterBulkUpdate(instances, options, fn)
394
+ // Extend model prototype with "hasPaperTrail" function
395
+ // Call model.hasPaperTrail() to enable revisions for model
396
+ _.assignIn(Sequelize.Model, {
397
+ hasPaperTrail: function hasPaperTrail() {
398
+ if (options.debug) {
399
+ log('Enabling paper trail on', this.name);
400
+ }
401
+ this.rawAttributes[options.revisionAttribute] = {
402
+ type: Sequelize.INTEGER,
403
+ defaultValue: 0,
404
+ };
405
+ this.revisionable = true;
406
+ // not sure if we need this
407
+ this.refreshAttributes();
408
+ this.extraRevisionAttributesExclude = new Set();
409
+ if (options.excludeVirtualAttributes) {
410
+ for (const attribute in this.rawAttributes) {
411
+ if (this.rawAttributes[attribute].type == "VIRTUAL") {
412
+ this.extraRevisionAttributesExclude.add(attribute);
413
+ }
414
+ }
415
+ }
416
+ if (options.enableMigration) {
417
+ const tableName = this.getTableName();
418
+ const queryInterface = sequelize.getQueryInterface();
419
+ queryInterface.describeTable(tableName).then(attributes => {
420
+ if (!attributes[options.revisionAttribute]) {
421
+ if (options.debug) {
422
+ log('adding revision attribute to the database');
423
+ }
424
+ queryInterface
425
+ .addColumn(tableName, options.revisionAttribute, {
426
+ type: Sequelize.INTEGER,
427
+ defaultValue: 0,
428
+ })
429
+ .then(() => null)
430
+ .catch(err => {
431
+ log('something went really wrong..', err);
432
+ return null;
433
+ });
434
+ }
435
+ return null;
436
+ });
437
+ }
438
+ this.addHook('beforeCreate', createBeforeHook('create'));
439
+ this.addHook('beforeDestroy', createBeforeHook('destroy'));
440
+ this.addHook('beforeUpdate', createBeforeHook('update'));
441
+ this.addHook('beforeRestore', createBeforeHook('restore'));
442
+ this.addHook('afterCreate', createAfterHook('create'));
443
+ this.addHook('afterDestroy', createAfterHook('destroy'));
444
+ this.addHook('afterUpdate', createAfterHook('update'));
445
+ this.addHook('afterRestore', createAfterHook('restore'));
446
+ // create association
447
+ if (options.mixedDocumentReference) {
448
+ this.hasMany(sequelize.models[options.revisionModel], {
449
+ constraints: false,
450
+ foreignKey: options.defaultAttributes.documentUuid,
451
+ });
452
+ this.hasMany(sequelize.models[options.revisionModel], {
453
+ foreignKey: options.defaultAttributes.documentId,
454
+ constraints: false,
455
+ scope: {
456
+ model: this.name,
457
+ },
458
+ });
459
+ }
460
+ else {
461
+ return this.hasMany(sequelize.models[options.revisionModel], {
462
+ foreignKey: options.defaultAttributes.documentId,
463
+ constraints: false,
464
+ scope: {
465
+ model: this.name,
466
+ },
467
+ });
468
+ }
469
+ },
470
+ });
471
+ return {
472
+ // TWS-1032 since ALS must be set after a .run()
473
+ // invocation this CANNOT be set on init(). If you would
474
+ // like to use ALS, set it after the first invocation of run()
475
+ setupALS: function (asyncLocalStorage) {
476
+ options.als = asyncLocalStorage;
477
+ },
478
+ alsEnabled: function () {
479
+ return (options.als === true);
480
+ },
481
+ defineModels: function defineModels(db) {
482
+ // Attributes for RevisionModel
483
+ let attributes = {
484
+ model: {
485
+ type: Sequelize.TEXT,
486
+ allowNull: false,
487
+ },
488
+ document: {
489
+ type: Sequelize.JSONB,
490
+ allowNull: false,
491
+ },
492
+ operation: Sequelize.STRING(7),
493
+ };
494
+ if (options.mysql) {
495
+ attributes.document.type = Sequelize.TEXT('MEDIUMTEXT');
496
+ }
497
+ attributes[options.defaultAttributes.documentId] = {
498
+ type: Sequelize.INTEGER,
499
+ allowNull: false,
500
+ };
501
+ attributes[options.defaultAttributes.autoGenerated] = {
502
+ type: Sequelize.BOOLEAN,
503
+ defaultValue: false,
504
+ allowNull: false,
505
+ };
506
+ attributes[options.revisionAttribute] = {
507
+ type: Sequelize.INTEGER,
508
+ allowNull: false,
509
+ };
510
+ attributes[options.userModelAttribute] = {
511
+ type: options.UUID ? Sequelize.UUID : Sequelize.INTEGER,
512
+ allowNull: true
513
+ };
514
+ attributes[options.tenantModelAttribute] = {
515
+ type: options.UUID ? Sequelize.UUID : Sequelize.INTEGER,
516
+ allowNull: true
517
+ };
518
+ if (options.UUID) {
519
+ attributes.id = {
520
+ primaryKey: true,
521
+ type: Sequelize.UUID,
522
+ defaultValue: Sequelize.UUIDV4,
523
+ };
524
+ if (!options.mixedDocumentReference)
525
+ attributes[options.defaultAttributes.documentId].type = Sequelize.UUID;
526
+ attributes[options.userModelAttribute].type = Sequelize.UUID;
527
+ }
528
+ if (options.mixedDocumentReference) {
529
+ attributes[options.defaultAttributes.documentId].allowNull = true;
530
+ attributes[options.defaultAttributes.documentUuid] = {
531
+ type: Sequelize.UUID,
532
+ allowNull: true
533
+ };
534
+ }
535
+ if (options.debug) {
536
+ log('attributes', attributes);
537
+ }
538
+ let indexes = [{
539
+ name: "document_reference_id",
540
+ fields: [options.defaultAttributes.documentId]
541
+ }];
542
+ if (options.userModel)
543
+ indexes.push({ fields: [options.userModelAttribute] });
544
+ if (options.tenantModel)
545
+ indexes.push({ fields: [options.tenantModelAttribute] });
546
+ if (options.mixedDocumentReference) {
547
+ indexes.push({
548
+ name: "document_reference_uuid",
549
+ fields: [options.defaultAttributes.documentUuid]
550
+ });
551
+ }
552
+ // Revision model
553
+ const Revision = sequelize.define(options.revisionModel, attributes, {
554
+ underscored: options.underscored,
555
+ tableName: options.tableName,
556
+ timestamps: true,
557
+ createdAt: options.underscored ? "created_at" : "createdAt",
558
+ updatedAt: options.underscored ? "updated_at" : "updatedAt",
559
+ indexes
560
+ });
561
+ // safely prune down values
562
+ Revision.prototype.toJSON = function () {
563
+ let values = this.get();
564
+ const excludedFields = ["updated_at"];
565
+ // ensure that we always reference the id as document_id
566
+ values.document_id = values.document_id || values.document_uuid;
567
+ delete values.document_uuid;
568
+ _.forEach(defaultOptions.censor, a => {
569
+ if (!utils.isBlank(values.document.newValues) && !utils.isBlank(values.document.newValues[a])) {
570
+ values.document.newValues[a] = censorText;
571
+ }
572
+ if (!utils.isBlank(values.document.oldValues) && !utils.isBlank(values.document.oldValues[a])) {
573
+ values.document.oldValues[a] = censorText;
574
+ }
575
+ });
576
+ return _.omitBy(values, function (value, key) {
577
+ return (excludedFields.includes(key) || (value === null));
578
+ });
579
+ };
580
+ Revision.associate = function associate(models) {
581
+ if (options.debug) {
582
+ log('models', models);
583
+ }
584
+ if (options.userModel) {
585
+ Revision.belongsTo(sequelize.model(options.userModel), options.belongsToUserOptions);
586
+ }
587
+ if (options.tenantModel) {
588
+ Revision.belongsTo(sequelize.model(options.tenantModel), options.belongsToTenantOptions);
589
+ }
590
+ };
591
+ if (options.enableRevisionChangeModel) {
592
+ // Attributes for RevisionChangeModel
593
+ attributes = {
594
+ path: {
595
+ type: Sequelize.TEXT,
596
+ allowNull: false,
597
+ },
598
+ document: {
599
+ type: Sequelize.JSONB,
600
+ allowNull: false,
601
+ },
602
+ diff: {
603
+ type: Sequelize.JSONB,
604
+ allowNull: false,
605
+ },
606
+ };
607
+ if (options.mysql) {
608
+ attributes.document.type = Sequelize.TEXT('MEDIUMTEXT');
609
+ attributes.diff.type = Sequelize.TEXT('MEDIUMTEXT');
610
+ }
611
+ if (options.UUID) {
612
+ attributes.id = {
613
+ primaryKey: true,
614
+ type: Sequelize.UUID,
615
+ defaultValue: Sequelize.UUIDV4,
616
+ };
617
+ }
618
+ // RevisionChange model
619
+ const RevisionChange = sequelize.define(options.revisionChangeModel, attributes, {
620
+ underscored: options.underscored,
621
+ });
622
+ // Set associations
623
+ Revision.hasMany(RevisionChange, {
624
+ foreignKey: options.defaultAttributes.revisionId,
625
+ constraints: false,
626
+ });
627
+ RevisionChange.belongsTo(Revision);
628
+ if (db)
629
+ db[RevisionChange.name] = RevisionChange;
630
+ }
631
+ paginator.paginate(Revision);
632
+ if (db)
633
+ db[Revision.name] = Revision;
634
+ /*
635
+ * We could extract this to a separate function so that having a
636
+ * user model doesn't require different loading
637
+ *
638
+ * or perhaps we could omit this because we are creating the
639
+ * association through the associate call above.
640
+ */
641
+ if (options.userModel) {
642
+ Revision.belongsTo(sequelize.model(options.userModel), {
643
+ as: "account",
644
+ foreignKey: {
645
+ fieldName: options.userModelAttribute
646
+ },
647
+ onDelete: "CASCADE"
648
+ });
649
+ }
650
+ return Revision;
651
+ },
652
+ };
653
+ };
654
+ /**
655
+ * Throw exceptions when the user identifier from ALS is not set or if the
656
+ * revisionAttribute was not loaded on the model.
657
+ */
658
+ paperTrail.enableFailHard = () => {
659
+ failHard = true;
660
+ };
661
+ export default paperTrail;
662
+ //# sourceMappingURL=index.js.map