@questwork/q-utilities 0.1.18 → 0.1.19

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.
@@ -0,0 +1,3653 @@
1
+
2
+ ;// ./lib/helpers/authorize/authorize.js
3
+ function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
4
+ if (!user) {
5
+ throw new Error('Require login.')
6
+ }
7
+ if (!user.permission) {
8
+ // throw new Error('You do not have any permission.')
9
+ }
10
+ const scopes = user.permission.getScopes(required || {}) || []
11
+ if (!scopes || scopes.length === 0) {
12
+ // throw new Error('You are not allowed in this scope.')
13
+ }
14
+ if (!scopes.includes('*')) {
15
+ query.tenantCode = user.tenantCode
16
+ }
17
+ if (!scopes.includes('TENANT')) {
18
+ query.eventShortCode = user.eventShortCode
19
+ }
20
+ // if (!scopes.includes('EVENT')) {
21
+ // query.eventRegistrationCode = user.eventRegistrationCode
22
+ // }
23
+ if (allowCoordinator) {
24
+ if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
25
+ query.__ALLOW_COORDINATOR = true
26
+ } else {
27
+ if (!scopes.includes('EVENT')) {
28
+ query.eventRegistrationCode = user.eventRegistrationCode
29
+ }
30
+ }
31
+ } else {
32
+ if (!scopes.includes('EVENT')) {
33
+ query.eventRegistrationCode = user.eventRegistrationCode
34
+ }
35
+ }
36
+ if (allowOwner) {
37
+ query.__ALLOW_OWNER = true
38
+ }
39
+ // not good, just use it as example
40
+ if (user.hasExcludedFields) {
41
+ query.__EXCLUDED_FIELDS = user.getExcludedFields(required)
42
+ }
43
+ query.__LOGIN_SUBJECT_CODE = user.loginSubjectCode
44
+ return query
45
+ }
46
+
47
+ ;// ./lib/helpers/authorize/index.js
48
+
49
+
50
+ ;// ./lib/helpers/calculateAge/calculateAge.js
51
+ function calculateAge(timestamp, reference) {
52
+ const birthDate = new Date(timestamp)
53
+ const refDate = reference ? new Date(reference) : new Date()
54
+ // Validate inputs
55
+ if (isNaN(birthDate.getTime())) {
56
+ return null
57
+ }
58
+ if (isNaN(refDate.getTime())) {
59
+ return null
60
+ }
61
+ if (birthDate > refDate) {
62
+ return null
63
+ }
64
+
65
+ // Calculate raw difference
66
+ let age = refDate.getFullYear() - birthDate.getFullYear();
67
+ const monthDiff = refDate.getMonth() - birthDate.getMonth();
68
+
69
+ // Adjust if birthday hasn't occurred yet this year
70
+ if (monthDiff < 0 || (monthDiff === 0 && refDate.getDate() < birthDate.getDate())) {
71
+ age--
72
+ }
73
+
74
+ return age
75
+ }
76
+
77
+ ;// ./lib/helpers/calculateAge/index.js
78
+
79
+
80
+ ;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
81
+ function changeCreatorOwner(that, { source, target }) {
82
+ if (that.meta) {
83
+ if (!that.meta.creator || that.meta.creator === source.getId()) {
84
+ that.meta.creator = target.getId()
85
+ }
86
+ if (!that.meta.owner || that.meta.owner === source.getId()) {
87
+ that.meta.owner = target.getId()
88
+ }
89
+ } else {
90
+ if (!that.creator || that.creator === source.getId()) {
91
+ that.creator = target.getId()
92
+ }
93
+ if (!that.owner || that.owner === source.getId()) {
94
+ that.owner = target.getId()
95
+ }
96
+ }
97
+ return that
98
+ }
99
+
100
+ ;// ./lib/helpers/changeCreatorOwner/index.js
101
+
102
+
103
+ ;// ./lib/helpers/getValidation/getValidation.js
104
+ function getValidation(rule, data, getDataByKey, KeyValueObject) {
105
+ if (!rule) {
106
+ return true
107
+ }
108
+ if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
109
+ return false
110
+ }
111
+ const { key = '', value, placeholder, keyValuePath = '' } = rule
112
+ const [valueAttribute] = Object.keys(value)
113
+
114
+ if (!key && typeof placeholder === 'undefined') {
115
+ switch (valueAttribute) {
116
+ case '$and': {
117
+ return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
118
+ }
119
+ case '$or': {
120
+ return value['$or'].reduce((acc, item) => (acc || getValidation(item, data, getDataByKey, KeyValueObject)), false)
121
+ }
122
+ default:
123
+ return false
124
+ }
125
+ }
126
+ let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
127
+
128
+ // if KeyValue object
129
+ if (keyValuePath) {
130
+ const rowValueData = KeyValueObject.toObject(rowValue)
131
+ rowValue = getDataByKey(keyValuePath, rowValueData)
132
+ }
133
+
134
+ switch (valueAttribute) {
135
+ case '$empty': {
136
+ const isEmpty = rowValue === null || rowValue === undefined
137
+ return isEmpty === value['$empty']
138
+ }
139
+ case '$eq': {
140
+ return rowValue === value['$eq']
141
+ }
142
+ case '$gt': {
143
+ return rowValue > value['$gt']
144
+ }
145
+ case '$gte': {
146
+ return rowValue >= value['$gte']
147
+ }
148
+ case '$hasOverlap': {
149
+ return _hasOverlap(rowValue, value['$hasOverlap'])
150
+ }
151
+ case '$lt': {
152
+ return rowValue < value['$lt']
153
+ }
154
+ case '$lte': {
155
+ return rowValue <= value['$lte']
156
+ }
157
+ case '$in': {
158
+ if (Array.isArray(rowValue)) {
159
+ return !!rowValue.find((e) => (value['$in'].includes(e)))
160
+ }
161
+ if (typeof rowValue !== 'object') {
162
+ return !!value['$in'].includes(rowValue)
163
+ }
164
+ return false
165
+ }
166
+ case '$inValue': {
167
+ const result = getDataByKey(value['$inValue'], data)
168
+ const _value = Array.isArray(result) ? result : []
169
+ if (Array.isArray(rowValue)) {
170
+ return !!rowValue.find((e) => (_value.includes(e)))
171
+ }
172
+ if (typeof rowValue === 'string') {
173
+ return !!_value.includes(rowValue)
174
+ }
175
+ return false
176
+ }
177
+ case '$ne': {
178
+ return rowValue !== value['$ne']
179
+ }
180
+ case '$notIn': {
181
+ if (Array.isArray(rowValue)) {
182
+ return !rowValue.find((e) => (value['$notIn'].includes(e)))
183
+ }
184
+ if (typeof rowValue !== 'object') {
185
+ return !value['$notIn'].includes(rowValue)
186
+ }
187
+ return false
188
+ }
189
+ case '$intervalTimeGt': {
190
+ const now = new Date().getTime()
191
+ const timestamp = new Date(rowValue).getTime()
192
+ return (now - timestamp) > value['$intervalTimeGt']
193
+ }
194
+ case '$intervalTimeLt': {
195
+ const now = new Date().getTime()
196
+ const timestamp = new Date(rowValue).getTime()
197
+ return (now - timestamp) < value['$intervalTimeLt']
198
+ }
199
+ case '$isToday': {
200
+ const currentDate = new Date()
201
+ const start = currentDate.setHours(0,0,0,0)
202
+ const end = currentDate.setHours(23,59,59,59)
203
+ const dateValue = new Date(rowValue).getTime()
204
+ return (start <= dateValue && end >= dateValue) === value['$isToday']
205
+ }
206
+ case '$notInValue': {
207
+ const result = getDataByKey(value['$notInValue'], data)
208
+ const _value = Array.isArray(result) ? result : []
209
+ if (Array.isArray(rowValue)) {
210
+ return !rowValue.find((e) => (_value.includes(e)))
211
+ }
212
+ if (typeof rowValue !== 'object') {
213
+ return !_value.includes(rowValue)
214
+ }
215
+ return false
216
+ }
217
+ case '$range': {
218
+ const [min, max] = value['$range']
219
+ if (typeof min === 'number' && typeof max === 'number' && rowValue >= min && rowValue <= max) {
220
+ return true
221
+ }
222
+ return false
223
+ }
224
+ default:
225
+ return false
226
+ }
227
+
228
+ }
229
+
230
+ function _hasOverlap(item1, item2) {
231
+ let arr1 = item1
232
+ let arr2 = item2
233
+ if (typeof arr1 === 'string') {
234
+ arr1 = arr1.split(',')
235
+ }
236
+ if (typeof arr2 === 'string') {
237
+ arr2 = arr2.split(',')
238
+ }
239
+ const set1 = new Set(arr1)
240
+ return arr2.find((i) => (set1.has(i)))
241
+ }
242
+
243
+ /* harmony default export */ const getValidation_getValidation = ({
244
+ getValidation
245
+ });
246
+
247
+
248
+ ;// ./lib/helpers/getValidation/index.js
249
+
250
+
251
+ ;// ./lib/helpers/formatDate/formatDate.js
252
+
253
+ function formatDate(date, format) {
254
+ const _date = date && date instanceof Date ? date : new Date(date)
255
+ const dayMapChi = ['日','一','二','三','四','五','六']
256
+ const dayMapEng = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
257
+ const dayMapEngShort = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
258
+ const _format = format || 'YYYY/MM/DD hh:mm'
259
+ const e = _date.getDay()
260
+ const ee = dayMapEngShort[e]
261
+ const eee = dayMapChi[e]
262
+ const eeee = dayMapEng[e]
263
+ const y = _date.getFullYear()
264
+ const m = _date.getMonth() + 1
265
+ const d = _date.getDate()
266
+ const h = _date.getHours()
267
+ const mm = _date.getMinutes()
268
+ const s = _date.getSeconds()
269
+
270
+ return _format.replace('YYYY', y)
271
+ .replace('MM', padding(m))
272
+ .replace('MM', padding(m))
273
+ .replace('DD', padding(d))
274
+ .replace('hh', padding(h))
275
+ .replace('mm', padding(mm))
276
+ .replace('ss', padding(s))
277
+ .replace('M', m)
278
+ .replace('D', d)
279
+ .replace('h', h)
280
+ .replace('m', mm)
281
+ .replace('s', s)
282
+ .replace('EEEE', padding(eeee))
283
+ .replace('EEE', padding(eee))
284
+ .replace('EE', padding(ee))
285
+ .replace('E', padding(e))
286
+ }
287
+
288
+ function padding(m) {
289
+ return m < 10 ? `0${m}` : m
290
+ }
291
+
292
+
293
+ /* harmony default export */ const formatDate_formatDate = ({
294
+ formatDate
295
+ });
296
+
297
+
298
+
299
+ ;// ./lib/helpers/formatDate/index.js
300
+
301
+
302
+ ;// ./lib/helpers/getValueByKeys/getValueByKeys.js
303
+ // keys can be array or object or string
304
+ function getValueByKeys_getValueByKeys(keys, data) {
305
+ let _keys = keys
306
+ let _data = data
307
+ if (typeof keys === 'string') {
308
+ _keys = _keys.split('.')
309
+ }
310
+ if (!Array.isArray(keys) && typeof keys === 'object') {
311
+ const { keys: keyArr, obj } = keys
312
+ _keys = keyArr
313
+ _data = obj
314
+ }
315
+ if (_keys.length === 0) {
316
+ return _data
317
+ }
318
+ const firstKey = _keys.shift()
319
+ if (_data && Object.prototype.hasOwnProperty.call(_data, firstKey)) {
320
+ return getValueByKeys_getValueByKeys(_keys, _data[firstKey])
321
+ }
322
+ if (_data && firstKey) {
323
+ if (_keys.length > 0) {
324
+ return getValueByKeys_getValueByKeys(_keys, _data[firstKey])
325
+ }
326
+ return _data[firstKey]
327
+ }
328
+ return _data
329
+
330
+ }
331
+ /* harmony default export */ const getValueByKeys = ({
332
+ getValueByKeys: getValueByKeys_getValueByKeys
333
+ });
334
+
335
+
336
+ ;// ./lib/helpers/getValueByKeys/index.js
337
+
338
+
339
+ ;// ./lib/models/templateCompiler/templateCompilerException.js
340
+ const TEMPLATE_COMPILER_EXCEPTION_TYPE = {
341
+ argumentEmptyException: 'Argument is empty',
342
+ argumentFormatException: 'Incorrect number or format of argument',
343
+ invalidFuntionException: 'Function Name is invalid',
344
+ invalidRegExpException: 'Invalid regular expression',
345
+ isNotAFunctionException: 'Is not a function',
346
+ notExistException: 'Key does not exist',
347
+ resultEmptyException: 'Result is empty',
348
+ resultMoreThanOneException: 'More than one result'
349
+ }
350
+
351
+ class TemplateCompilerException extends Error {
352
+ constructor(message) {
353
+ super(message)
354
+ this.message = message
355
+ }
356
+ }
357
+
358
+
359
+
360
+ ;// ./lib/models/templateCompiler/constants.js
361
+ const _EMPTY = '_EMPTY'
362
+ const _FN_NAMES = [
363
+ 'concatIf',
364
+ 'divide',
365
+ 'eq',
366
+ 'exec',
367
+ 'filterAll',
368
+ 'filterOne',
369
+ 'formatDate',
370
+ 'get',
371
+ 'gt',
372
+ 'gte',
373
+ 'isEmpty',
374
+ 'isNotEmpty',
375
+ 'join',
376
+ 'lt',
377
+ 'lte',
378
+ 'map',
379
+ 'neq',
380
+ 'removeHtml',
381
+ 'toLowerCase',
382
+ 'toUpperCase',
383
+ ]
384
+ const _HIDE = '_HIDE'
385
+ const _NOT_EMPTY = '_NOT_EMPTY'
386
+ const _SELF = '_SELF'
387
+ const TAGS_EJS = ['<%=', '%>']
388
+ const TAGS_HANDLEBAR = ['{{', '}}']
389
+
390
+
391
+
392
+ ;// ./lib/models/templateCompiler/helpers/_concatIf.js
393
+
394
+
395
+
396
+
397
+ function _concatIf(data, args) {
398
+ if (typeof data !== 'string') {
399
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string :${data.join(', ')}`)
400
+ }
401
+ if (args.length !== 3) {
402
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
403
+ }
404
+ if (data === null || (typeof data === 'undefined')) {
405
+ return null
406
+ }
407
+ const [condition, success, failover] = args
408
+ const validConditions = [_EMPTY, _NOT_EMPTY]
409
+ if (validConditions.includes(condition) || success.length !== 2) {
410
+ throw new TemplateCompilerException(`concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException}: ${condition}, ${success}`)
411
+ }
412
+ if (data === '' && failover.includes(_HIDE)) {
413
+ return ''
414
+ }
415
+ if (data !== '' && (data !== null || data !== undefined) && failover.includes(_HIDE)) {
416
+ return `${success[0]}${data}${success[success.length - 1]}`
417
+ }
418
+ return failover
419
+ }
420
+
421
+
422
+
423
+ ;// ./lib/models/templateCompiler/helpers/_divide.js
424
+ function _divide(value, divisor) {
425
+ try {
426
+ if (Number.isNaN(value)) {
427
+ return value
428
+ }
429
+ return (value / divisor)
430
+ } catch (e) {
431
+ throw e
432
+ }
433
+ }
434
+
435
+
436
+
437
+ ;// ./lib/models/templateCompiler/helpers/_eq.js
438
+
439
+
440
+
441
+
442
+ function _eq(data, args) {
443
+ if (args.length !== 3) {
444
+ throw new TemplateCompilerException(`eq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
445
+ }
446
+ if (data === null || (typeof data === 'undefined')) {
447
+ return null
448
+ }
449
+ if (args.includes(_SELF)) {
450
+ args = args.map((arg) => {
451
+ return (arg === _SELF) ? data : arg
452
+ })
453
+ }
454
+ const expected = args[0]
455
+ return data === expected ? args[1] : args[2]
456
+ }
457
+
458
+
459
+
460
+ ;// ./lib/models/templateCompiler/helpers/_exec.js
461
+ function _exec(data, args) {
462
+ try {
463
+ const [methodName, ..._args] = args
464
+ return data[methodName](..._args)
465
+ } catch (e) {
466
+ throw e
467
+ }
468
+ }
469
+
470
+
471
+
472
+ ;// ./lib/models/templateCompiler/helpers/_filterAll.js
473
+
474
+
475
+
476
+ // const DELIMITER = '~~~'
477
+
478
+ function _filterAll(data, args) {
479
+ try {
480
+ if (!Array.isArray(args) || args.length === 0) {
481
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
482
+ }
483
+ if (!Array.isArray(data) || data.length === 0) {
484
+ return []
485
+ }
486
+ if (typeof data[0] === 'object') {
487
+ return _existObject(data, args)
488
+ }
489
+ if (typeof data[0] === 'string' || typeof data[0] === 'number') {
490
+ return _exist(data, args)
491
+ }
492
+ return []
493
+ } catch (e) {
494
+ throw e
495
+ }
496
+ }
497
+
498
+ function _exist(data, args) {
499
+ const _args = args.flat()
500
+ return data.filter((e) => _args.some((arg) => _performOperation(arg, e)))
501
+ }
502
+
503
+ function _existObject(data, args) {
504
+ if (args.length === 1) {
505
+ const arg = args[0]
506
+ return data.filter((e) => {
507
+ if (arg.includes('.')) {
508
+ return getValueByKeys_getValueByKeys(arg.split('.'), e)
509
+ }
510
+ return Object.prototype.hasOwnProperty.call(e, arg)
511
+ })
512
+ }
513
+
514
+ if (args.length > 2) {
515
+ let res = data
516
+ for (let i = 0; i < args.length; i += 2) {
517
+ const group = [args[i], args[i + 1]]
518
+ res = _existObject(res, group)
519
+ }
520
+ return res
521
+ }
522
+
523
+ const [key, ..._argsArr] = args
524
+ const _args = _argsArr.flat()
525
+ return data.filter((e) => {
526
+ const value = key.includes('.') ? getValueByKeys_getValueByKeys(key.split('.'), e) : e[key]
527
+ return _args.some((arg) => _performOperation(arg, value))
528
+ })
529
+ }
530
+
531
+ function _performOperation(arg, value) {
532
+ // the arg is undefined
533
+ if (arg === undefined && value === undefined) return true
534
+
535
+ // the arg is null
536
+ if (arg === null && value === null) return true
537
+
538
+ // the arg is boolean
539
+ if (typeof arg === 'boolean') {
540
+ return arg === value
541
+ }
542
+
543
+ // the arg is blank or *: Blank => Empty, * => Not Empty
544
+ if (arg === '' || arg === '*') {
545
+ // null and undefined are not included in either case
546
+ if (value === null || value === undefined) {
547
+ return false
548
+ }
549
+ if (typeof value === 'string') {
550
+ return arg === '' ? value === '' : value !== ''
551
+ }
552
+ if (Array.isArray(value)) {
553
+ return arg === '' ? value.length === 0 : value.length !== 0
554
+ }
555
+ return arg !== ''
556
+ }
557
+
558
+ // the arg is alphabetic or number
559
+ if (_isPureStringOrNumber(arg)) {
560
+ return arg === value
561
+ }
562
+
563
+ // the arg is array of [] or [*]: [] => Empty, [*] => Not Empty
564
+ if (arg.startsWith('[') && arg.endsWith(']')) {
565
+ if (arg === '[]') {
566
+ return Array.isArray(value) && value.length === 0
567
+ }
568
+ if (arg === '[*]') {
569
+ return Array.isArray(value) && value.length !== 0
570
+ }
571
+ return false
572
+ }
573
+
574
+ // the arg is 'operator + string | number'
575
+ const { operator, value: argValue } = _splitOperator(arg)
576
+ if (!operator || (argValue !== 0 && !argValue)) {
577
+ return false
578
+ }
579
+ switch (operator) {
580
+ case '>':
581
+ return value > argValue
582
+ case '<':
583
+ return value < argValue
584
+ case '!=':
585
+ return value !== argValue
586
+ case '>=':
587
+ return value >= argValue
588
+ case '<=':
589
+ return value <= argValue
590
+ default:
591
+ return false
592
+ }
593
+ }
594
+
595
+ function _isPureStringOrNumber(input) {
596
+ if (typeof input === 'string') {
597
+ if (input.startsWith('[') && input.endsWith(']')) {
598
+ return false
599
+ }
600
+ if (/!=|>=|<=|>|</.test(input)) {
601
+ return false
602
+ }
603
+ return true
604
+ }
605
+ return !Number.isNaN(input)
606
+ }
607
+
608
+ function _splitOperator(str) {
609
+ const operators = ['!=', '>=', '<=', '>', '<']
610
+
611
+ const matchedOp = operators.find((op) => str.startsWith(op))
612
+ if (!matchedOp) return { operator: null, value: null }
613
+
614
+ const remaining = str.slice(matchedOp.length)
615
+
616
+ // '>Primary' or '<Primary' is invalid
617
+ if (/^[a-zA-Z]*$/.test(remaining) && matchedOp !== '!=') {
618
+ return { operator: null, value: null }
619
+ }
620
+
621
+ // if it is a number it is converted to a number
622
+ const value = (!Number.isNaN(parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
623
+
624
+ return {
625
+ operator: matchedOp,
626
+ value
627
+ }
628
+ }
629
+
630
+
631
+
632
+ ;// ./lib/models/templateCompiler/helpers/_filterOne.js
633
+
634
+
635
+
636
+ function _filterOne(data, args) {
637
+ try {
638
+ const list = _filterAll(data, args)
639
+ if (list.length === 1) {
640
+ return list[0]
641
+ }
642
+ if (list.length === 0) {
643
+ return null
644
+ }
645
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.resultMoreThanOneException)
646
+ } catch (e) {
647
+ throw e
648
+ }
649
+ }
650
+
651
+
652
+
653
+ ;// ./lib/models/templateCompiler/helpers/_formatDate.js
654
+
655
+
656
+ function _formatDate(timestamp, format) {
657
+ if (format.length === 0) {
658
+ throw new TemplateCompilerException(`_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: format parts must be not empty array`)
659
+ }
660
+
661
+ if (timestamp === null || timestamp === undefined) {
662
+ return null
663
+ }
664
+
665
+ const date = new Date(timestamp)
666
+
667
+ const partsMap = {
668
+ yyyy: String(date.getFullYear()),
669
+ mm: String(date.getMonth() + 1).padStart(2, '0'),
670
+ dd: String(date.getDate()).padStart(2, '0')
671
+ }
672
+
673
+ // Check for invalid format tokens
674
+ const validTokens = ['yyyy', 'mm', 'dd']
675
+ const invalidTokens = format.filter((part) => part.length > 1 && !validTokens.includes(part))
676
+
677
+ if (invalidTokens.length > 0) {
678
+ throw new TemplateCompilerException(
679
+ `_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the format type is not valid: ${format.join(', ')}`
680
+ )
681
+ }
682
+
683
+ // Build the formatted string using reduce
684
+ return format.reduce((result, part) => result + (partsMap[part] || part), '')
685
+ }
686
+
687
+
688
+
689
+ ;// ./lib/models/templateCompiler/helpers/_get.js
690
+
691
+
692
+ function _get(data, key, failover = null) {
693
+ try {
694
+ if (key === null || (typeof key === 'undefined') || key === '') {
695
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
696
+ }
697
+ if (data === null) {
698
+ return null
699
+ }
700
+ if (key.includes('.')) {
701
+ const parts = key.split('.')
702
+ if (parts.length > 1) {
703
+ const first = parts.shift()
704
+ const remainingKey = parts.join('.')
705
+ if (typeof data[first] !== 'undefined') {
706
+ return _get(data[first], remainingKey, failover)
707
+ }
708
+ return _handleFailover(key, failover)
709
+ }
710
+ }
711
+ if (typeof data[key] !== 'undefined') {
712
+ return data[key]
713
+ }
714
+ return _handleFailover(key, failover)
715
+ } catch (e) {
716
+ throw e
717
+ }
718
+ }
719
+
720
+ function _handleFailover(key, failover) {
721
+ if (failover !== null) {
722
+ return failover
723
+ }
724
+ return null
725
+ // throw new TemplateCompilerException(`Key "${key}" does not exist and no failover`)
726
+ }
727
+
728
+
729
+
730
+ ;// ./lib/models/templateCompiler/helpers/_gt.js
731
+
732
+
733
+
734
+
735
+ function _gt(data, args) {
736
+ if (args.length !== 3) {
737
+ throw new TemplateCompilerException(`_gt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
738
+ }
739
+ if (data === null || (typeof data === 'undefined')) {
740
+ return null
741
+ }
742
+ if (args.includes(_SELF)) {
743
+ args = args.map((arg) => {
744
+ return (arg === _SELF) ? data : arg
745
+ })
746
+ }
747
+ const expected = args[0]
748
+ return data > expected ? args[1] : args[2]
749
+ }
750
+
751
+
752
+
753
+ ;// ./lib/models/templateCompiler/helpers/_gte.js
754
+
755
+
756
+
757
+
758
+ function _gte(data, args) {
759
+ if (args.length !== 3) {
760
+ throw new TemplateCompilerException(`_gte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
761
+ }
762
+ if (data === null || (typeof data === 'undefined')) {
763
+ return null
764
+ }
765
+ if (args.includes(_SELF)) {
766
+ args = args.map((arg) => {
767
+ return (arg === _SELF) ? data : arg
768
+ })
769
+ }
770
+ const expected = args[0]
771
+ return data >= expected ? args[1] : args[2]
772
+ }
773
+
774
+
775
+
776
+ ;// ./lib/models/templateCompiler/helpers/_isEmpty.js
777
+
778
+
779
+
780
+
781
+ function _isEmpty(data, args) {
782
+ if (args.length !== 2) {
783
+ throw new TemplateCompilerException(`_isEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
784
+ }
785
+ // if (data === null || (typeof data === 'undefined')) {
786
+ // return null
787
+ // }
788
+ if (args.includes(_SELF)) {
789
+ args = args.map((arg) => {
790
+ return (arg === _SELF) ? data : arg
791
+ })
792
+ }
793
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
794
+ return args[0]
795
+ }
796
+ return (data === '' || data === null || data === undefined || data.length === 0) ? args[0] : args[1]
797
+ }
798
+
799
+
800
+
801
+ ;// ./lib/models/templateCompiler/helpers/_isNotEmpty.js
802
+
803
+
804
+
805
+
806
+ function _isNotEmpty(data, args) {
807
+ if (args.length !== 2) {
808
+ throw new TemplateCompilerException(`_isNotEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
809
+ }
810
+ // if (data === null || (typeof data === 'undefined')) {
811
+ // return null
812
+ // }
813
+ if (args.includes(_SELF)) {
814
+ args = args.map((arg) => {
815
+ return (arg === _SELF) ? data : arg
816
+ })
817
+ }
818
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
819
+ return args[1]
820
+ }
821
+ if (Array.isArray(data) && data.length === 0) {
822
+ return args[1]
823
+ }
824
+ if (typeof data === 'string' && data === '') {
825
+ return args[1]
826
+ }
827
+ if (data === null || data === undefined) {
828
+ return args[1]
829
+ }
830
+ return args[0]
831
+ }
832
+
833
+
834
+ ;// ./lib/models/templateCompiler/helpers/_join.js
835
+ function _join(data, delimiter) {
836
+ try {
837
+ if (data.length === 0) return ''
838
+ if (data.length === 1) return _stringifyObject(data[0])
839
+ return data.map((item) => _stringifyObject(item)).join(delimiter)
840
+ } catch (e) {
841
+ throw e
842
+ }
843
+ }
844
+
845
+ function _stringifyObject(obj) {
846
+ return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1: ').replace(/"([^"]+)"/g, '$1').replace(/,/g, ', ')
847
+ }
848
+
849
+
850
+
851
+ ;// ./lib/models/templateCompiler/helpers/_lt.js
852
+
853
+
854
+
855
+
856
+ function _lt(data, args) {
857
+ if (args.length !== 3) {
858
+ throw new TemplateCompilerException(`_lt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
859
+ }
860
+ if (data === null || (typeof data === 'undefined')) {
861
+ return null
862
+ }
863
+ if (args.includes(_SELF)) {
864
+ args = args.map((arg) => {
865
+ return (arg === _SELF) ? data : arg
866
+ })
867
+ }
868
+ const expected = args[0]
869
+ return data < expected ? args[1] : args[2]
870
+ }
871
+
872
+
873
+
874
+ ;// ./lib/models/templateCompiler/helpers/_lte.js
875
+
876
+
877
+
878
+
879
+ function _lte(data, args) {
880
+ if (args.length !== 3) {
881
+ throw new TemplateCompilerException(`_lte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
882
+ }
883
+ if (data === null || (typeof data === 'undefined')) {
884
+ return null
885
+ }
886
+ if (args.includes(_SELF)) {
887
+ args = args.map((arg) => {
888
+ return (arg === _SELF) ? data : arg
889
+ })
890
+ }
891
+ const expected = args[0]
892
+ return data <= expected ? args[1] : args[2]
893
+ }
894
+
895
+
896
+
897
+ ;// ./lib/models/templateCompiler/helpers/_map.js
898
+
899
+
900
+
901
+ function _map(data, args) {
902
+ try {
903
+ if (args.length === 0) {
904
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
905
+ }
906
+ if (data === null || (typeof data === 'undefined')) {
907
+ return null
908
+ }
909
+
910
+ const result = data.reduce((acc, item) => {
911
+ if (args.length === 1 && Array.isArray(args[0])) {
912
+ args = args[0]
913
+ acc.hasFormat = true
914
+ }
915
+ const list = args.map((key) => {
916
+ if (key.includes('.')) {
917
+ const parts = key.split('.')
918
+ const first = parts[0]
919
+ parts.shift()
920
+ const remainingKey = parts.join('.')
921
+ return _get(item[first], remainingKey)
922
+ }
923
+ if (typeof item[key] !== 'undefined') {
924
+ return item[key]
925
+ }
926
+ return null
927
+ })
928
+ if (acc.hasFormat) {
929
+ acc.content.push(list)
930
+ } else {
931
+ acc.content = acc.content.concat(list)
932
+ }
933
+ return acc
934
+ }, {
935
+ content: [],
936
+ hasFormat: false
937
+ })
938
+ return result.content
939
+ } catch (e) {
940
+ throw e
941
+ }
942
+ }
943
+
944
+
945
+
946
+ ;// ./lib/models/templateCompiler/helpers/_neq.js
947
+
948
+
949
+
950
+
951
+ function _neq(data, args) {
952
+ if (args.length !== 3) {
953
+ throw new TemplateCompilerException(`_neq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
954
+ }
955
+ if (data === null || (typeof data === 'undefined')) {
956
+ return null
957
+ }
958
+ if (args.includes(_SELF)) {
959
+ args = args.map((arg) => {
960
+ return (arg === _SELF) ? data : arg
961
+ })
962
+ }
963
+ const expected = args[0]
964
+ return data !== expected ? args[1] : args[2]
965
+ }
966
+
967
+
968
+
969
+ ;// ./lib/models/templateCompiler/helpers/_removeHtml.js
970
+
971
+
972
+ function _removeHtml(html, args) {
973
+ if (html === null || html === undefined) {
974
+ return null
975
+ }
976
+ if (!Array.isArray(args)) {
977
+ throw new TemplateCompilerException(`_removeHtml: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: args parts must be array`)
978
+ }
979
+
980
+ return _htmlToPlainText(html, args[0])
981
+ }
982
+
983
+ function _htmlToPlainText(html, delimiter = '\n') {
984
+ if (typeof delimiter !== 'string') {
985
+ delimiter = '\n'; // Fallback to default if not a string
986
+ }
987
+
988
+ // First decode HTML entities and normalize whitespace
989
+ const decodedHtml = html
990
+ .replace(/&nbsp;/g, ' ')
991
+ .replace(/\s+/g, ' '); // Collapse all whitespace to single spaces
992
+
993
+ // Process HTML tags
994
+ let text = decodedHtml
995
+ // Replace block tags with temporary marker (~~~)
996
+ .replace(/<\/?(p|div|h[1-6]|ul|ol|li|pre|section|article|table|tr|td|th)(\s[^>]*)?>/gi, '~~~')
997
+ // Replace <br> tags with temporary marker (~~~)
998
+ .replace(/<br\s*\/?>/gi, '~~~')
999
+ // Remove all other tags
1000
+ .replace(/<[^>]+>/g, '')
1001
+ // Convert markers to specified delimiter
1002
+ .replace(/~~~+/g, delimiter)
1003
+ // Trim and clean whitespace
1004
+ .trim();
1005
+
1006
+ // Special handling for empty delimiter
1007
+ if (delimiter === '') {
1008
+ // Collapse all whitespace to single space
1009
+ text = text.replace(/\s+/g, ' ');
1010
+ } else {
1011
+
1012
+
1013
+ // Collapse multiple delimiters to single
1014
+ text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter);
1015
+ // Remove leading/trailing delimiters
1016
+ text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '');
1017
+ }
1018
+
1019
+ return text;
1020
+ }
1021
+
1022
+
1023
+ function escapeRegExp(string) {
1024
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1025
+ }
1026
+
1027
+
1028
+
1029
+ ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
1030
+
1031
+
1032
+ function _toLowerCase(data, args) {
1033
+ if (args !== undefined) {
1034
+ throw new TemplateCompilerException(`_toLowerCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1035
+ }
1036
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
1037
+ return null
1038
+ }
1039
+ return String(data).toLowerCase()
1040
+ }
1041
+
1042
+
1043
+
1044
+ ;// ./lib/models/templateCompiler/helpers/_toUpperCase.js
1045
+
1046
+
1047
+ function _toUpperCase(data, args) {
1048
+ if (typeof data !== 'string') {
1049
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string: ${data}`)
1050
+ }
1051
+ if (args !== undefined) {
1052
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the argument must be empty: ${args.join(', ')}`)
1053
+ }
1054
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
1055
+ return null
1056
+ }
1057
+ return String(data).toUpperCase()
1058
+ }
1059
+
1060
+
1061
+
1062
+ ;// ./lib/models/templateCompiler/helpers/index.js
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+
1073
+
1074
+
1075
+
1076
+
1077
+
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+ ;// ./lib/models/templateCompiler/templateCompiler.js
1087
+
1088
+
1089
+
1090
+
1091
+ class TemplateCompiler {
1092
+ constructor(data) {
1093
+ this.data = data
1094
+ }
1095
+ static init(options) {
1096
+ return new this(options)
1097
+ }
1098
+ static initFromArray(arr = []) {
1099
+ if (Array.isArray(arr)) {
1100
+ return arr.map((a) => this.init(a))
1101
+ }
1102
+ return []
1103
+ }
1104
+ static initOnlyValidFromArray(arr = []) {
1105
+ return this.initFromArray(arr).filter((i) => i)
1106
+ }
1107
+ static concatIf(data, args) {
1108
+ return _concatIf(data, args)
1109
+ }
1110
+ static divide(data, args) {
1111
+ return _divide(data, args)
1112
+ }
1113
+ static eq(data, args) {
1114
+ return _eq(data, args)
1115
+ }
1116
+
1117
+ static filterAll(data, args) {
1118
+ return _filterAll(data, args)
1119
+ }
1120
+
1121
+ static formatDate(data, args) {
1122
+ return _formatDate(data, args)
1123
+ }
1124
+ static get(data, key, failover = null) {
1125
+ return _get(data, key, failover)
1126
+ }
1127
+ static gt(data, args) {
1128
+ return _gt(data, args)
1129
+ }
1130
+ static gte(data, args) {
1131
+ return _gte(data, args)
1132
+ }
1133
+ static isEmpty(data, args) {
1134
+ return _isEmpty(data, args)
1135
+ }
1136
+ static isNotEmpty(data, args) {
1137
+ return _isNotEmpty(data, args)
1138
+ }
1139
+ static join(data, separator = '') {
1140
+ return _join(data, separator)
1141
+ }
1142
+ static lt(data, args) {
1143
+ return _lt(data, args)
1144
+ }
1145
+ static lte(data, args) {
1146
+ return _lte(data, args)
1147
+ }
1148
+ static map(data, args = []) {
1149
+ return _map(data, args)
1150
+ }
1151
+ static neq(data, args) {
1152
+ return _neq(data, args)
1153
+ }
1154
+ static removeHtml(data, args) {
1155
+ return _removeHtml(data, args)
1156
+ }
1157
+ static toLowerCase(data, args) {
1158
+ return _toLowerCase(data, args)
1159
+ }
1160
+ static toUpperCase(data, args) {
1161
+ return _toUpperCase(data, args)
1162
+ }
1163
+ static parseFunction(expression) {
1164
+ return _parseFunction(expression, _FN_NAMES)
1165
+ }
1166
+ static parseParams(parameters) {
1167
+ return _parseParams(parameters)
1168
+ }
1169
+
1170
+ pipe(expression = '') {
1171
+ this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
1172
+ const regex = new RegExp(`${this.delimiters[0]}\\s(.*?)\\s${this.delimiters[1]}`)
1173
+ const match = expression.match(regex)
1174
+ if (match !== null) {
1175
+ try {
1176
+ const functionList = _parseFunction(match[1], _FN_NAMES)
1177
+ return functionList.reduce((acc, fn) => {
1178
+ return _callFunction(acc, fn.name, fn.args)
1179
+ }, this.data)
1180
+ } catch (e) {
1181
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${e.message}`)
1182
+ }
1183
+ }
1184
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.invalidRegExpException}`)
1185
+ }
1186
+ }
1187
+
1188
+ function _parseFunction(expression, existFunctionNames) {
1189
+ const regExp = new RegExp(/(\w+)\(([^)]*)\)/)
1190
+ let parts
1191
+ if (expression.includes('|')) {
1192
+ parts = expression.split('|')
1193
+ } else {
1194
+ parts = [expression]
1195
+ }
1196
+ return parts.reduce((acc, part) => {
1197
+ const match = part.match(regExp)
1198
+ if (match !== null) {
1199
+ const functionName = match[1]
1200
+ const parameters = match[2]
1201
+ const paramList = _parseParams(parameters)
1202
+ if (existFunctionNames.includes(functionName)) {
1203
+ acc.push({
1204
+ name: functionName,
1205
+ args: paramList
1206
+ })
1207
+ } else {
1208
+ throw new TemplateCompilerException(`${functionName} is not a valid function`)
1209
+ }
1210
+ }
1211
+ return acc
1212
+ }, [])
1213
+ }
1214
+
1215
+ function _parseParams(parameters) {
1216
+ const _parameters = parameters.trim()
1217
+ const regExp = new RegExp(/^[^\w\d\s]+$/)
1218
+ const match = _parameters.match(regExp)
1219
+ if (match !== null) {
1220
+ return [_parameters.substring(1, _parameters.length - 1)]
1221
+ }
1222
+ if (_parameters.includes(',')) {
1223
+ // 用正则表达式匹配逗号,但忽略方括号中的逗号
1224
+ const parts = _splitIgnoringBrackets(_parameters)
1225
+ return parts.map((part) => _parseSinglePart(part))
1226
+ }
1227
+ return [_parseSinglePart(_parameters)]
1228
+ }
1229
+
1230
+ function _splitIgnoringBrackets(input) {
1231
+ const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
1232
+ const regExp = new RegExp(/(?![^\[]*\])\s*,\s*/)
1233
+ const parts = input.split(regExp)
1234
+ return parts.map((part) => {
1235
+ const _part = part.trim()
1236
+ if (_part !== '' && !!_part.match(regExp2)) {
1237
+ // 如果是数字,转换为 num 类型
1238
+ return Number.isNaN(_part) ? _part : parseInt(_part, 10)
1239
+ }
1240
+ // 否则当作字符串处理
1241
+ return _part
1242
+ })
1243
+ }
1244
+
1245
+ function _parseSinglePart(input) {
1246
+ if (typeof input === 'string') {
1247
+ if (input.startsWith('"') && input.endsWith('"')) {
1248
+ // 去掉双引号,返回
1249
+ return input.substring(1, input.length - 1)
1250
+ }
1251
+ if (input.startsWith("'") && input.endsWith("'")) {
1252
+ // 去掉双引号,返回
1253
+ return input.substring(1, input.length - 1)
1254
+ }
1255
+
1256
+ const _input = _toBasicType(input)
1257
+
1258
+ if (typeof _input !== 'string') {
1259
+ return _input
1260
+ }
1261
+
1262
+ // 如果是一个列表形式(例如 ["p", "d"] 或 [p, d])
1263
+ if (_input.startsWith('[') && _input.endsWith(']')) {
1264
+ const listContent = _input.substring(1, _input.length - 1).trim()
1265
+ if (listContent !== '') {
1266
+ return listContent.split(',').map((item) => {
1267
+ return _toBasicType(item.trim())
1268
+ })
1269
+ }
1270
+ return []
1271
+ }
1272
+ return input
1273
+ }
1274
+ return input
1275
+ }
1276
+
1277
+ function _toBasicType(input) {
1278
+ if (input.startsWith('"') && input.endsWith('"')) {
1279
+ // 去掉双引号,返回
1280
+ return input.substring(1, input.length - 1)
1281
+ }
1282
+ if (input.startsWith("'") && input.endsWith("'")) {
1283
+ // 去掉双引号,返回
1284
+ return input.substring(1, input.length - 1)
1285
+ }
1286
+ if (input === 'true') {
1287
+ return true
1288
+ }
1289
+ if (input === 'false') {
1290
+ return false
1291
+ }
1292
+ if (input === 'undefined') {
1293
+ return undefined
1294
+ }
1295
+ if (input === 'null') {
1296
+ return null
1297
+ }
1298
+ if (!Number.isNaN(input) && !Number.isNaN(Number.parseFloat(input))) {
1299
+ return Number(input)
1300
+ }
1301
+ return input
1302
+ }
1303
+
1304
+ function _callFunction(data, functionName, parameters) {
1305
+ try {
1306
+ let failover
1307
+ switch (functionName) {
1308
+ case 'concatIf':
1309
+ return _concatIf(data, parameters)
1310
+ case 'divide':
1311
+ return _divide(data, parameters)
1312
+ case 'eq':
1313
+ return _eq(data, parameters)
1314
+ case 'exec':
1315
+ return _exec(data, parameters)
1316
+ case 'filterAll':
1317
+ return _filterAll(data, parameters)
1318
+ case 'filterOne':
1319
+ return _filterOne(data, parameters)
1320
+ case 'formatDate':
1321
+ return _formatDate(data, parameters)
1322
+ case 'get':
1323
+ if (parameters.length > 2) {
1324
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
1325
+ }
1326
+ if (parameters.length === 2) {
1327
+ failover = parameters[parameters.length - 1]
1328
+ }
1329
+ return _get(data, parameters[0], failover)
1330
+ case 'gt':
1331
+ return _gt(data, parameters)
1332
+ case 'gte':
1333
+ return _gte(data, parameters)
1334
+ case 'isEmpty':
1335
+ return _isEmpty(data, parameters)
1336
+ case 'isNotEmpty':
1337
+ return _isNotEmpty(data, parameters)
1338
+ case 'join':
1339
+ return _join(data, parameters[0])
1340
+ case 'lt':
1341
+ return _lt(data, parameters)
1342
+ case 'lte':
1343
+ return _lte(data, parameters)
1344
+ case 'map':
1345
+ return _map(data, parameters)
1346
+ case 'neq':
1347
+ return _neq(data, parameters)
1348
+ case 'removeHtml':
1349
+ return _removeHtml(data, parameters)
1350
+ case 'toLowerCase':
1351
+ return _toLowerCase(data)
1352
+ case 'toUpperCase':
1353
+ return _toUpperCase(data)
1354
+ default:
1355
+ throw new Error(`${functionName} is not a valid function`)
1356
+ }
1357
+ } catch (e) {
1358
+ throw e
1359
+ }
1360
+ }
1361
+
1362
+
1363
+
1364
+ ;// ./lib/models/templateCompiler/index.js
1365
+
1366
+
1367
+
1368
+
1369
+ ;// ./lib/helpers/concatStringByArray/concatStringByArray.js
1370
+
1371
+
1372
+
1373
+
1374
+
1375
+ function concatStringByArray(arrTemplate, data) {
1376
+ return arrTemplate.reduce((acc, item) => {
1377
+ const { type, value = '', restriction, template, format, showMinutes } = item
1378
+ switch (type) {
1379
+ case('array'): {
1380
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1381
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || []
1382
+ acc += _value.reduce((_acc, item) => {
1383
+ return _acc += concatStringByArray(template, item)
1384
+ }, '')
1385
+ }
1386
+ break
1387
+ }
1388
+ case ('date'): {
1389
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1390
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1391
+ acc += (formatDate(_value, format).toString())
1392
+ }
1393
+ break
1394
+ }
1395
+ case('ellipsis'): {
1396
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1397
+ const { maxLength } = item
1398
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1399
+ if (_value.length <= maxLength) {
1400
+ acc += (_value.toString())
1401
+ } else {
1402
+ acc += `${_value.substr(0, maxLength)}...`
1403
+ }
1404
+ }
1405
+ break
1406
+ }
1407
+ case('group'): {
1408
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1409
+ return concatStringByArray(value, data)
1410
+ }
1411
+ break
1412
+ }
1413
+ case('label'): {
1414
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1415
+ acc += (value.toString())
1416
+ }
1417
+ break
1418
+ }
1419
+ case ('templateCompiler'): {
1420
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1421
+ const templateCompiler = new TemplateCompiler({ data })
1422
+ acc += templateCompiler.pipe(value)
1423
+ }
1424
+ break
1425
+ }
1426
+ case('value'): {
1427
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1428
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1429
+ acc += (_value.toString())
1430
+ }
1431
+ break
1432
+ }
1433
+ }
1434
+ return acc
1435
+ }, '')
1436
+ }
1437
+ /* harmony default export */ const concatStringByArray_concatStringByArray = ({
1438
+ concatStringByArray
1439
+ });
1440
+
1441
+
1442
+
1443
+ ;// ./lib/helpers/concatStringByArray/index.js
1444
+
1445
+
1446
+ ;// ./lib/helpers/convertString/convertString.js
1447
+
1448
+
1449
+ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByKeys) {
1450
+ if (!string) {
1451
+ return ''
1452
+ }
1453
+ let _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
1454
+ const reg = new RegExp(patternMatch, 'g')
1455
+ return string.replace(reg, (match, key) => {
1456
+ const result = _getValueByKeys({ keys: key.split('.'), obj: value })
1457
+ if (result === null || result === undefined) {
1458
+ return ''
1459
+ }
1460
+ return typeof result === 'object' ? JSON.stringify(result) : result
1461
+ })
1462
+ }
1463
+
1464
+ /* harmony default export */ const convertString_convertString = ({
1465
+ convertString
1466
+ });
1467
+
1468
+
1469
+ ;// ./lib/helpers/convertString/index.js
1470
+
1471
+
1472
+ ;// ./lib/helpers/escapeRegex/escapeRegex.js
1473
+ function escapeRegex(string) {
1474
+ return String(string).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
1475
+ }
1476
+
1477
+ ;// ./lib/helpers/escapeRegex/index.js
1478
+
1479
+
1480
+ ;// ./lib/helpers/expressHelper/customHandler.js
1481
+ function customHandler({ responseHelper, handler, ignoreError = false }) {
1482
+ return async (req, res, next) => {
1483
+ try {
1484
+ await handler({ req, res })
1485
+ await next()
1486
+ } catch (err) {
1487
+ if (ignoreError || !responseHelper) {
1488
+ await next()
1489
+ } else {
1490
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1491
+ }
1492
+ }
1493
+ }
1494
+ }
1495
+
1496
+ ;// ./lib/helpers/expressHelper/findAllResult.js
1497
+ function findAllResult({ responseHelper, service }) {
1498
+ return async (req, res, next) => {
1499
+ try {
1500
+ const { query } = req
1501
+ const result = await service.findAll({ query })
1502
+ res.locals.findAllResult = result
1503
+ await next()
1504
+ } catch (err) {
1505
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1506
+ }
1507
+ }
1508
+ }
1509
+
1510
+ ;// ./lib/helpers/expressHelper/findOneResult.js
1511
+ function findOneResult({ responseHelper, service }) {
1512
+ return async (req, res, next) => {
1513
+ try {
1514
+ const { params, query } = req
1515
+ const { id } = params
1516
+ const result = await service.findOne({
1517
+ query: {
1518
+ ...query,
1519
+ id
1520
+ }
1521
+ })
1522
+ res.locals.findOneResult = result
1523
+ await next()
1524
+ } catch (err) {
1525
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1526
+ }
1527
+ }
1528
+ }
1529
+
1530
+ ;// ./lib/helpers/expressHelper/postResult.js
1531
+ function postResult({ responseHelper, service }) {
1532
+ return async (req, res, next) => {
1533
+ try {
1534
+ const { body } = req
1535
+ let result
1536
+ if (Array.isArray(body)) {
1537
+ result = await service.saveAll({ docs: body })
1538
+ } else {
1539
+ result = await service.saveOne({ doc: body })
1540
+ }
1541
+ res.locals.postResult = result
1542
+ await next()
1543
+ } catch (err) {
1544
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1545
+ }
1546
+ }
1547
+ }
1548
+
1549
+ ;// ./lib/helpers/expressHelper/updateOneResult.js
1550
+ function updateOneResult({ responseHelper, service }) {
1551
+ return async (req, res, next) => {
1552
+ try {
1553
+ const { body, params } = req
1554
+ const { id } = params
1555
+ if (id !== body.id) {
1556
+ throw new Error('id in params and body must be same')
1557
+ }
1558
+ const { data } = await service.findOne({ query: { id } })
1559
+ const doc = data[0]
1560
+ doc.update(body)
1561
+ const result = await service.saveOne({ doc })
1562
+ res.locals.updateOneResult = result
1563
+ await next()
1564
+ } catch (err) {
1565
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1566
+ }
1567
+ }
1568
+ }
1569
+
1570
+ ;// ./lib/helpers/expressHelper/index.js
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+
1577
+
1578
+ const expressHelper = {
1579
+ customHandler: customHandler,
1580
+ findAllResult: findAllResult,
1581
+ findOneResult: findOneResult,
1582
+ postResult: postResult,
1583
+ updateOneResult: updateOneResult,
1584
+ }
1585
+
1586
+ ;// ./lib/helpers/extractEmails/extractEmails.js
1587
+ /**
1588
+ * Extracts and normalizes unique email addresses from an array containing messy entries
1589
+ * @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
1590
+ * @returns {Array} Sorted array of unique, lowercase email addresses
1591
+ */
1592
+ function extractEmails(dirtyArray) {
1593
+ const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
1594
+ const emails = new Set()
1595
+
1596
+ // Handle null/undefined input array
1597
+ if (!dirtyArray) return []
1598
+
1599
+ dirtyArray.forEach(entry => {
1600
+ // Skip null, undefined, empty, or whitespace-only entries
1601
+ if (!entry || typeof entry !== 'string' || !entry.trim()) return
1602
+
1603
+ try {
1604
+ const cleanEntry = entry
1605
+ .replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
1606
+ .replace(/[<>]/g, ' ') // Convert email delimiters to spaces
1607
+ .replace(/\s+/g, ' ') // Collapse multiple whitespace
1608
+ .trim()
1609
+
1610
+ // Extract all email matches
1611
+ const matches = cleanEntry.match(emailRegex)
1612
+ if (matches) {
1613
+ matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
1614
+ }
1615
+ } catch (e) {
1616
+ console.warn('Failed to process entry:', entry, e)
1617
+ }
1618
+ })
1619
+
1620
+ // Convert Set to array and sort alphabetically
1621
+ return Array.from(emails).sort((a, b) => a.localeCompare(b))
1622
+ }
1623
+
1624
+ ;// ./lib/helpers/extractEmails/index.js
1625
+
1626
+
1627
+ ;// ./lib/helpers/objectHelper/objectHelper.js
1628
+ const objectHelper = {
1629
+ get(obj, path) {
1630
+ const parts = path.split('.')
1631
+ return parts.reduce((acc, part) => {
1632
+ if (part.endsWith('[]')) {
1633
+ // 处理数组遍历
1634
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
1635
+ if (Array.isArray(acc[key])) {
1636
+ return acc[key] // 返回整个数组
1637
+ }
1638
+ return [] // 如果不是数组,返回空数组
1639
+ }
1640
+ if (part.includes('[') && part.includes(']')) {
1641
+ // 处理数组索引
1642
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
1643
+ if (arrayMatch) {
1644
+ const key = arrayMatch[1]
1645
+ const index = arrayMatch[2]
1646
+ return acc && acc[key] && acc[key][index]
1647
+ }
1648
+ } else if (acc && Array.isArray(acc)) {
1649
+ // 如果当前值是数组,提取每个对象的指定属性
1650
+ return acc.map((item) => item[part])
1651
+ } else {
1652
+ // 处理普通属性
1653
+ return acc && acc[part]
1654
+ }
1655
+ }, obj)
1656
+ },
1657
+ merge,
1658
+ set(obj, path, value) {
1659
+ const parts = path.split('.');
1660
+ let current = obj;
1661
+
1662
+ // 处理所有中间部分
1663
+ for (let i = 0; i < parts.length - 1; i++) {
1664
+ const part = parts[i];
1665
+ let key, index;
1666
+
1667
+ // 检查是否是数组索引格式,如key[0]
1668
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1669
+ if (arrayMatch) {
1670
+ key = arrayMatch[1];
1671
+ index = parseInt(arrayMatch[2], 10);
1672
+ // 确保当前层级的数组存在
1673
+ if (!current[key] || !Array.isArray(current[key])) {
1674
+ current[key] = [];
1675
+ }
1676
+ // 扩展数组到足够大
1677
+ while (current[key].length <= index) {
1678
+ current[key].push(undefined);
1679
+ }
1680
+ // 如果当前位置未定义或为null,初始化为对象
1681
+ if (current[key][index] == null) {
1682
+ current[key][index] = {};
1683
+ }
1684
+ current = current[key][index];
1685
+ } else {
1686
+ // 处理普通属性
1687
+ if (!current[part]) {
1688
+ current[part] = {};
1689
+ }
1690
+ current = current[part];
1691
+ }
1692
+ }
1693
+
1694
+ // 处理最后一部分
1695
+ const lastPart = parts[parts.length - 1];
1696
+ const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
1697
+ if (arrayMatch) {
1698
+ const key = arrayMatch[1];
1699
+ const index = parseInt(arrayMatch[2], 10);
1700
+ // 确保数组存在
1701
+ if (!current[key] || !Array.isArray(current[key])) {
1702
+ current[key] = [];
1703
+ }
1704
+ // 扩展数组到所需索引
1705
+ while (current[key].length <= index) {
1706
+ current[key].push(undefined);
1707
+ }
1708
+ current[key][index] = value;
1709
+ } else {
1710
+ current[lastPart] = value;
1711
+ }
1712
+ }
1713
+ }
1714
+
1715
+ function merge(target, ...sources) {
1716
+ if (!sources.length) return target
1717
+
1718
+ const source = sources.shift() // 取出第一个源对象
1719
+
1720
+ if (_isObject(target) && _isObject(source)) {
1721
+ for (const key in source) {
1722
+ if (_isObject(source[key])) {
1723
+ if (!target[key]) {
1724
+ // 如果目标对象没有该属性,创建一个空对象
1725
+ target[key] = {}
1726
+ }
1727
+ // 递归合并
1728
+ merge(target[key], source[key])
1729
+ } else {
1730
+ // 直接覆盖
1731
+ target[key] = source[key]
1732
+ }
1733
+ }
1734
+ }
1735
+
1736
+ // 继续合并剩余的源对象
1737
+ return merge(target, ...sources)
1738
+ }
1739
+
1740
+ function _isObject(obj) {
1741
+ return obj && typeof obj === 'object' && !Array.isArray(obj)
1742
+ }
1743
+
1744
+
1745
+
1746
+ ;// ./lib/helpers/objectHelper/index.js
1747
+
1748
+
1749
+
1750
+
1751
+ ;// ./lib/helpers/pReduce/pReduce.js
1752
+ async function pReduce(iterable, reducer, initialValue) {
1753
+ return new Promise((resolve, reject) => {
1754
+ const iterator = iterable[Symbol.iterator]()
1755
+ let index = 0
1756
+
1757
+ const next = async total => {
1758
+ const element = iterator.next()
1759
+
1760
+ if (element.done) {
1761
+ resolve(total)
1762
+ return
1763
+ }
1764
+
1765
+ try {
1766
+ const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
1767
+ next(reducer(resolvedTotal, resolvedValue, index++))
1768
+ } catch (error) {
1769
+ reject(error)
1770
+ }
1771
+ }
1772
+
1773
+ next(initialValue)
1774
+ })
1775
+ }
1776
+
1777
+
1778
+
1779
+ ;// ./lib/models/repo/repo.js
1780
+
1781
+
1782
+ class Repo {
1783
+ constructor(options) {
1784
+ options = options || {}
1785
+ this.model = options.model
1786
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1787
+ this._queryOptions = options._queryOptions
1788
+ this._saveOptions = options._saveOptions
1789
+ this._Class = options._constructor && options._constructor._Class
1790
+ ? options._constructor._Class
1791
+ : null
1792
+ }
1793
+ static init(options = {}) {
1794
+ return init(this, options)
1795
+ }
1796
+ static get _classname() {
1797
+ return 'Repo'
1798
+ }
1799
+ static get _superclass() {
1800
+ return 'Repo'
1801
+ }
1802
+
1803
+ get _classname() {
1804
+ return 'Repo'
1805
+ }
1806
+
1807
+ get _superclass() {
1808
+ return 'Repo'
1809
+ }
1810
+
1811
+ get isValid() {
1812
+ return this.model
1813
+ && (typeof this.model.deleteOne === 'function')
1814
+ && (typeof this.model.findAll === 'function')
1815
+ && (typeof this.model.saveOne === 'function')
1816
+ }
1817
+
1818
+ get queryOptions() {
1819
+ return {
1820
+ ...this._sharedOptions,
1821
+ ...this._queryOptions,
1822
+ }
1823
+ }
1824
+
1825
+ get saveOptions() {
1826
+ return {
1827
+ ...this._sharedOptions,
1828
+ ...this._saveOptions,
1829
+ }
1830
+ }
1831
+
1832
+ init(options) {
1833
+ if (this._Class && typeof this._Class.init === 'function') {
1834
+ return this._Class.init(options)
1835
+ }
1836
+ return options
1837
+ }
1838
+
1839
+ async deleteOne({ id }) {
1840
+ try {
1841
+ const result = await this.model.deleteOne({ _id: id })
1842
+ return {
1843
+ ...result, // { message: 'ok', total }
1844
+ isNew: false,
1845
+ data: []
1846
+ }
1847
+ } catch (err) {
1848
+ throw err
1849
+ }
1850
+ }
1851
+
1852
+ // systemLog is optional
1853
+ findAll({ query, systemLog }) {
1854
+ const log = _makeLog({
1855
+ systemLog,
1856
+ label: 'REPO_READ',
1857
+ message: `fn ${this._classname}.prototype.findAll`,
1858
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1859
+ })
1860
+ return new Promise((resolve, reject) => {
1861
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
1862
+ if (err) {
1863
+ log({ level: 'warn', output: err.toString() })
1864
+ reject(err)
1865
+ } else {
1866
+ const result = {
1867
+ isNew: false,
1868
+ data,
1869
+ total: total || data.length
1870
+ }
1871
+ log({ level: 'info', output: { ...result } })
1872
+ resolve(result)
1873
+ }
1874
+ })
1875
+ })
1876
+ }
1877
+
1878
+ findOne({ query, systemLog }) {
1879
+ const log = _makeLog({
1880
+ systemLog,
1881
+ label: 'REPO_READ',
1882
+ message: `fn ${this._classname}.prototype.findOne`,
1883
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1884
+ })
1885
+ return new Promise((resolve, reject) => {
1886
+ this.model.findAll(query, this.queryOptions, (err, data) => {
1887
+ if (err) {
1888
+ reject(err)
1889
+ } else if (data.length === 1) {
1890
+ const result = {
1891
+ isNew: false,
1892
+ data,
1893
+ total: 1
1894
+ }
1895
+ log({ level: 'info', output: { ...result } })
1896
+ resolve(result)
1897
+ } else if (data.length === 0) {
1898
+ reject(new Error('record not found'))
1899
+ } else {
1900
+ reject(new Error('more than one is found'))
1901
+ }
1902
+ })
1903
+ })
1904
+ .catch((err) => {
1905
+ log({ level: 'warn', output: err.toString() })
1906
+ throw err
1907
+ })
1908
+ }
1909
+
1910
+ saveAll({ config = {}, docs, systemLog }) {
1911
+ let isNew
1912
+ const log = _makeLog({
1913
+ systemLog,
1914
+ label: 'REPO_WRITE',
1915
+ message: `fn ${this._classname}.prototype.saveAll`,
1916
+ input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
1917
+ })
1918
+ const promise = typeof this.model.saveAll === 'function'
1919
+ ? this.model.saveAll({ config, docs })
1920
+ : Promise.all(docs.map(async (doc) => {
1921
+ if (doc) {
1922
+ const result = await this.saveOne({ config, doc })
1923
+ isNew = result.isNew
1924
+ const _data = result._data || result.data
1925
+ return _data[0]
1926
+ }
1927
+ return null
1928
+ }))
1929
+ return promise.then((savedData) => {
1930
+ if (savedData.length !== 1) isNew = null
1931
+ const result = {
1932
+ data: savedData,
1933
+ isNew,
1934
+ total: savedData.length
1935
+ }
1936
+ log({ level: 'info', output: { ...result } })
1937
+ return result
1938
+ }).catch((err) => {
1939
+ log({ level: 'warn', output: err.toString() })
1940
+ throw err
1941
+ })
1942
+ }
1943
+
1944
+ saveOne({ config = {}, doc, systemLog }) {
1945
+ const log = _makeLog({
1946
+ systemLog,
1947
+ label: 'REPO_WRITE',
1948
+ message: `fn ${this._classname}.prototype.saveOne`,
1949
+ input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
1950
+ })
1951
+ const saveOptions = {
1952
+ ...this.saveOptions,
1953
+ ...config,
1954
+ }
1955
+ return new Promise((resolve, reject) => {
1956
+ this.model.saveOne(doc, saveOptions, (err, result) => {
1957
+ if (err) {
1958
+ log({ level: 'warn', output: err.toString() })
1959
+ reject(err)
1960
+ } else {
1961
+ log({ level: 'info', output: { ...result } })
1962
+ resolve(result)
1963
+ }
1964
+ })
1965
+ })
1966
+ }
1967
+ }
1968
+
1969
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
1970
+ return ({ level, messgae: massage2, output } = {}) => {
1971
+ if (systemLog && systemLog.systemLogHelper) {
1972
+ systemLog.systemLogHelper.log({
1973
+ batchId: systemLog.batchId,
1974
+ label,
1975
+ level,
1976
+ message: massage2 || message1,
1977
+ data: {
1978
+ payload: {
1979
+ input,
1980
+ output
1981
+ }
1982
+ }
1983
+ })
1984
+ }
1985
+ }
1986
+ }
1987
+
1988
+
1989
+
1990
+ ;// ./lib/models/repo/index.js
1991
+
1992
+
1993
+
1994
+
1995
+ ;// ./lib/models/apiResponse/apiResponse.js
1996
+ class ApiResponse {
1997
+ constructor(options = {}) {
1998
+ options = options || {}
1999
+ this._data = options.data || options._data || []
2000
+ this.err = options.err
2001
+ this.isNew = options.isNew || false
2002
+ this.message = options.message
2003
+ this.total = options.total || 0
2004
+ this._instanceBuilder = options._instanceBuilder
2005
+ }
2006
+
2007
+ static init(options = {}) {
2008
+ if (options instanceof this) {
2009
+ return options
2010
+ }
2011
+ const instance = new this(options)
2012
+ return instance
2013
+ }
2014
+ static get _classname() {
2015
+ return 'ApiResponse'
2016
+ }
2017
+ static get _superclass() {
2018
+ return 'ApiResponse'
2019
+ }
2020
+
2021
+ // getters
2022
+ get data() {
2023
+ if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
2024
+ return this._data.map(this._instanceBuilder)
2025
+ }
2026
+ return this._data
2027
+ }
2028
+ }
2029
+
2030
+
2031
+
2032
+ ;// ./lib/models/apiResponse/makeApiResponse.js
2033
+
2034
+
2035
+ function makeApiResponse({ repo, result }) {
2036
+ return ApiResponse.init({
2037
+ ...result,
2038
+ _instanceBuilder: (i) => {
2039
+ return repo.init(i)
2040
+ }
2041
+ })
2042
+ }
2043
+
2044
+
2045
+
2046
+ ;// ./lib/models/service/service.js
2047
+
2048
+
2049
+
2050
+ class Service {
2051
+ constructor({ repo }) {
2052
+ this.repo = repo
2053
+ }
2054
+
2055
+ static get _classname() {
2056
+ return 'Service'
2057
+ }
2058
+ static get _superclass() {
2059
+ return 'Service'
2060
+ }
2061
+
2062
+ async deleteOne({ id }) {
2063
+ const result = await this.repo.deleteOne({ id })
2064
+ return makeApiResponse({
2065
+ repo: this.repo,
2066
+ result
2067
+ })
2068
+ // return this.repo.delete({ id })
2069
+ // .catch(() => {
2070
+ // throw new Error(`Not found for query: ${id}`)
2071
+ // })
2072
+ }
2073
+
2074
+ async findAll({ query = {}, systemLog } = {}) {
2075
+ const result = await this.repo.findAll({ query, systemLog })
2076
+ return makeApiResponse({
2077
+ repo: this.repo,
2078
+ result
2079
+ })
2080
+ }
2081
+
2082
+ async findOne({ query = {}, systemLog } = {}) {
2083
+ const result = await this.repo.findOne({ query, systemLog })
2084
+ return makeApiResponse({
2085
+ repo: this.repo,
2086
+ result
2087
+ })
2088
+ }
2089
+
2090
+ init(options) {
2091
+ return this.repo.init(options)
2092
+ }
2093
+ initFromArray(arr = []) {
2094
+ if (Array.isArray(arr)) {
2095
+ return arr.map((a) => this.init(a))
2096
+ }
2097
+ return []
2098
+ }
2099
+ initOnlyValidFromArray(arr = []) {
2100
+ return this.initFromArray(arr).filter((i) => i)
2101
+ }
2102
+
2103
+ async saveAll({ config = {}, docs = [], systemLog } = {}) {
2104
+ const copies = docs.map((doc) => {
2105
+ return config.skipInit ? doc : this.init(doc)
2106
+ })
2107
+ const result = await this.repo.saveAll({ config, docs: copies, systemLog })
2108
+ return makeApiResponse({
2109
+ repo: this.repo,
2110
+ result
2111
+ })
2112
+ }
2113
+
2114
+ // set skipInit to true if we want to use POST for query
2115
+ async saveOne({ config = {}, doc = {}, systemLog } = {}) {
2116
+ const copy = config.skipInit ? doc : this.init(doc)
2117
+ if (copy) {
2118
+ const result = await this.repo.saveOne({ config, doc: copy, systemLog })
2119
+ return makeApiResponse({
2120
+ repo: this.repo,
2121
+ result
2122
+ })
2123
+ }
2124
+ return {
2125
+ isNew: null,
2126
+ data: [],
2127
+ err: new Error('doc is not a valid instance')
2128
+ }
2129
+ }
2130
+ }
2131
+
2132
+ function makeService({ repo }) {
2133
+ if (repo === undefined) {
2134
+ throw new Error('repo is required.')
2135
+ }
2136
+ if (repo._superclass !== Repo._superclass) {
2137
+ throw new Error('repo is not an instance of Repo.')
2138
+ }
2139
+ return new Service({ repo })
2140
+ }
2141
+
2142
+
2143
+
2144
+ ;// ./lib/models/service/index.js
2145
+
2146
+
2147
+
2148
+
2149
+ ;// ./lib/helpers/generalPost/generalPost.js
2150
+
2151
+
2152
+
2153
+
2154
+
2155
+ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
2156
+ const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
2157
+ const _resourceInfo = resourceInfo || body.resourceInfo
2158
+ _attachShared(data, globalShared, shared)
2159
+ const obj = await pReduce(resources, async (acc, resource) => {
2160
+ const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
2161
+ _createRelationship(data, relationship[resource], acc)
2162
+ const _data = data[resource]
2163
+ const result = await service.saveAll({ docs: [].concat(_data) })
2164
+ acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
2165
+ return acc
2166
+ }, {})
2167
+ return obj
2168
+ }
2169
+
2170
+ function _attachShared(data, globalShared = {}, shared = {}) {
2171
+ Object.keys(shared).forEach((key) => {
2172
+ const _data = data[key]
2173
+ if (Array.isArray(_data)) {
2174
+ data[key] = _data.map((_dataItem) => {
2175
+ return objectHelper.merge({}, _dataItem, globalShared, shared[key] || {})
2176
+ })
2177
+ } else {
2178
+ data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
2179
+ }
2180
+ })
2181
+ }
2182
+
2183
+ function _createRelationship(data, relationship = {}, object) {
2184
+ Object.keys(relationship).forEach((key) => {
2185
+ const path = relationship[key]
2186
+ const val = objectHelper.get(object, path)
2187
+ objectHelper.set(data, key, val)
2188
+ })
2189
+ }
2190
+
2191
+ function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
2192
+ const { collectionName, fields } = resourceInfo[resource]
2193
+ const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
2194
+ const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
2195
+ return makeService({
2196
+ repo: new Repo({ model })
2197
+ })
2198
+ }
2199
+
2200
+
2201
+
2202
+ ;// ./lib/helpers/generalPost/index.js
2203
+
2204
+
2205
+
2206
+
2207
+ ;// ./lib/helpers/groupArrayByKey/groupArrayByKey.js
2208
+ function groupArrayByKey(arr, key) {
2209
+ if (!key || typeof key !== 'string') {
2210
+ return {}
2211
+ }
2212
+ return arr.reduce((acc, curr) => {
2213
+ if (!acc[curr[key]]) {
2214
+ acc[curr[key]] = 0
2215
+ }
2216
+ acc[curr[key]]++
2217
+ return acc
2218
+ }, {})
2219
+ }
2220
+
2221
+ ;// ./lib/helpers/groupArrayByKey/index.js
2222
+
2223
+
2224
+ ;// ./lib/helpers/init/init.js
2225
+ function init(_class, options) {
2226
+ if (options instanceof _class) {
2227
+ return options
2228
+ }
2229
+ try {
2230
+ const instance = new _class(options)
2231
+ return instance.isValid !== false ? instance : null
2232
+ } catch (e) {
2233
+ console.log(`init failed for class: ${_class._classname || 'no _classname'}`, e)
2234
+ return null
2235
+ }
2236
+ }
2237
+
2238
+ ;// ./lib/helpers/init/index.js
2239
+
2240
+
2241
+ ;// ./lib/helpers/initFromArray/initFromArray.js
2242
+
2243
+
2244
+ function initFromArray(_class, arr) {
2245
+ if (Array.isArray(arr)) {
2246
+ return arr.map((a) => init(_class, a))
2247
+ }
2248
+ return []
2249
+ }
2250
+
2251
+ ;// ./lib/helpers/initFromArray/index.js
2252
+
2253
+
2254
+ ;// ./lib/helpers/initOnlyValidFromArray/initOnlyValidFromArray.js
2255
+
2256
+
2257
+ function initOnlyValidFromArray(_class, arr) {
2258
+ return initFromArray(_class, arr).filter((i) => i)
2259
+ }
2260
+
2261
+ ;// ./lib/helpers/initOnlyValidFromArray/index.js
2262
+
2263
+
2264
+ ;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
2265
+ function mergeArraysByKey(arr1, arr2) {
2266
+ // Handle undefined/null inputs by defaulting to empty arrays
2267
+ const safeArr1 = Array.isArray(arr1) ? arr1 : []
2268
+ const safeArr2 = Array.isArray(arr2) ? arr2 : []
2269
+
2270
+ const mergedMap = new Map()
2271
+
2272
+ // Helper function to merge values based on their type
2273
+ const mergeValues = (existingValue, newValue) => {
2274
+ if (existingValue === undefined) return newValue
2275
+
2276
+ // Handle arrays by concatenating
2277
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
2278
+ return [...new Set([...existingValue, ...newValue])]
2279
+ }
2280
+
2281
+ // Handle objects by merging
2282
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
2283
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
2284
+ return { ...existingValue, ...newValue }
2285
+ }
2286
+
2287
+ // // Handle numbers by adding
2288
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
2289
+ // return existingValue
2290
+ // }
2291
+
2292
+ // // Handle strings by concatenating
2293
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
2294
+ // return existingValue
2295
+ // }
2296
+
2297
+ // Default: use the new value
2298
+ return newValue
2299
+ }
2300
+
2301
+ // Process first array
2302
+ safeArr1.forEach(item => {
2303
+ mergedMap.set(item.key, item.value)
2304
+ })
2305
+
2306
+ // Process second array and merge values
2307
+ safeArr2.forEach(item => {
2308
+ const existingValue = mergedMap.get(item.key)
2309
+ mergedMap.set(item.key, mergeValues(existingValue, item.value))
2310
+ })
2311
+
2312
+ // Convert back to array format
2313
+ return Array.from(mergedMap.entries()).map(([key, value]) => ({
2314
+ key,
2315
+ value
2316
+ }))
2317
+ }
2318
+
2319
+ ;// ./lib/helpers/mergeArraysByKey/index.js
2320
+
2321
+
2322
+ ;// ./lib/helpers/padZeros/padZeros.js
2323
+ function padZeros(num, minLength = 6) {
2324
+ num = num.toString()
2325
+ if (num.length < minLength) {
2326
+ return padZeros('0' + num, minLength)
2327
+ }
2328
+ return num
2329
+ }
2330
+
2331
+
2332
+
2333
+ ;// ./lib/helpers/padZeros/index.js
2334
+
2335
+
2336
+
2337
+
2338
+ ;// ./lib/helpers/pReduce/index.js
2339
+
2340
+
2341
+
2342
+
2343
+ ;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
2344
+ function replacePlaceholders({ content, mapping }) {
2345
+ let isObjectMode = false
2346
+
2347
+ if (typeof content === 'object' && content !== null) {
2348
+ content = JSON.stringify(content)
2349
+ isObjectMode = true
2350
+ }
2351
+
2352
+ // [[ eventRegistration.eventRegistrationCode | 0 ]]
2353
+ const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
2354
+
2355
+ const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
2356
+
2357
+ // Split the path into parts
2358
+ const keys = path.trim().split('.')
2359
+
2360
+ // Traverse the nested object structure
2361
+ let value = mapping
2362
+ for (const key of keys) {
2363
+ // Handle empty keys (in case of double dots or leading/trailing dots)
2364
+ if (!key) continue
2365
+
2366
+ value = value?.[key]
2367
+ if (value === undefined) {
2368
+ break
2369
+ }
2370
+ }
2371
+
2372
+ // Apply default if missing
2373
+ if (value === undefined) value = defaultValue?.trim();
2374
+ if (value === undefined) return isObjectMode ? undefined : match;
2375
+
2376
+ value = value !== undefined
2377
+ ? leadingBrackets + value + trailingBrackets
2378
+ : match
2379
+
2380
+ // Return replacement or original if not found
2381
+ return value
2382
+ })
2383
+
2384
+ if (isObjectMode) {
2385
+ return JSON.parse(result)
2386
+ }
2387
+ return result
2388
+ }
2389
+
2390
+ ;// ./lib/helpers/replacePlaceholders/index.js
2391
+
2392
+
2393
+ ;// ./lib/helpers/sanitizeText/sanitizeText.js
2394
+ /**
2395
+ * Sanitizes input by removing hidden/control characters with customizable whitespace handling.
2396
+ * @param {string} input - The string to sanitize.
2397
+ * @param {Object} [options] - Configuration options.
2398
+ * @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
2399
+ * @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
2400
+ * @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
2401
+ * @returns {string} The sanitized string.
2402
+ */
2403
+ function sanitizeText(input, options = {}) {
2404
+ const {
2405
+ normalizeWhitespace = true,
2406
+ removeNewlines = false,
2407
+ trim = true,
2408
+ preserveBasicWhitespace = true, // new option to keep tabs, newlines if removeNewlines=false
2409
+ } = options
2410
+
2411
+ if (typeof input !== 'string') {
2412
+ return input
2413
+ }
2414
+
2415
+ let result = input
2416
+
2417
+ // Phase 1: Remove all control characters except basic whitespace if requested
2418
+ if (preserveBasicWhitespace && !removeNewlines) {
2419
+ // Keep tab (\t), newline (\n), carriage return (\r)
2420
+ result = result.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
2421
+ } else {
2422
+ // Remove all control characters including basic whitespace
2423
+ result = result.replace(/[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
2424
+ }
2425
+
2426
+ // Phase 2: Handle whitespace transformations
2427
+ if (removeNewlines) {
2428
+ result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
2429
+ }
2430
+
2431
+ if (normalizeWhitespace) {
2432
+ result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
2433
+ }
2434
+
2435
+ // Phase 3: Final trimming
2436
+ if (trim) {
2437
+ result = result.trim()
2438
+ }
2439
+
2440
+ return result
2441
+ }
2442
+
2443
+ ;// ./lib/helpers/sanitizeText/index.js
2444
+
2445
+
2446
+ ;// ./lib/helpers/shuffleArray/shuffleArray.js
2447
+ function shuffleArray(array) {
2448
+ const arr = [...array];
2449
+ for (let i = arr.length - 1; i >= 0; i--) { // Changed `i > 0` to `i >= 0`
2450
+ const j = Math.floor(Math.random() * (i + 1));
2451
+ [arr[i], arr[j]] = [arr[j], arr[i]];
2452
+ }
2453
+ return arr;
2454
+ }
2455
+
2456
+ ;// ./lib/helpers/shuffleArray/index.js
2457
+
2458
+
2459
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
2460
+ function stringFormatter(str, delimiter = '_') {
2461
+ if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
2462
+ return null
2463
+ }
2464
+ return str.toString()
2465
+ .trim()
2466
+ .toUpperCase()
2467
+ .replace('-', delimiter)
2468
+ .replace(' ', delimiter)
2469
+ }
2470
+
2471
+
2472
+
2473
+ ;// ./lib/helpers/stringFormatter/index.js
2474
+
2475
+
2476
+
2477
+
2478
+ ;// ./lib/helpers/stringHelper/stringHelper.js
2479
+ function baseXEncode(num, base = 34) {
2480
+ const charset = getBaseCharset(base)
2481
+ return encode(num, charset)
2482
+ }
2483
+
2484
+ function encode(int, charset) {
2485
+ const { byCode } = charset
2486
+ if (int === 0) {
2487
+ return byCode[0]
2488
+ }
2489
+
2490
+ let res = ''
2491
+ const max = charset.length
2492
+ while (int > 0) {
2493
+ res = byCode[int % max] + res
2494
+ int = Math.floor(int / max)
2495
+ }
2496
+ return res
2497
+ }
2498
+
2499
+ function getBaseCharset(base) {
2500
+ let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
2501
+ if (base === 58) {
2502
+ charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
2503
+ }
2504
+ return indexCharset(charset)
2505
+ }
2506
+
2507
+ function indexCharset(str) {
2508
+ const byCode = {}
2509
+ const byChar = {}
2510
+ const { length } = str
2511
+ let char
2512
+ for (let i = 0; i < length; i++) {
2513
+ char = str[i]
2514
+ byCode[i] = char
2515
+ byChar[char] = i;
2516
+ }
2517
+ return { byCode, byChar, length }
2518
+ }
2519
+
2520
+ function isSame(str1, str2) {
2521
+ if (typeof str1 !== 'string' || typeof str2 !== 'string') {
2522
+ return false
2523
+ }
2524
+ return str1.trim().toUpperCase() === str2.trim().toUpperCase()
2525
+ }
2526
+
2527
+ function randomString({ len = 16, pattern = 'a1' } = {}) {
2528
+ const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
2529
+ const a = 'abcdefghijklmnopqrstuvwxyz'
2530
+ const num = '1234567890'
2531
+ const mark = '~!@#$%^&*_+-='
2532
+ let str = ''
2533
+ if (pattern.includes('A')) {
2534
+ str += A
2535
+ }
2536
+ if (pattern.includes('a')) {
2537
+ str += a
2538
+ }
2539
+ if (pattern.includes('1')) {
2540
+ str += num
2541
+ }
2542
+ if (pattern.includes('#')) {
2543
+ str += mark
2544
+ }
2545
+ const chars = [...str]
2546
+ return [...Array(len)].map(i => {
2547
+ return chars[(Math.random() * chars.length) | 0]
2548
+ }).join``
2549
+ }
2550
+
2551
+ function reverse(str) {
2552
+ const _str = (typeof str !== 'string') ? str.toString() : str
2553
+ const splitString = _str.split('')
2554
+ const reverseArray = splitString.reverse()
2555
+ return reverseArray.join('')
2556
+ }
2557
+
2558
+ function setCode(base = 34) {
2559
+ const now = (new Date()).valueOf()
2560
+ const random = randomString({
2561
+ len: 8,
2562
+ pattern: '1'
2563
+ })
2564
+ const str = reverse(`${now}${random}`)
2565
+ // const str = `${now}${random}`
2566
+ return baseXEncode(str, base)
2567
+ }
2568
+
2569
+ function toCamelCase(str) {
2570
+ if (!str) return ''
2571
+ return str
2572
+ .trim()
2573
+ .split(/\s+/)
2574
+ .map((word, index) => {
2575
+ if (!word) return ''
2576
+ if (index === 0) {
2577
+ return word.toLowerCase()
2578
+ }
2579
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
2580
+ })
2581
+ .join('')
2582
+ }
2583
+
2584
+ function toLowerCase(str) {
2585
+ if (!str) return ''
2586
+ return str
2587
+ .trim()
2588
+ .toLowerCase()
2589
+ }
2590
+
2591
+ const stringHelper = {
2592
+ isSame,
2593
+ setCode,
2594
+ toCamelCase,
2595
+ toLowerCase,
2596
+ }
2597
+
2598
+
2599
+
2600
+ ;// ./lib/helpers/stringHelper/index.js
2601
+
2602
+
2603
+
2604
+
2605
+ ;// ./lib/helpers/trackingPlugin/trackingPlugin.js
2606
+ function trackingPlugin(schema, options) {
2607
+ // Add meta fields
2608
+ schema.add({
2609
+ meta: {
2610
+ active: { type: Boolean, default: true },
2611
+ created: { type: Number },
2612
+ creator: { type: String },
2613
+ deleted: { type: Boolean, default: false },
2614
+ modified: { type: Number },
2615
+ owner: { type: String },
2616
+ }
2617
+ })
2618
+
2619
+ // Auto-update hook
2620
+ schema.pre('save', function(next) {
2621
+ this.meta.modified = Date.now()
2622
+ next()
2623
+ })
2624
+
2625
+ // Add core indexes
2626
+ schema.index({
2627
+ 'meta.active': 1,
2628
+ 'meta.deleted': 1
2629
+ }, {
2630
+ name: 'tracking_status_index',
2631
+ background: true,
2632
+ partialFilterExpression: {
2633
+ 'meta.active': true,
2634
+ 'meta.deleted': false
2635
+ }
2636
+ })
2637
+
2638
+ // Optional: Add helper methods
2639
+ // schema.methods.touch = function(userId) {
2640
+ // this.meta.updatedAt = new Date()
2641
+ // this.meta.updatedBy = userId
2642
+ // }
2643
+ }
2644
+
2645
+ ;// ./lib/helpers/tenantPlugin/tenantPlugin.js
2646
+
2647
+
2648
+ function tenantPlugin(schema, options) {
2649
+ // Apply tracking plugin first if not already present
2650
+ if (!schema.path('meta')) {
2651
+ trackingPlugin(schema, options)
2652
+ }
2653
+
2654
+ // Add tenant-specific fields
2655
+ schema.add({
2656
+ metadata: [{ type: Object }], // Instead of Schema.Types.Mixed
2657
+ remarks: [{ type: Object }],
2658
+ tenantCode: { type: String, required: true }
2659
+ })
2660
+
2661
+ // Add core indexes
2662
+ schema.index({
2663
+ 'tenantCode': 1
2664
+ }, {
2665
+ name: 'tenant_core_index',
2666
+ background: true
2667
+ })
2668
+
2669
+ // 1. ENHANCE EXISTING TRACKING INDEXES
2670
+ const existingIndexes = schema.indexes()
2671
+
2672
+ // Check if tracking_status_index exists
2673
+ const hasTenantStatusIndex = existingIndexes.some(idx =>
2674
+ idx.name === 'tenant_status_index' // Check by name for reliability
2675
+ )
2676
+
2677
+ if (!hasTenantStatusIndex) {
2678
+ schema.index({
2679
+ 'tenantCode': 1, // Unique field first
2680
+ _type: 1, // Low-cardinality field last
2681
+ }, {
2682
+ name: 'tenant_status_index',
2683
+ background: true,
2684
+ partialFilterExpression: {
2685
+ '_type': 'Tenant',
2686
+ 'meta.active': true,
2687
+ 'meta.deleted': false
2688
+ }
2689
+ })
2690
+ }
2691
+ }
2692
+
2693
+ ;// ./lib/helpers/tenantPlugin/index.js
2694
+
2695
+
2696
+ ;// ./lib/helpers/trackingPlugin/index.js
2697
+
2698
+
2699
+ ;// ./lib/helpers/index.js
2700
+
2701
+
2702
+
2703
+
2704
+
2705
+
2706
+
2707
+
2708
+
2709
+
2710
+
2711
+
2712
+
2713
+
2714
+
2715
+
2716
+
2717
+
2718
+
2719
+
2720
+
2721
+
2722
+
2723
+
2724
+
2725
+
2726
+
2727
+
2728
+ ;// ./lib/models/apiResponse/index.js
2729
+
2730
+
2731
+
2732
+
2733
+
2734
+ ;// ./lib/models/awsStsS3Client/awsStsS3Client.js
2735
+ class AwsStsS3Client {
2736
+ constructor(options) {
2737
+ options = options || {}
2738
+
2739
+ this.expiration = options.expiration || null
2740
+ this.s3Client = options.s3Client || null
2741
+ this.getIdToken = options.getIdToken
2742
+ this.region = options.region || 'ap-east-1'
2743
+ this.roleArn = options.roleArn
2744
+ this.roleSessionName = options.roleSessionName || 'web-identity-session'
2745
+ this.durationSession = options.durationSession || 3600
2746
+ this.awsClientSts = options.awsClientSts
2747
+ this.awsClientS3 = options.awsClientS3
2748
+ }
2749
+
2750
+ static dummyData() {
2751
+ return {
2752
+ getIdToken: () => 'mock-web-identity-token',
2753
+ roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
2754
+ awsClientSts: {
2755
+ STSClient: class {},
2756
+ AssumeRoleWithWebIdentityCommand: class {}
2757
+ },
2758
+ awsClientS3: {
2759
+ S3Client: class {},
2760
+ PutObjectCommand: class {},
2761
+ GetObjectCommand: class {},
2762
+ DeleteObjectCommand: class {}
2763
+ }
2764
+ }
2765
+ }
2766
+
2767
+ static init(options = {}) {
2768
+ if (options instanceof this) {
2769
+ return options
2770
+ }
2771
+ try {
2772
+ const instance = new this(options)
2773
+ if (!instance.isValid) {
2774
+ return null
2775
+ }
2776
+ return instance
2777
+ } catch (error) {
2778
+ return null
2779
+ }
2780
+ }
2781
+
2782
+ get isExpired() {
2783
+ if (!this.expiration) return true;
2784
+ const now = new Date();
2785
+ const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
2786
+ return now >= new Date(this.expiration.getTime() - bufferMs);
2787
+ }
2788
+
2789
+ get isValid() {
2790
+ if (!this.getIdToken) {
2791
+ throw new Error('Missing required configuration: getIdToken function')
2792
+ }
2793
+ if (!this.roleArn) {
2794
+ throw new Error('Missing required configuration: roleArn')
2795
+ }
2796
+ if (!this.awsClientSts) {
2797
+ throw new Error('Missing required AWS awsClientSts client configuration')
2798
+ }
2799
+ if (!this.awsClientSts.STSClient) {
2800
+ throw new Error('Missing STSClient in AWS awsClientSts client configuration')
2801
+ }
2802
+ if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
2803
+ throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
2804
+ }
2805
+ if (!this.awsClientS3) {
2806
+ throw new Error('Missing required AWS awsClientS3 client configuration')
2807
+ }
2808
+
2809
+ const requiredS3Components = [
2810
+ 'S3Client',
2811
+ 'PutObjectCommand',
2812
+ 'GetObjectCommand',
2813
+ 'DeleteObjectCommand'
2814
+ ]
2815
+
2816
+ for (const component of requiredS3Components) {
2817
+ if (!this.awsClientS3[component]) {
2818
+ throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
2819
+ }
2820
+ }
2821
+
2822
+ return true
2823
+ }
2824
+
2825
+ async refreshCredentials() {
2826
+ try {
2827
+ const webIdentityToken = await this.getIdToken()
2828
+ if (!webIdentityToken) {
2829
+ throw new Error('getIdToken function returned empty or invalid token')
2830
+ }
2831
+
2832
+ const stsClient = new this.awsClientSts.STSClient({ region: this.region })
2833
+
2834
+ const stsResponse = await stsClient.send(
2835
+ new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
2836
+ RoleArn: this.roleArn,
2837
+ RoleSessionName: this.roleSessionName,
2838
+ WebIdentityToken: await this.getIdToken(),
2839
+ DurationSeconds: this.durationSession,
2840
+ })
2841
+ )
2842
+
2843
+ const credentials = stsResponse.Credentials
2844
+ if (!credentials) {
2845
+ throw new Error('No credentials returned from awsClientSts')
2846
+ }
2847
+
2848
+ this.expiration = credentials.Expiration
2849
+
2850
+ this.s3Client = new this.awsClientS3.S3Client({
2851
+ region: this.region,
2852
+ credentials: {
2853
+ accessKeyId: credentials.AccessKeyId,
2854
+ secretAccessKey: credentials.SecretAccessKey,
2855
+ sessionToken: credentials.SessionToken,
2856
+ }
2857
+ })
2858
+
2859
+ return this
2860
+ } catch (error) {
2861
+ throw new Error(`Failed to refresh credentials: ${error.message}`)
2862
+ }
2863
+ }
2864
+
2865
+ async getS3Client() {
2866
+ if (this.isExpired || !this.s3Client) {
2867
+ await this.refreshCredentials()
2868
+ }
2869
+ return this.s3Client
2870
+ }
2871
+
2872
+ async putObject(params) {
2873
+ try {
2874
+ const client = await this.getS3Client()
2875
+ const command = new this.awsClientS3.PutObjectCommand(params)
2876
+ await client.send(command)
2877
+ const fileArr = params.Key.split('/')
2878
+ return {
2879
+ url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
2880
+ filename: fileArr.pop(),
2881
+ folder: params.Bucket,
2882
+ subFolders: fileArr
2883
+ }
2884
+ } catch (error) {
2885
+ throw new Error(`Failed to put object: ${error.message}`)
2886
+ }
2887
+ }
2888
+
2889
+ async getObject(params) {
2890
+ try {
2891
+ const client = await this.getS3Client()
2892
+ const command = new this.awsClientS3.GetObjectCommand(params)
2893
+ const response = await client.send(command)
2894
+ return {
2895
+ body: response.Body,
2896
+ contentType: response.ContentType,
2897
+ lastModified: response.LastModified,
2898
+ contentLength: response.ContentLength,
2899
+ }
2900
+ } catch (error) {
2901
+ throw new Error(`Failed to get object: ${error.message}`)
2902
+ }
2903
+ }
2904
+
2905
+ async deleteObject(params) {
2906
+ try {
2907
+ const client = await this.getS3Client()
2908
+ const command = new this.awsClientS3.DeleteObjectCommand(params)
2909
+ await client.send(command)
2910
+ return true
2911
+ } catch (error) {
2912
+ throw new Error(`Failed to delete object: ${error.message}`)
2913
+ }
2914
+ }
2915
+ }
2916
+
2917
+
2918
+
2919
+ ;// ./lib/models/awsStsS3Client/index.js
2920
+
2921
+
2922
+
2923
+
2924
+ ;// ./lib/models/keyValueObject/keyValueObject.js
2925
+ class KeyValueObject {
2926
+ constructor(options = {}) {
2927
+ options = options || {}
2928
+ this.key = options.key || null
2929
+ this.value = (typeof options.value !== 'undefined') ? options.value : ''
2930
+ }
2931
+
2932
+ // Class methods
2933
+ static init(options = {}) {
2934
+ if (options instanceof this) {
2935
+ return options
2936
+ }
2937
+ const instance = new this(options)
2938
+ return instance.isValid ? instance : null
2939
+ }
2940
+ static initFromArray(arr = []) {
2941
+ if (Array.isArray(arr)) {
2942
+ return arr.map((a) => this.init(a))
2943
+ }
2944
+ return []
2945
+ }
2946
+ static initOnlyValidFromArray(arr = []) {
2947
+ return this.initFromArray(arr).filter((i) => i)
2948
+ }
2949
+ static get _classname() {
2950
+ return 'KeyValueObject'
2951
+ }
2952
+ static get _superclass() {
2953
+ return 'KeyValueObject'
2954
+ }
2955
+
2956
+ static addItem(arr, key, value) {
2957
+ arr.push(this.init({ key, value }))
2958
+ }
2959
+ static addRecord(arr = [], key, value) {
2960
+ if (!this.hasKeyValue(arr, key, value)) {
2961
+ arr.push(this.init({ key, value }))
2962
+ }
2963
+ return arr
2964
+ }
2965
+ static appendRecord(arr = [], key, value) {
2966
+ return arr.map((item) => {
2967
+ if (this.sameKey(item, key)) {
2968
+ item.value = [...item.value, ...value]
2969
+ }
2970
+ return item
2971
+ })
2972
+ }
2973
+ static appendValueArray(arr = [], key, value) {
2974
+ return arr.map((item) => {
2975
+ if (this.sameKey(item, key)) {
2976
+ item.value = [...item.value, ...value]
2977
+ }
2978
+ return item
2979
+ })
2980
+ }
2981
+ static foundByKey(arr = [], key) {
2982
+ const found = arr.find((m) => {
2983
+ return this.sameKey(m, key)
2984
+ })
2985
+ return found || null
2986
+ }
2987
+ static foundValueByKey(arr = [], key) {
2988
+ const found = this.foundByKey(arr, key)
2989
+ return found ? found.value : null
2990
+ }
2991
+ static fromObject(options = {}) {
2992
+ return Object.keys(options).reduce((acc, key) => {
2993
+ acc.push(this.init({ key, value: options[key] }))
2994
+ return acc
2995
+ }, [])
2996
+ }
2997
+ static getValueByKey(arr = [], key) {
2998
+ return this.foundValueByKey(arr, key)
2999
+ }
3000
+ static getValueByKeyFromArray(arr = [], key) {
3001
+ if (arr.length === 0) {
3002
+ return null
3003
+ }
3004
+ const firstArr = arr.shift()
3005
+ const found = firstArr.find((i) => {
3006
+ return this.sameKey(i, key)
3007
+ })
3008
+ if (found && found.value) {
3009
+ return found.value
3010
+ }
3011
+ return this.getValueByKeyFromArray(arr, key)
3012
+ }
3013
+ static getValuesByKey(arr = [], key) {
3014
+ return arr.reduce((acc, item) => {
3015
+ if (this.sameKey(item, key)) {
3016
+ acc.push(item.value)
3017
+ }
3018
+ return acc
3019
+ }, [])
3020
+ }
3021
+ static hasKeyValue(arr = [], key, value) {
3022
+ if (typeof value === 'undefined') {
3023
+ return arr.filter((item) => this.sameKey(item, key)).length > 0
3024
+ }
3025
+ return arr.filter((item) => (this.sameKey(item, key) && _isSame(item.value, value))).length > 0
3026
+ }
3027
+ static insertOrUpdateRecord(arr = [], key, value) {
3028
+ let copy = [...arr]
3029
+ if (!this.hasKeyValue(arr, key)) {
3030
+ copy.push(this.init({ key, value }))
3031
+ } else {
3032
+ copy = this.updateRecord(arr, key, value)
3033
+ }
3034
+ return copy
3035
+ }
3036
+ static keys(arr = []) {
3037
+ if (Array.isArray(arr)) {
3038
+ return arr.reduce((acc, item) => {
3039
+ acc.push(item.key)
3040
+ return acc
3041
+ }, [])
3042
+ }
3043
+ return []
3044
+ }
3045
+ static merge(toArr, fromArr) {
3046
+ (fromArr || []).map((from) => {
3047
+ const found = toArr.find((to) => {
3048
+ return to.key === from.key
3049
+ })
3050
+ if (found) {
3051
+ found.value = _mergeValues(from.value, found.value)
3052
+ } else {
3053
+ toArr.push(from)
3054
+ }
3055
+ })
3056
+ return toArr
3057
+ }
3058
+ static removeByKey(arr, key) {
3059
+ return arr.reduce((acc, item) => {
3060
+ if (!this.sameKey(item, key)) {
3061
+ acc.push(item)
3062
+ }
3063
+ return acc
3064
+ }, [])
3065
+ }
3066
+ static sameKey(item, key) {
3067
+ if (item) {
3068
+ return _isSame(item.key, key)
3069
+ }
3070
+ return false
3071
+ }
3072
+ static toObject(arr = []) {
3073
+ if (Array.isArray(arr)) {
3074
+ return arr.reduce((acc, item) => {
3075
+ acc[item.key] = item.value
3076
+ return acc
3077
+ }, {})
3078
+ }
3079
+ return {}
3080
+ }
3081
+ static toString(arr = [], delimiter = '; ') {
3082
+ if (Array.isArray(arr)) {
3083
+ return arr.reduce((acc, item) => {
3084
+ acc.push(`${item.key}: ${item.value}`)
3085
+ return acc
3086
+ }, []).join(delimiter)
3087
+ }
3088
+ return ''
3089
+ }
3090
+ static updateRecord(arr = [], key, value) {
3091
+ return arr.map((item) => {
3092
+ if (this.sameKey(item, key)) {
3093
+ return {
3094
+ ...item,
3095
+ value
3096
+ }
3097
+ }
3098
+ return item
3099
+ })
3100
+ }
3101
+ static updateOrInsertRecord(arr = [], key, value) {
3102
+ return this.insertOrUpdateRecord(arr, key, value)
3103
+ }
3104
+ static updateRecordsFromArray(arr = [], updateArr = []) {
3105
+ if (Array.isArray(arr) && Array.isArray(updateArr)) {
3106
+ const obj1 = this.toObject(arr)
3107
+ const obj2 = this.toObject(updateArr)
3108
+ return this.fromObject({
3109
+ ...obj1,
3110
+ ...obj2
3111
+ })
3112
+ }
3113
+ return []
3114
+ }
3115
+ static values(arr = []) {
3116
+ if (Array.isArray(arr)) {
3117
+ return arr.reduce((acc, item) => {
3118
+ acc.push(item.value)
3119
+ return acc
3120
+ }, [])
3121
+ }
3122
+ return []
3123
+ }
3124
+
3125
+ // getters
3126
+ get isValid() {
3127
+ return !!this.key
3128
+ }
3129
+
3130
+ get toObject() {
3131
+ const obj = {}
3132
+ if (this.isValid) {
3133
+ obj[this.key] = this.value
3134
+ }
3135
+ return obj
3136
+ }
3137
+ }
3138
+
3139
+ function _mergeValues(existingValue, newValue) {
3140
+ if (existingValue === undefined) return newValue
3141
+
3142
+ // Handle arrays by concatenating
3143
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
3144
+ return [...new Set([...existingValue, ...newValue])]
3145
+ }
3146
+
3147
+ // Handle objects by merging
3148
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
3149
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
3150
+ return { ...existingValue, ...newValue }
3151
+ }
3152
+
3153
+ // // Handle numbers by adding
3154
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
3155
+ // return existingValue
3156
+ // }
3157
+
3158
+ // // Handle strings by concatenating
3159
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
3160
+ // return existingValue
3161
+ // }
3162
+
3163
+ // Default: use the new value
3164
+ return newValue
3165
+ }
3166
+
3167
+ function _isSame(key1, key2) {
3168
+ return key1 === key2
3169
+ }
3170
+
3171
+
3172
+
3173
+ ;// ./lib/models/keyValueObject/index.js
3174
+
3175
+
3176
+
3177
+
3178
+ ;// ./lib/models/metadata/metadata.js
3179
+
3180
+
3181
+
3182
+ const DELIMITER = '_'
3183
+
3184
+ class Metadata extends KeyValueObject {
3185
+ static init(options = {}) {
3186
+ if (options instanceof this) {
3187
+ return options
3188
+ }
3189
+ const instance = new this({
3190
+ ...options,
3191
+ key: stringFormatter(options.key, DELIMITER),
3192
+ })
3193
+ return instance.isValid ? instance : null
3194
+ }
3195
+ static get _classname() {
3196
+ return 'Metadata'
3197
+ }
3198
+
3199
+ static merge(toArr, fromArr) {
3200
+ (fromArr || []).map((from) => {
3201
+ const found = toArr.find((to) => {
3202
+ return metadata_isSame(to.key, from.key)
3203
+ })
3204
+ if (found) {
3205
+ found.value = metadata_mergeValues(from.value, found.value)
3206
+ } else {
3207
+ toArr.push(from)
3208
+ }
3209
+ })
3210
+ return toArr
3211
+ }
3212
+ static sameKey(item, key) {
3213
+ return metadata_isSame(item.key, key)
3214
+ }
3215
+ }
3216
+
3217
+ function metadata_isSame(key1, key2) {
3218
+ return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
3219
+ }
3220
+
3221
+ function metadata_mergeValues(existingValue, newValue) {
3222
+ if (existingValue === undefined) return newValue
3223
+
3224
+ // Handle arrays by concatenating
3225
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
3226
+ return [...new Set([...existingValue, ...newValue])]
3227
+ }
3228
+
3229
+ // Handle objects by merging
3230
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
3231
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
3232
+ return { ...existingValue, ...newValue }
3233
+ }
3234
+
3235
+ // // Handle numbers by adding
3236
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
3237
+ // return existingValue
3238
+ // }
3239
+
3240
+ // // Handle strings by concatenating
3241
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
3242
+ // return existingValue
3243
+ // }
3244
+
3245
+ // Default: use the new value
3246
+ return newValue
3247
+ }
3248
+
3249
+
3250
+
3251
+ ;// ./lib/models/metadata/index.js
3252
+
3253
+
3254
+
3255
+
3256
+ ;// ./lib/models/trackedEntity/trackedEntity.js
3257
+
3258
+
3259
+ class TrackedEntity {
3260
+ constructor(options = {}) {
3261
+ options = options || {}
3262
+ const timestamp = Date.now()
3263
+ this.meta = {
3264
+ active: options.meta?.active ?? options.active ?? true,
3265
+ created: options.meta?.created ?? (options.created
3266
+ ? new Date(options.created).getTime()
3267
+ : timestamp),
3268
+ creator: options.meta?.creator ?? options.creator ?? '',
3269
+ deleted: options.meta?.deleted ?? options.deleted ?? false,
3270
+ modified: options.meta?.modified ?? (options.modified
3271
+ ? new Date(options.modified).getTime()
3272
+ : timestamp),
3273
+ owner: options.meta?.owner ?? options.owner ?? '',
3274
+ }
3275
+
3276
+ // if (trackFlat) {
3277
+ // Object.assign(this, _tracking)
3278
+ // } else {
3279
+ // this.meta = { ..._tracking, ...options.meta }
3280
+ // }
3281
+ }
3282
+
3283
+ // Class methods
3284
+ static get _classname() {
3285
+ return 'TrackedEntity'
3286
+ }
3287
+ static get _superclass() {
3288
+ return 'TrackedEntity'
3289
+ }
3290
+
3291
+ static init(options = {}) {
3292
+ return init(this, options)
3293
+ }
3294
+ static initFromArray(arr = []) {
3295
+ return initFromArray(this, arr)
3296
+ }
3297
+ static initOnlyValidFromArray(arr = []) {
3298
+ return initOnlyValidFromArray(this, arr)
3299
+ }
3300
+ // static nest(entity) {
3301
+ // const { active, created, creator, deleted, modified, owner, ...rest } = entity
3302
+ // return { ...rest, meta: { active, created, creator, deleted, modified, owner } }
3303
+ // }
3304
+
3305
+ // getters
3306
+ get isValid() {
3307
+ return !!this
3308
+ }
3309
+ get active() {
3310
+ return this.meta?.active ?? this.active
3311
+ }
3312
+ get created() {
3313
+ return this.meta?.created ?? this.created
3314
+ }
3315
+ get creator() {
3316
+ return this.meta?.creator ?? this.creator
3317
+ }
3318
+ get deleted() {
3319
+ return this.meta?.deleted ?? this.deleted
3320
+ }
3321
+ get modified() {
3322
+ return this.meta?.modified ?? this.modified
3323
+ }
3324
+ get owner() {
3325
+ return this.meta?.owner ?? this.owner
3326
+ }
3327
+ changeCreatorOwner({ source, target }) {
3328
+ return changeCreatorOwner(this, { source, target }).setModified()
3329
+ }
3330
+ delete() {
3331
+ return this.setDeleted()
3332
+ }
3333
+ setActive() {
3334
+ if (this.meta) {
3335
+ this.meta.active = true
3336
+ } else {
3337
+ this.active = true
3338
+ }
3339
+ return this
3340
+ }
3341
+ setDeleted() {
3342
+ if (this.meta) {
3343
+ this.meta.deleted = true
3344
+ } else {
3345
+ this.deleted = true
3346
+ }
3347
+ return this
3348
+ }
3349
+ setModified() {
3350
+ const timestamp = Date.now()
3351
+ if (this.meta) {
3352
+ this.meta.modified = timestamp
3353
+ } else {
3354
+ this.modified = timestamp
3355
+ }
3356
+ return this
3357
+ }
3358
+ setOwner(owner) {
3359
+ if (!owner) {
3360
+ return this
3361
+ }
3362
+ if (this.meta) {
3363
+ this.meta.owner = owner
3364
+ } else {
3365
+ this.owner = owner
3366
+ }
3367
+ return this
3368
+ }
3369
+ unsetActive() {
3370
+ if (this.meta) {
3371
+ this.meta.active = false
3372
+ } else {
3373
+ this.active = false
3374
+ }
3375
+ return this
3376
+ }
3377
+ unsetDeleted() {
3378
+ if (this.meta) {
3379
+ this.meta.deleted = false
3380
+ } else {
3381
+ this.deleted = false
3382
+ }
3383
+ return this
3384
+ }
3385
+
3386
+ update(update) {
3387
+ if (update.meta) {
3388
+ this.meta = { ...this.meta, ...update.meta }
3389
+ }
3390
+ return this.setModified()
3391
+ }
3392
+ }
3393
+
3394
+ ;// ./lib/models/trackedEntity/index.js
3395
+
3396
+ // Explicit named export (optional)
3397
+
3398
+ ;// ./lib/models/pushEnvelope/pushEnvelope.js
3399
+
3400
+
3401
+
3402
+
3403
+
3404
+ class PushEnvelope extends TrackedEntity {
3405
+ constructor(options) {
3406
+ options = options || {}
3407
+ super(options)
3408
+
3409
+ this.id = options.id
3410
+ this.body = options.body
3411
+ this.data = options.data
3412
+ this.dirty = options.dirty
3413
+ this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
3414
+ this.remarks = KeyValueObject.initOnlyValidFromArray(options.remarks)
3415
+ this.threadID = options.threadID
3416
+ this.title = options.title
3417
+ }
3418
+ static get _classname() {
3419
+ return 'PushEnvelope'
3420
+ }
3421
+ static get _superclass() {
3422
+ return 'PushEnvelope'
3423
+ }
3424
+ static init(options = {}) {
3425
+ return init(this, options)
3426
+ }
3427
+
3428
+ get _classname() {
3429
+ return 'PushEnvelope'
3430
+ }
3431
+
3432
+ get _superclass() {
3433
+ return 'PushEnvelope'
3434
+ }
3435
+
3436
+ get isValid() {
3437
+ return super.isValid && this.data
3438
+ }
3439
+
3440
+ }
3441
+
3442
+ ;// ./lib/models/pushEnvelope/index.js
3443
+
3444
+
3445
+ ;// ./lib/models/qMeta/qMeta.js
3446
+
3447
+
3448
+ const updateAllowedProps = [
3449
+ 'attributes',
3450
+ 'ref'
3451
+ ]
3452
+
3453
+ class QMeta {
3454
+ constructor(options = {}) {
3455
+ options = options || {}
3456
+ this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
3457
+ this.ref = options.ref || {}
3458
+ }
3459
+
3460
+ static get _classname() {
3461
+ return 'QMeta'
3462
+ }
3463
+ static get _superclass() {
3464
+ return 'QMeta'
3465
+ }
3466
+
3467
+ // Class methods
3468
+ static init(options = {}) {
3469
+ if (options instanceof QMeta) {
3470
+ return options
3471
+ }
3472
+ return new QMeta(options)
3473
+ }
3474
+
3475
+ // instance methods
3476
+ addAttribute(obj) {
3477
+ const kvObject = KeyValueObject.init(obj)
3478
+ if (!kvObject) {
3479
+ throw new Error('invalid meta attribute')
3480
+ }
3481
+ this.attributes.push(kvObject)
3482
+ return this
3483
+ }
3484
+
3485
+ update(obj) {
3486
+ Object.keys(obj).forEach((key) => {
3487
+ if (updateAllowedProps.includes(key)) {
3488
+ if (key === 'attributes') {
3489
+ this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
3490
+ } else {
3491
+ this[key] = obj[key]
3492
+ }
3493
+ }
3494
+ })
3495
+ return this
3496
+ }
3497
+ }
3498
+
3499
+
3500
+
3501
+ ;// ./lib/models/qMeta/index.js
3502
+
3503
+
3504
+
3505
+
3506
+ ;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
3507
+
3508
+
3509
+
3510
+
3511
+ class TenantAwareEntity extends TrackedEntity {
3512
+ constructor(options = {}) {
3513
+ options = options || {}
3514
+
3515
+ /**
3516
+ * instead of throw error, we choose to implement the isValid checking
3517
+ */
3518
+ // if (!options.tenantCode) {
3519
+ // throw new Error('tenantCode required')
3520
+ // }
3521
+
3522
+ super(options)
3523
+
3524
+ this._tenant = options._tenant
3525
+
3526
+ this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
3527
+ this.remarks = KeyValueObject.initOnlyValidFromArray(options.remarks)
3528
+ this.tenantCode = options.tenantCode // Required for multi-tenancy
3529
+ }
3530
+
3531
+ // Class methods
3532
+ static get _classname() {
3533
+ return 'TenantAwareEntity'
3534
+ }
3535
+ static get _superclass() {
3536
+ return 'TenantAwareEntity'
3537
+ }
3538
+
3539
+ // getters
3540
+ get isValid() {
3541
+ return super.isValid && !!this.tenantCode // Required for multi-tenancy
3542
+ }
3543
+
3544
+ // instance methods
3545
+ getMetadata() {
3546
+ return this.metadata
3547
+ }
3548
+ getMetadataByKey(key) {
3549
+ return Metadata.foundByKey(this.metadata, key)
3550
+ }
3551
+ getMetadataValueByKey(key) {
3552
+ const found = this.getMetadataByKey(key)
3553
+ return found ? found.value : null
3554
+ }
3555
+ getRemarks() {
3556
+ return this.remarks
3557
+ }
3558
+ getRemarkByKey(key) {
3559
+ return KeyValueObject.foundByKey(this.remarks, key)
3560
+ }
3561
+ getRemarksValueByKey(key) {
3562
+ const found = this.getRemarkByKey(key)
3563
+ return found ? found.value : null
3564
+ }
3565
+ getTenantCode() {
3566
+ return this.tenantCode
3567
+ }
3568
+
3569
+ update(update) {
3570
+ if (update.metadata && Array.isArray(update.metadata)) {
3571
+ this.metadata = Metadata.initOnlyValidFromArray(update.metadata)
3572
+ }
3573
+ if (update.remarks && Array.isArray(update.remarks)) {
3574
+ this.remarks = KeyValueObject.initOnlyValidFromArray(update.remarks)
3575
+ }
3576
+ return super.update(update)
3577
+ }
3578
+ }
3579
+
3580
+ ;// ./lib/models/tenantAwareEntity/index.js
3581
+
3582
+
3583
+
3584
+ ;// ./lib/models/uniqueKeyGenerator/uniqueKeyGenerator.js
3585
+
3586
+
3587
+ class UniqueKeyGenerator {
3588
+ static get _classname() {
3589
+ return 'UniqueKeyGenerator'
3590
+ }
3591
+ static get _superclass() {
3592
+ return 'UniqueKeyGenerator'
3593
+ }
3594
+ static makeFormatter({ fieldName, format, options }) {
3595
+ switch (format) {
3596
+ case 'set_code':
3597
+ return _makeSetCode(fieldName, options)
3598
+ default:
3599
+ return _makeSetCode(fieldName, options)
3600
+ }
3601
+ }
3602
+ static makeGenerator(arr) {
3603
+ const fns = arr.map((item) => this.makeFormatter(item))
3604
+ return async (obj) => {
3605
+ const output = await pReduce(fns, async (acc, fn) => {
3606
+ const _obj = await fn(obj)
3607
+ return Object.assign(acc, _obj)
3608
+ }, obj)
3609
+ return output
3610
+ }
3611
+ }
3612
+ }
3613
+
3614
+ function _makeSetCode(fieldName, options) {
3615
+ return async (obj = {}) => {
3616
+ if (obj[fieldName]) {
3617
+ return {}
3618
+ }
3619
+ return {
3620
+ [fieldName]: stringHelper.setCode()
3621
+ }
3622
+ }
3623
+ }
3624
+
3625
+
3626
+
3627
+ ;// ./lib/models/uniqueKeyGenerator/index.js
3628
+
3629
+
3630
+
3631
+
3632
+ ;// ./lib/models/index.js
3633
+
3634
+
3635
+
3636
+
3637
+
3638
+
3639
+
3640
+
3641
+
3642
+
3643
+
3644
+
3645
+
3646
+ ;// ./lib/index.js
3647
+
3648
+
3649
+
3650
+ ;// ./index.js
3651
+
3652
+
3653
+ export { ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, PushEnvelope, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, calculateAge, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, groupArrayByKey, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, shuffleArray, stringFormatter, stringHelper, tenantPlugin, trackingPlugin };