@questwork/q-utilities 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.cjs +957 -65
- package/dist/q-utilities.esm.js +3434 -0
- package/dist/q-utilities.min.js +957 -65
- package/package.json +14 -8
package/dist/q-utilities.min.js
CHANGED
|
@@ -49,6 +49,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
49
49
|
// EXPORTS
|
|
50
50
|
__webpack_require__.d(__webpack_exports__, {
|
|
51
51
|
ApiResponse: () => (/* reexport */ ApiResponse),
|
|
52
|
+
AwsStsS3Client: () => (/* reexport */ AwsStsS3Client),
|
|
52
53
|
KeyValueObject: () => (/* reexport */ KeyValueObject),
|
|
53
54
|
Metadata: () => (/* reexport */ Metadata),
|
|
54
55
|
QMeta: () => (/* reexport */ QMeta),
|
|
@@ -58,8 +59,13 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
58
59
|
TenantAwareEntity: () => (/* reexport */ TenantAwareEntity),
|
|
59
60
|
TrackedEntity: () => (/* reexport */ TrackedEntity),
|
|
60
61
|
UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
|
|
62
|
+
authorize: () => (/* reexport */ authorize),
|
|
63
|
+
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
61
64
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
62
65
|
convertString: () => (/* reexport */ convertString),
|
|
66
|
+
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
67
|
+
expressHelper: () => (/* reexport */ expressHelper),
|
|
68
|
+
extractEmails: () => (/* reexport */ extractEmails),
|
|
63
69
|
formatDate: () => (/* reexport */ formatDate),
|
|
64
70
|
generalPost: () => (/* reexport */ generalPost),
|
|
65
71
|
getValidation: () => (/* reexport */ getValidation),
|
|
@@ -69,13 +75,75 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
69
75
|
initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
|
|
70
76
|
makeApiResponse: () => (/* reexport */ makeApiResponse),
|
|
71
77
|
makeService: () => (/* reexport */ makeService),
|
|
78
|
+
mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
|
|
72
79
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
73
80
|
pReduce: () => (/* reexport */ pReduce),
|
|
74
81
|
padZeros: () => (/* reexport */ padZeros),
|
|
82
|
+
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
83
|
+
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
75
84
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
76
|
-
stringHelper: () => (/* reexport */ stringHelper)
|
|
85
|
+
stringHelper: () => (/* reexport */ stringHelper),
|
|
86
|
+
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
77
87
|
});
|
|
78
88
|
|
|
89
|
+
;// ./lib/helpers/authorize/authorize.js
|
|
90
|
+
function authorize({ allowOwner, query = {}, required, user }) {
|
|
91
|
+
if (!user) {
|
|
92
|
+
throw new Error('Require login.')
|
|
93
|
+
}
|
|
94
|
+
if (!user.permission) {
|
|
95
|
+
throw new Error('You do not have any permission.')
|
|
96
|
+
}
|
|
97
|
+
const scopes = user.permission.getScopes(required || {})
|
|
98
|
+
if (!scopes || scopes.length === 0) {
|
|
99
|
+
throw new Error('You are not allowed in this scope.')
|
|
100
|
+
}
|
|
101
|
+
if (!scopes.includes('*')) {
|
|
102
|
+
query.tenantCode = user.tenantCode
|
|
103
|
+
}
|
|
104
|
+
if (!scopes.includes('TENANT')) {
|
|
105
|
+
query.eventShortCode = user.eventShortCode
|
|
106
|
+
}
|
|
107
|
+
if (!scopes.includes('EVENT')) {
|
|
108
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
109
|
+
}
|
|
110
|
+
if (allowOwner) {
|
|
111
|
+
query.__ALLOW_OWNER = true
|
|
112
|
+
}
|
|
113
|
+
// not good, just use it as example
|
|
114
|
+
if (user.hasExcludedFields) {
|
|
115
|
+
query.__EXCLUDED_FIELDS = user.getExcludedFields(required)
|
|
116
|
+
}
|
|
117
|
+
query.__LOGIN_SUBJECT_CODE = user.loginSubjectCode
|
|
118
|
+
return query
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
;// ./lib/helpers/authorize/index.js
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
|
|
125
|
+
function changeCreatorOwner(that, { source, target }) {
|
|
126
|
+
if (that.meta) {
|
|
127
|
+
if (!that.meta.creator || that.meta.creator === source.getId()) {
|
|
128
|
+
that.meta.creator = target.getId()
|
|
129
|
+
}
|
|
130
|
+
if (!that.meta.owner || that.meta.owner === source.getId()) {
|
|
131
|
+
that.meta.owner = target.getId()
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (!that.creator || that.creator === source.getId()) {
|
|
135
|
+
that.creator = target.getId()
|
|
136
|
+
}
|
|
137
|
+
if (!that.owner || that.owner === source.getId()) {
|
|
138
|
+
that.owner = target.getId()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return that
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
145
|
+
|
|
146
|
+
|
|
79
147
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
80
148
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
81
149
|
if (!rule) {
|
|
@@ -84,10 +152,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
84
152
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
85
153
|
return false
|
|
86
154
|
}
|
|
87
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
155
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
88
156
|
const [valueAttribute] = Object.keys(value)
|
|
89
157
|
|
|
90
|
-
if (!key) {
|
|
158
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
91
159
|
switch (valueAttribute) {
|
|
92
160
|
case '$and': {
|
|
93
161
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -99,14 +167,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
99
167
|
return false
|
|
100
168
|
}
|
|
101
169
|
}
|
|
102
|
-
|
|
103
|
-
let rowValue = getDataByKey(key, data)
|
|
104
|
-
|
|
105
|
-
// debugger
|
|
170
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
106
171
|
|
|
107
172
|
// if KeyValue object
|
|
108
173
|
if (keyValuePath) {
|
|
109
|
-
console.log('keyValuePath', keyValuePath)
|
|
110
174
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
111
175
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
112
176
|
}
|
|
@@ -125,6 +189,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
125
189
|
case '$gte': {
|
|
126
190
|
return rowValue >= value['$gte']
|
|
127
191
|
}
|
|
192
|
+
case '$hasOverlap': {
|
|
193
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
194
|
+
}
|
|
128
195
|
case '$lt': {
|
|
129
196
|
return rowValue < value['$lt']
|
|
130
197
|
}
|
|
@@ -201,6 +268,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
201
268
|
default:
|
|
202
269
|
return false
|
|
203
270
|
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function _hasOverlap(item1, item2) {
|
|
275
|
+
let arr1 = item1
|
|
276
|
+
let arr2 = item2
|
|
277
|
+
if (typeof arr1 === 'string') {
|
|
278
|
+
arr1 = arr1.split(',')
|
|
279
|
+
}
|
|
280
|
+
if (typeof arr2 === 'string') {
|
|
281
|
+
arr2 = arr2.split(',')
|
|
282
|
+
}
|
|
283
|
+
const set1 = new Set(arr1)
|
|
284
|
+
return arr2.find((i) => (set1.has(i)))
|
|
204
285
|
}
|
|
205
286
|
|
|
206
287
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -337,6 +418,7 @@ const _FN_NAMES = [
|
|
|
337
418
|
'lte',
|
|
338
419
|
'map',
|
|
339
420
|
'neq',
|
|
421
|
+
'removeHtml',
|
|
340
422
|
'toLowerCase',
|
|
341
423
|
'toUpperCase',
|
|
342
424
|
]
|
|
@@ -925,6 +1007,66 @@ function _neq(data, args) {
|
|
|
925
1007
|
|
|
926
1008
|
|
|
927
1009
|
|
|
1010
|
+
;// ./lib/models/templateCompiler/helpers/_removeHtml.js
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
function _removeHtml(html, args) {
|
|
1014
|
+
if (html === null || html === undefined) {
|
|
1015
|
+
return null
|
|
1016
|
+
}
|
|
1017
|
+
if (!Array.isArray(args)) {
|
|
1018
|
+
throw new TemplateCompilerException(`_removeHtml: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: args parts must be array`)
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
return _htmlToPlainText(html, args[0])
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
function _htmlToPlainText(html, delimiter = '\n') {
|
|
1025
|
+
if (typeof delimiter !== 'string') {
|
|
1026
|
+
delimiter = '\n'; // Fallback to default if not a string
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// First decode HTML entities and normalize whitespace
|
|
1030
|
+
const decodedHtml = html
|
|
1031
|
+
.replace(/ /g, ' ')
|
|
1032
|
+
.replace(/\s+/g, ' '); // Collapse all whitespace to single spaces
|
|
1033
|
+
|
|
1034
|
+
// Process HTML tags
|
|
1035
|
+
let text = decodedHtml
|
|
1036
|
+
// Replace block tags with temporary marker (~~~)
|
|
1037
|
+
.replace(/<\/?(p|div|h[1-6]|ul|ol|li|pre|section|article|table|tr|td|th)(\s[^>]*)?>/gi, '~~~')
|
|
1038
|
+
// Replace <br> tags with temporary marker (~~~)
|
|
1039
|
+
.replace(/<br\s*\/?>/gi, '~~~')
|
|
1040
|
+
// Remove all other tags
|
|
1041
|
+
.replace(/<[^>]+>/g, '')
|
|
1042
|
+
// Convert markers to specified delimiter
|
|
1043
|
+
.replace(/~~~+/g, delimiter)
|
|
1044
|
+
// Trim and clean whitespace
|
|
1045
|
+
.trim();
|
|
1046
|
+
|
|
1047
|
+
// Special handling for empty delimiter
|
|
1048
|
+
if (delimiter === '') {
|
|
1049
|
+
// Collapse all whitespace to single space
|
|
1050
|
+
text = text.replace(/\s+/g, ' ');
|
|
1051
|
+
} else {
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
// Collapse multiple delimiters to single
|
|
1055
|
+
text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter);
|
|
1056
|
+
// Remove leading/trailing delimiters
|
|
1057
|
+
text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '');
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
return text;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
function escapeRegExp(string) {
|
|
1065
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
|
|
928
1070
|
;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
|
|
929
1071
|
|
|
930
1072
|
|
|
@@ -979,6 +1121,7 @@ function _toUpperCase(data, args) {
|
|
|
979
1121
|
|
|
980
1122
|
|
|
981
1123
|
|
|
1124
|
+
|
|
982
1125
|
|
|
983
1126
|
|
|
984
1127
|
;// ./lib/models/templateCompiler/templateCompiler.js
|
|
@@ -1049,6 +1192,9 @@ class TemplateCompiler {
|
|
|
1049
1192
|
static neq(data, args) {
|
|
1050
1193
|
return _neq(data, args)
|
|
1051
1194
|
}
|
|
1195
|
+
static removeHtml(data, args) {
|
|
1196
|
+
return _removeHtml(data, args)
|
|
1197
|
+
}
|
|
1052
1198
|
static toLowerCase(data, args) {
|
|
1053
1199
|
return _toLowerCase(data, args)
|
|
1054
1200
|
}
|
|
@@ -1058,6 +1204,9 @@ class TemplateCompiler {
|
|
|
1058
1204
|
static parseFunction(expression) {
|
|
1059
1205
|
return _parseFunction(expression, _FN_NAMES)
|
|
1060
1206
|
}
|
|
1207
|
+
static parseParams(parameters) {
|
|
1208
|
+
return _parseParams(parameters)
|
|
1209
|
+
}
|
|
1061
1210
|
|
|
1062
1211
|
pipe(expression = '') {
|
|
1063
1212
|
this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
|
|
@@ -1237,6 +1386,8 @@ function _callFunction(data, functionName, parameters) {
|
|
|
1237
1386
|
return _map(data, parameters)
|
|
1238
1387
|
case 'neq':
|
|
1239
1388
|
return _neq(data, parameters)
|
|
1389
|
+
case 'removeHtml':
|
|
1390
|
+
return _removeHtml(data, parameters)
|
|
1240
1391
|
case 'toLowerCase':
|
|
1241
1392
|
return _toLowerCase(data)
|
|
1242
1393
|
case 'toUpperCase':
|
|
@@ -1353,6 +1504,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1353
1504
|
;// ./lib/helpers/convertString/index.js
|
|
1354
1505
|
|
|
1355
1506
|
|
|
1507
|
+
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1508
|
+
function escapeRegex(string) {
|
|
1509
|
+
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
;// ./lib/helpers/escapeRegex/index.js
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
;// ./lib/helpers/expressHelper/customHandler.js
|
|
1516
|
+
function customHandler({ responseHelper, handler, ignoreError = false }) {
|
|
1517
|
+
return async (req, res, next) => {
|
|
1518
|
+
try {
|
|
1519
|
+
await handler({ req, res })
|
|
1520
|
+
await next()
|
|
1521
|
+
} catch (err) {
|
|
1522
|
+
if (ignoreError) {
|
|
1523
|
+
await next()
|
|
1524
|
+
} else {
|
|
1525
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
;// ./lib/helpers/expressHelper/findAllResult.js
|
|
1532
|
+
function findAllResult({ responseHelper, service }) {
|
|
1533
|
+
return async (req, res, next) => {
|
|
1534
|
+
try {
|
|
1535
|
+
const { query } = req
|
|
1536
|
+
const result = await service.findAll({ query })
|
|
1537
|
+
res.locals.findAllResult = result
|
|
1538
|
+
await next()
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
;// ./lib/helpers/expressHelper/findOneResult.js
|
|
1546
|
+
function findOneResult({ responseHelper, service }) {
|
|
1547
|
+
return async (req, res, next) => {
|
|
1548
|
+
try {
|
|
1549
|
+
const { params, query } = req
|
|
1550
|
+
const { id } = params
|
|
1551
|
+
const result = await service.findOne({
|
|
1552
|
+
query: {
|
|
1553
|
+
...query,
|
|
1554
|
+
id
|
|
1555
|
+
}
|
|
1556
|
+
})
|
|
1557
|
+
res.locals.findOneResult = result
|
|
1558
|
+
await next()
|
|
1559
|
+
} catch (err) {
|
|
1560
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
;// ./lib/helpers/expressHelper/postResult.js
|
|
1566
|
+
function postResult({ responseHelper, service }) {
|
|
1567
|
+
return async (req, res, next) => {
|
|
1568
|
+
try {
|
|
1569
|
+
const { body } = req
|
|
1570
|
+
let result
|
|
1571
|
+
if (Array.isArray(body)) {
|
|
1572
|
+
result = await service.saveAll({ docs: body })
|
|
1573
|
+
} else {
|
|
1574
|
+
result = await service.saveOne({ doc: body })
|
|
1575
|
+
}
|
|
1576
|
+
res.locals.postResult = result
|
|
1577
|
+
await next()
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
;// ./lib/helpers/expressHelper/updateOneResult.js
|
|
1585
|
+
function updateOneResult({ responseHelper, service }) {
|
|
1586
|
+
return async (req, res, next) => {
|
|
1587
|
+
try {
|
|
1588
|
+
const { body, params } = req
|
|
1589
|
+
const { id } = params
|
|
1590
|
+
if (id !== body.id) {
|
|
1591
|
+
throw new Error('id in params and body must be same')
|
|
1592
|
+
}
|
|
1593
|
+
const { data } = await service.findOne({ query: { id } })
|
|
1594
|
+
const doc = data[0]
|
|
1595
|
+
doc.update(body)
|
|
1596
|
+
const result = await service.saveOne({ doc })
|
|
1597
|
+
res.locals.updateOneResult = result
|
|
1598
|
+
await next()
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
;// ./lib/helpers/expressHelper/index.js
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
const expressHelper = {
|
|
1614
|
+
customHandler: customHandler,
|
|
1615
|
+
findAllResult: findAllResult,
|
|
1616
|
+
findOneResult: findOneResult,
|
|
1617
|
+
postResult: postResult,
|
|
1618
|
+
updateOneResult: updateOneResult,
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
;// ./lib/helpers/extractEmails/extractEmails.js
|
|
1622
|
+
/**
|
|
1623
|
+
* Extracts and normalizes unique email addresses from an array containing messy entries
|
|
1624
|
+
* @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
|
|
1625
|
+
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1626
|
+
*/
|
|
1627
|
+
function extractEmails(dirtyArray) {
|
|
1628
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
|
|
1629
|
+
const emails = new Set()
|
|
1630
|
+
|
|
1631
|
+
// Handle null/undefined input array
|
|
1632
|
+
if (!dirtyArray) return []
|
|
1633
|
+
|
|
1634
|
+
dirtyArray.forEach(entry => {
|
|
1635
|
+
// Skip null, undefined, empty, or whitespace-only entries
|
|
1636
|
+
if (!entry || typeof entry !== 'string' || !entry.trim()) return
|
|
1637
|
+
|
|
1638
|
+
try {
|
|
1639
|
+
const cleanEntry = entry
|
|
1640
|
+
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1641
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1642
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1643
|
+
.trim()
|
|
1644
|
+
|
|
1645
|
+
// Extract all email matches
|
|
1646
|
+
const matches = cleanEntry.match(emailRegex)
|
|
1647
|
+
if (matches) {
|
|
1648
|
+
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1649
|
+
}
|
|
1650
|
+
} catch (e) {
|
|
1651
|
+
console.warn('Failed to process entry:', entry, e)
|
|
1652
|
+
}
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
// Convert Set to array and sort alphabetically
|
|
1656
|
+
return Array.from(emails).sort((a, b) => a.localeCompare(b))
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
;// ./lib/helpers/extractEmails/index.js
|
|
1660
|
+
|
|
1661
|
+
|
|
1356
1662
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1357
1663
|
const objectHelper = {
|
|
1358
1664
|
get(obj, path) {
|
|
@@ -1385,42 +1691,59 @@ const objectHelper = {
|
|
|
1385
1691
|
},
|
|
1386
1692
|
merge,
|
|
1387
1693
|
set(obj, path, value) {
|
|
1388
|
-
const parts = path.split('.')
|
|
1389
|
-
let current = obj
|
|
1694
|
+
const parts = path.split('.');
|
|
1695
|
+
let current = obj;
|
|
1696
|
+
|
|
1697
|
+
// 处理所有中间部分
|
|
1390
1698
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
1391
|
-
const part = parts[i]
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1699
|
+
const part = parts[i];
|
|
1700
|
+
let key, index;
|
|
1701
|
+
|
|
1702
|
+
// 检查是否是数组索引格式,如key[0]
|
|
1703
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
1704
|
+
if (arrayMatch) {
|
|
1705
|
+
key = arrayMatch[1];
|
|
1706
|
+
index = parseInt(arrayMatch[2], 10);
|
|
1707
|
+
// 确保当前层级的数组存在
|
|
1708
|
+
if (!current[key] || !Array.isArray(current[key])) {
|
|
1709
|
+
current[key] = [];
|
|
1397
1710
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
// 处理数组索引
|
|
1402
|
-
const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
|
|
1403
|
-
if (arrayMatch) {
|
|
1404
|
-
const key = arrayMatch[1]
|
|
1405
|
-
const index = arrayMatch[2]
|
|
1406
|
-
if (Array.isArray(current[key]) && current[key][index]) {
|
|
1407
|
-
current = current[key][index]
|
|
1408
|
-
} else {
|
|
1409
|
-
return // 如果数组或索引不存在,直接返回
|
|
1410
|
-
}
|
|
1711
|
+
// 扩展数组到足够大
|
|
1712
|
+
while (current[key].length <= index) {
|
|
1713
|
+
current[key].push(undefined);
|
|
1411
1714
|
}
|
|
1715
|
+
// 如果当前位置未定义或为null,初始化为对象
|
|
1716
|
+
if (current[key][index] == null) {
|
|
1717
|
+
current[key][index] = {};
|
|
1718
|
+
}
|
|
1719
|
+
current = current[key][index];
|
|
1412
1720
|
} else {
|
|
1413
1721
|
// 处理普通属性
|
|
1414
1722
|
if (!current[part]) {
|
|
1415
|
-
current[part] = {}
|
|
1723
|
+
current[part] = {};
|
|
1416
1724
|
}
|
|
1417
|
-
current = current[part]
|
|
1725
|
+
current = current[part];
|
|
1418
1726
|
}
|
|
1419
1727
|
}
|
|
1420
|
-
|
|
1421
|
-
//
|
|
1422
|
-
const lastPart = parts[parts.length - 1]
|
|
1423
|
-
|
|
1728
|
+
|
|
1729
|
+
// 处理最后一部分
|
|
1730
|
+
const lastPart = parts[parts.length - 1];
|
|
1731
|
+
const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
|
|
1732
|
+
if (arrayMatch) {
|
|
1733
|
+
const key = arrayMatch[1];
|
|
1734
|
+
const index = parseInt(arrayMatch[2], 10);
|
|
1735
|
+
// 确保数组存在
|
|
1736
|
+
if (!current[key] || !Array.isArray(current[key])) {
|
|
1737
|
+
current[key] = [];
|
|
1738
|
+
}
|
|
1739
|
+
// 扩展数组到所需索引
|
|
1740
|
+
while (current[key].length <= index) {
|
|
1741
|
+
current[key].push(undefined);
|
|
1742
|
+
}
|
|
1743
|
+
current[key][index] = value;
|
|
1744
|
+
} else {
|
|
1745
|
+
current[lastPart] = value;
|
|
1746
|
+
}
|
|
1424
1747
|
}
|
|
1425
1748
|
}
|
|
1426
1749
|
|
|
@@ -1489,6 +1812,8 @@ async function pReduce(iterable, reducer, initialValue) {
|
|
|
1489
1812
|
|
|
1490
1813
|
|
|
1491
1814
|
;// ./lib/models/repo/repo.js
|
|
1815
|
+
|
|
1816
|
+
|
|
1492
1817
|
class Repo {
|
|
1493
1818
|
constructor(options) {
|
|
1494
1819
|
options = options || {}
|
|
@@ -1501,11 +1826,7 @@ class Repo {
|
|
|
1501
1826
|
: null
|
|
1502
1827
|
}
|
|
1503
1828
|
static init(options = {}) {
|
|
1504
|
-
|
|
1505
|
-
return options
|
|
1506
|
-
}
|
|
1507
|
-
const instance = new this(options)
|
|
1508
|
-
return instance.isValid ? instance : null
|
|
1829
|
+
return init(this, options)
|
|
1509
1830
|
}
|
|
1510
1831
|
static get _classname() {
|
|
1511
1832
|
return 'Repo'
|
|
@@ -1697,6 +2018,11 @@ function _makeLog({ systemLog, label, message: message1, input } = {}) {
|
|
|
1697
2018
|
|
|
1698
2019
|
|
|
1699
2020
|
|
|
2021
|
+
;// ./lib/models/repo/index.js
|
|
2022
|
+
|
|
2023
|
+
|
|
2024
|
+
|
|
2025
|
+
|
|
1700
2026
|
;// ./lib/models/apiResponse/apiResponse.js
|
|
1701
2027
|
class ApiResponse {
|
|
1702
2028
|
constructor(options = {}) {
|
|
@@ -1841,6 +2167,11 @@ function makeService({ repo }) {
|
|
|
1841
2167
|
|
|
1842
2168
|
|
|
1843
2169
|
|
|
2170
|
+
;// ./lib/models/service/index.js
|
|
2171
|
+
|
|
2172
|
+
|
|
2173
|
+
|
|
2174
|
+
|
|
1844
2175
|
;// ./lib/helpers/generalPost/generalPost.js
|
|
1845
2176
|
|
|
1846
2177
|
|
|
@@ -1865,7 +2196,13 @@ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resour
|
|
|
1865
2196
|
function _attachShared(data, globalShared = {}, shared = {}) {
|
|
1866
2197
|
Object.keys(shared).forEach((key) => {
|
|
1867
2198
|
const _data = data[key]
|
|
1868
|
-
|
|
2199
|
+
if (Array.isArray(_data)) {
|
|
2200
|
+
data[key] = _data.map((_dataItem) => {
|
|
2201
|
+
return objectHelper.merge({}, _dataItem, globalShared, shared[key] || {})
|
|
2202
|
+
})
|
|
2203
|
+
} else {
|
|
2204
|
+
data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
|
|
2205
|
+
}
|
|
1869
2206
|
})
|
|
1870
2207
|
}
|
|
1871
2208
|
|
|
@@ -1900,7 +2237,7 @@ function init(_class, options) {
|
|
|
1900
2237
|
}
|
|
1901
2238
|
try {
|
|
1902
2239
|
const instance = new _class(options)
|
|
1903
|
-
return instance.isValid ? instance : null
|
|
2240
|
+
return instance.isValid !== false ? instance : null
|
|
1904
2241
|
} catch (e) {
|
|
1905
2242
|
console.log(`init failed for class: ${_class._classname || 'no _classname'}`, e)
|
|
1906
2243
|
return null
|
|
@@ -1933,6 +2270,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
1933
2270
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
1934
2271
|
|
|
1935
2272
|
|
|
2273
|
+
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2274
|
+
function mergeArraysByKey(arr1, arr2) {
|
|
2275
|
+
// Handle undefined/null inputs by defaulting to empty arrays
|
|
2276
|
+
const safeArr1 = Array.isArray(arr1) ? arr1 : []
|
|
2277
|
+
const safeArr2 = Array.isArray(arr2) ? arr2 : []
|
|
2278
|
+
|
|
2279
|
+
const mergedMap = new Map()
|
|
2280
|
+
|
|
2281
|
+
// Helper function to merge values based on their type
|
|
2282
|
+
const mergeValues = (existingValue, newValue) => {
|
|
2283
|
+
if (existingValue === undefined) return newValue
|
|
2284
|
+
|
|
2285
|
+
// Handle arrays by concatenating
|
|
2286
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2287
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
// Handle objects by merging
|
|
2291
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2292
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2293
|
+
return { ...existingValue, ...newValue }
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// // Handle numbers by adding
|
|
2297
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2298
|
+
// return existingValue
|
|
2299
|
+
// }
|
|
2300
|
+
|
|
2301
|
+
// // Handle strings by concatenating
|
|
2302
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2303
|
+
// return existingValue
|
|
2304
|
+
// }
|
|
2305
|
+
|
|
2306
|
+
// Default: use the new value
|
|
2307
|
+
return newValue
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// Process first array
|
|
2311
|
+
safeArr1.forEach(item => {
|
|
2312
|
+
mergedMap.set(item.key, item.value)
|
|
2313
|
+
})
|
|
2314
|
+
|
|
2315
|
+
// Process second array and merge values
|
|
2316
|
+
safeArr2.forEach(item => {
|
|
2317
|
+
const existingValue = mergedMap.get(item.key)
|
|
2318
|
+
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2319
|
+
})
|
|
2320
|
+
|
|
2321
|
+
// Convert back to array format
|
|
2322
|
+
return Array.from(mergedMap.entries()).map(([key, value]) => ({
|
|
2323
|
+
key,
|
|
2324
|
+
value
|
|
2325
|
+
}))
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
;// ./lib/helpers/mergeArraysByKey/index.js
|
|
2329
|
+
|
|
2330
|
+
|
|
1936
2331
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
1937
2332
|
function padZeros(num, minLength = 6) {
|
|
1938
2333
|
num = num.toString()
|
|
@@ -1954,6 +2349,102 @@ function padZeros(num, minLength = 6) {
|
|
|
1954
2349
|
|
|
1955
2350
|
|
|
1956
2351
|
|
|
2352
|
+
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2353
|
+
function replacePlaceholders({ content, mapping }) {
|
|
2354
|
+
let isObjectMode = false
|
|
2355
|
+
|
|
2356
|
+
if (typeof content === 'object' && content !== null) {
|
|
2357
|
+
content = JSON.stringify(content)
|
|
2358
|
+
isObjectMode = true
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2362
|
+
const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
|
|
2363
|
+
|
|
2364
|
+
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2365
|
+
|
|
2366
|
+
// Split the path into parts
|
|
2367
|
+
const keys = path.trim().split('.')
|
|
2368
|
+
|
|
2369
|
+
// Traverse the nested object structure
|
|
2370
|
+
let value = mapping
|
|
2371
|
+
for (const key of keys) {
|
|
2372
|
+
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2373
|
+
if (!key) continue
|
|
2374
|
+
|
|
2375
|
+
value = value?.[key]
|
|
2376
|
+
if (value === undefined) {
|
|
2377
|
+
break
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// Apply default if missing
|
|
2382
|
+
if (value === undefined) value = defaultValue?.trim();
|
|
2383
|
+
if (value === undefined) return isObjectMode ? undefined : match;
|
|
2384
|
+
|
|
2385
|
+
value = value !== undefined
|
|
2386
|
+
? leadingBrackets + value + trailingBrackets
|
|
2387
|
+
: match
|
|
2388
|
+
|
|
2389
|
+
// Return replacement or original if not found
|
|
2390
|
+
return value
|
|
2391
|
+
})
|
|
2392
|
+
|
|
2393
|
+
if (isObjectMode) {
|
|
2394
|
+
return JSON.parse(result)
|
|
2395
|
+
}
|
|
2396
|
+
return result
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
;// ./lib/helpers/replacePlaceholders/index.js
|
|
2400
|
+
|
|
2401
|
+
|
|
2402
|
+
;// ./lib/helpers/sanitizeText/sanitizeText.js
|
|
2403
|
+
/**
|
|
2404
|
+
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2405
|
+
* @param {string} input - The string to sanitize.
|
|
2406
|
+
* @param {Object} [options] - Configuration options.
|
|
2407
|
+
* @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
|
|
2408
|
+
* @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
|
|
2409
|
+
* @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
|
|
2410
|
+
* @returns {string} The sanitized string.
|
|
2411
|
+
*/
|
|
2412
|
+
function sanitizeText(input, options = {}) {
|
|
2413
|
+
const {
|
|
2414
|
+
normalizeWhitespace = true,
|
|
2415
|
+
removeNewlines = false,
|
|
2416
|
+
trim = true,
|
|
2417
|
+
} = options
|
|
2418
|
+
|
|
2419
|
+
if (typeof input !== 'string') {
|
|
2420
|
+
return input
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
let result = input
|
|
2424
|
+
|
|
2425
|
+
// Phase 1: Remove hidden/control characters
|
|
2426
|
+
result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2427
|
+
|
|
2428
|
+
// Phase 2: Handle whitespace transformations
|
|
2429
|
+
if (removeNewlines) {
|
|
2430
|
+
result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
if (normalizeWhitespace) {
|
|
2434
|
+
result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
// Phase 3: Final trimming
|
|
2438
|
+
if (trim) {
|
|
2439
|
+
result = result.trim()
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
return result
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
;// ./lib/helpers/sanitizeText/index.js
|
|
2446
|
+
|
|
2447
|
+
|
|
1957
2448
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
1958
2449
|
function stringFormatter(str, delimiter = '_') {
|
|
1959
2450
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2079,10 +2570,18 @@ function toCamelCase(str) {
|
|
|
2079
2570
|
.join('')
|
|
2080
2571
|
}
|
|
2081
2572
|
|
|
2573
|
+
function toLowerCase(str) {
|
|
2574
|
+
if (!str) return ''
|
|
2575
|
+
return str
|
|
2576
|
+
.trim()
|
|
2577
|
+
.toLowerCase()
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2082
2580
|
const stringHelper = {
|
|
2083
2581
|
isSame,
|
|
2084
2582
|
setCode,
|
|
2085
2583
|
toCamelCase,
|
|
2584
|
+
toLowerCase,
|
|
2086
2585
|
}
|
|
2087
2586
|
|
|
2088
2587
|
|
|
@@ -2092,6 +2591,36 @@ const stringHelper = {
|
|
|
2092
2591
|
|
|
2093
2592
|
|
|
2094
2593
|
|
|
2594
|
+
;// ./lib/helpers/trackingPlugin/trackingPlugin.js
|
|
2595
|
+
function trackingPlugin(schema, options) {
|
|
2596
|
+
// Add meta fields
|
|
2597
|
+
schema.add({
|
|
2598
|
+
meta: {
|
|
2599
|
+
active: { type: Boolean, default: true },
|
|
2600
|
+
created: { type: Number },
|
|
2601
|
+
creator: { type: String },
|
|
2602
|
+
deleted: { type: Boolean, default: false },
|
|
2603
|
+
modified: { type: Number },
|
|
2604
|
+
owner: { type: String },
|
|
2605
|
+
}
|
|
2606
|
+
})
|
|
2607
|
+
|
|
2608
|
+
// Auto-update hook
|
|
2609
|
+
schema.pre('save', function(next) {
|
|
2610
|
+
this.meta.modified = Date.now()
|
|
2611
|
+
next()
|
|
2612
|
+
})
|
|
2613
|
+
|
|
2614
|
+
// Optional: Add helper methods
|
|
2615
|
+
// schema.methods.touch = function(userId) {
|
|
2616
|
+
// this.meta.updatedAt = new Date()
|
|
2617
|
+
// this.meta.updatedBy = userId
|
|
2618
|
+
// }
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
;// ./lib/helpers/trackingPlugin/index.js
|
|
2622
|
+
|
|
2623
|
+
|
|
2095
2624
|
;// ./lib/helpers/index.js
|
|
2096
2625
|
|
|
2097
2626
|
|
|
@@ -2104,6 +2633,15 @@ const stringHelper = {
|
|
|
2104
2633
|
|
|
2105
2634
|
|
|
2106
2635
|
|
|
2636
|
+
|
|
2637
|
+
|
|
2638
|
+
|
|
2639
|
+
|
|
2640
|
+
|
|
2641
|
+
|
|
2642
|
+
|
|
2643
|
+
|
|
2644
|
+
|
|
2107
2645
|
|
|
2108
2646
|
|
|
2109
2647
|
|
|
@@ -2114,6 +2652,196 @@ const stringHelper = {
|
|
|
2114
2652
|
|
|
2115
2653
|
|
|
2116
2654
|
|
|
2655
|
+
;// ./lib/models/awsStsS3Client/awsStsS3Client.js
|
|
2656
|
+
class AwsStsS3Client {
|
|
2657
|
+
constructor(options) {
|
|
2658
|
+
options = options || {}
|
|
2659
|
+
|
|
2660
|
+
this.expiration = options.expiration || null
|
|
2661
|
+
this.s3Client = options.s3Client || null
|
|
2662
|
+
this.getIdToken = options.getIdToken
|
|
2663
|
+
this.region = options.region || 'ap-east-1'
|
|
2664
|
+
this.roleArn = options.roleArn
|
|
2665
|
+
this.roleSessionName = options.roleSessionName || 'web-identity-session'
|
|
2666
|
+
this.durationSession = options.durationSession || 3600
|
|
2667
|
+
this.awsClientSts = options.awsClientSts
|
|
2668
|
+
this.awsClientS3 = options.awsClientS3
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
static dummyData() {
|
|
2672
|
+
return {
|
|
2673
|
+
getIdToken: () => 'mock-web-identity-token',
|
|
2674
|
+
roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
|
|
2675
|
+
awsClientSts: {
|
|
2676
|
+
STSClient: class {},
|
|
2677
|
+
AssumeRoleWithWebIdentityCommand: class {}
|
|
2678
|
+
},
|
|
2679
|
+
awsClientS3: {
|
|
2680
|
+
S3Client: class {},
|
|
2681
|
+
PutObjectCommand: class {},
|
|
2682
|
+
GetObjectCommand: class {},
|
|
2683
|
+
DeleteObjectCommand: class {}
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
static init(options = {}) {
|
|
2689
|
+
if (options instanceof this) {
|
|
2690
|
+
return options
|
|
2691
|
+
}
|
|
2692
|
+
try {
|
|
2693
|
+
const instance = new this(options)
|
|
2694
|
+
if (!instance.isValid) {
|
|
2695
|
+
return null
|
|
2696
|
+
}
|
|
2697
|
+
return instance
|
|
2698
|
+
} catch (error) {
|
|
2699
|
+
return null
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
get isExpired() {
|
|
2704
|
+
if (!this.expiration) return true;
|
|
2705
|
+
const now = new Date();
|
|
2706
|
+
const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
|
|
2707
|
+
return now >= new Date(this.expiration.getTime() - bufferMs);
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
get isValid() {
|
|
2711
|
+
if (!this.getIdToken) {
|
|
2712
|
+
throw new Error('Missing required configuration: getIdToken function')
|
|
2713
|
+
}
|
|
2714
|
+
if (!this.roleArn) {
|
|
2715
|
+
throw new Error('Missing required configuration: roleArn')
|
|
2716
|
+
}
|
|
2717
|
+
if (!this.awsClientSts) {
|
|
2718
|
+
throw new Error('Missing required AWS awsClientSts client configuration')
|
|
2719
|
+
}
|
|
2720
|
+
if (!this.awsClientSts.STSClient) {
|
|
2721
|
+
throw new Error('Missing STSClient in AWS awsClientSts client configuration')
|
|
2722
|
+
}
|
|
2723
|
+
if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
|
|
2724
|
+
throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
|
|
2725
|
+
}
|
|
2726
|
+
if (!this.awsClientS3) {
|
|
2727
|
+
throw new Error('Missing required AWS awsClientS3 client configuration')
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
const requiredS3Components = [
|
|
2731
|
+
'S3Client',
|
|
2732
|
+
'PutObjectCommand',
|
|
2733
|
+
'GetObjectCommand',
|
|
2734
|
+
'DeleteObjectCommand'
|
|
2735
|
+
]
|
|
2736
|
+
|
|
2737
|
+
for (const component of requiredS3Components) {
|
|
2738
|
+
if (!this.awsClientS3[component]) {
|
|
2739
|
+
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
return true
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
async refreshCredentials() {
|
|
2747
|
+
try {
|
|
2748
|
+
const webIdentityToken = await this.getIdToken()
|
|
2749
|
+
if (!webIdentityToken) {
|
|
2750
|
+
throw new Error('getIdToken function returned empty or invalid token')
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2754
|
+
|
|
2755
|
+
const stsResponse = await stsClient.send(
|
|
2756
|
+
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2757
|
+
RoleArn: this.roleArn,
|
|
2758
|
+
RoleSessionName: this.roleSessionName,
|
|
2759
|
+
WebIdentityToken: await this.getIdToken(),
|
|
2760
|
+
DurationSeconds: this.durationSession,
|
|
2761
|
+
})
|
|
2762
|
+
)
|
|
2763
|
+
|
|
2764
|
+
const credentials = stsResponse.Credentials
|
|
2765
|
+
if (!credentials) {
|
|
2766
|
+
throw new Error('No credentials returned from awsClientSts')
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
this.expiration = credentials.Expiration
|
|
2770
|
+
|
|
2771
|
+
this.s3Client = new this.awsClientS3.S3Client({
|
|
2772
|
+
region: this.region,
|
|
2773
|
+
credentials: {
|
|
2774
|
+
accessKeyId: credentials.AccessKeyId,
|
|
2775
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
2776
|
+
sessionToken: credentials.SessionToken,
|
|
2777
|
+
}
|
|
2778
|
+
})
|
|
2779
|
+
|
|
2780
|
+
return this
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
throw new Error(`Failed to refresh credentials: ${error.message}`)
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
async getS3Client() {
|
|
2787
|
+
if (this.isExpired || !this.s3Client) {
|
|
2788
|
+
await this.refreshCredentials()
|
|
2789
|
+
}
|
|
2790
|
+
return this.s3Client
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
async putObject(params) {
|
|
2794
|
+
try {
|
|
2795
|
+
const client = await this.getS3Client()
|
|
2796
|
+
const command = new this.awsClientS3.PutObjectCommand(params)
|
|
2797
|
+
await client.send(command)
|
|
2798
|
+
const fileArr = params.Key.split('/')
|
|
2799
|
+
return {
|
|
2800
|
+
url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
|
|
2801
|
+
filename: fileArr.pop(),
|
|
2802
|
+
folder: params.Bucket,
|
|
2803
|
+
subFolders: fileArr
|
|
2804
|
+
}
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
throw new Error(`Failed to put object: ${error.message}`)
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
async getObject(params) {
|
|
2811
|
+
try {
|
|
2812
|
+
const client = await this.getS3Client()
|
|
2813
|
+
const command = new this.awsClientS3.GetObjectCommand(params)
|
|
2814
|
+
const response = await client.send(command)
|
|
2815
|
+
return {
|
|
2816
|
+
body: response.Body,
|
|
2817
|
+
contentType: response.ContentType,
|
|
2818
|
+
lastModified: response.LastModified,
|
|
2819
|
+
contentLength: response.ContentLength,
|
|
2820
|
+
}
|
|
2821
|
+
} catch (error) {
|
|
2822
|
+
throw new Error(`Failed to get object: ${error.message}`)
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
async deleteObject(params) {
|
|
2827
|
+
try {
|
|
2828
|
+
const client = await this.getS3Client()
|
|
2829
|
+
const command = new this.awsClientS3.DeleteObjectCommand(params)
|
|
2830
|
+
await client.send(command)
|
|
2831
|
+
return true
|
|
2832
|
+
} catch (error) {
|
|
2833
|
+
throw new Error(`Failed to delete object: ${error.message}`)
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
|
|
2839
|
+
|
|
2840
|
+
;// ./lib/models/awsStsS3Client/index.js
|
|
2841
|
+
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
|
|
2117
2845
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2118
2846
|
class KeyValueObject {
|
|
2119
2847
|
constructor(options = {}) {
|
|
@@ -2241,7 +2969,7 @@ class KeyValueObject {
|
|
|
2241
2969
|
return to.key === from.key
|
|
2242
2970
|
})
|
|
2243
2971
|
if (found) {
|
|
2244
|
-
found.value = (
|
|
2972
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2245
2973
|
} else {
|
|
2246
2974
|
toArr.push(from)
|
|
2247
2975
|
}
|
|
@@ -2326,6 +3054,34 @@ class KeyValueObject {
|
|
|
2326
3054
|
}
|
|
2327
3055
|
}
|
|
2328
3056
|
|
|
3057
|
+
function _mergeValues(existingValue, newValue) {
|
|
3058
|
+
if (existingValue === undefined) return newValue
|
|
3059
|
+
|
|
3060
|
+
// Handle arrays by concatenating
|
|
3061
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3062
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// Handle objects by merging
|
|
3066
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3067
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3068
|
+
return { ...existingValue, ...newValue }
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
// // Handle numbers by adding
|
|
3072
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3073
|
+
// return existingValue
|
|
3074
|
+
// }
|
|
3075
|
+
|
|
3076
|
+
// // Handle strings by concatenating
|
|
3077
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3078
|
+
// return existingValue
|
|
3079
|
+
// }
|
|
3080
|
+
|
|
3081
|
+
// Default: use the new value
|
|
3082
|
+
return newValue
|
|
3083
|
+
}
|
|
3084
|
+
|
|
2329
3085
|
function _isSame(key1, key2) {
|
|
2330
3086
|
return key1 === key2
|
|
2331
3087
|
}
|
|
@@ -2364,7 +3120,7 @@ class Metadata extends KeyValueObject {
|
|
|
2364
3120
|
return metadata_isSame(to.key, from.key)
|
|
2365
3121
|
})
|
|
2366
3122
|
if (found) {
|
|
2367
|
-
found.value = (
|
|
3123
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2368
3124
|
} else {
|
|
2369
3125
|
toArr.push(from)
|
|
2370
3126
|
}
|
|
@@ -2380,6 +3136,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2380
3136
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2381
3137
|
}
|
|
2382
3138
|
|
|
3139
|
+
function metadata_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
|
+
|
|
2383
3167
|
|
|
2384
3168
|
|
|
2385
3169
|
;// ./lib/models/metadata/index.js
|
|
@@ -2448,21 +3232,12 @@ class QMeta {
|
|
|
2448
3232
|
|
|
2449
3233
|
|
|
2450
3234
|
|
|
2451
|
-
;// ./lib/models/repo/index.js
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
;// ./lib/models/service/index.js
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
3235
|
;// ./lib/models/trackedEntity/trackedEntity.js
|
|
2462
3236
|
|
|
2463
3237
|
|
|
2464
3238
|
class TrackedEntity {
|
|
2465
|
-
constructor(options = {}
|
|
3239
|
+
constructor(options = {}) {
|
|
3240
|
+
options = options || {}
|
|
2466
3241
|
const timestamp = Date.now()
|
|
2467
3242
|
const _tracking = {
|
|
2468
3243
|
active: options.active ?? true,
|
|
@@ -2473,11 +3248,13 @@ class TrackedEntity {
|
|
|
2473
3248
|
owner: options.owner ?? '',
|
|
2474
3249
|
}
|
|
2475
3250
|
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
}
|
|
3251
|
+
this.meta = { ..._tracking, ...options.meta }
|
|
3252
|
+
|
|
3253
|
+
// if (trackFlat) {
|
|
3254
|
+
// Object.assign(this, _tracking)
|
|
3255
|
+
// } else {
|
|
3256
|
+
// this.meta = { ..._tracking, ...options.meta }
|
|
3257
|
+
// }
|
|
2481
3258
|
}
|
|
2482
3259
|
|
|
2483
3260
|
// Class methods
|
|
@@ -2497,16 +3274,55 @@ class TrackedEntity {
|
|
|
2497
3274
|
static initOnlyValidFromArray(arr = []) {
|
|
2498
3275
|
return initOnlyValidFromArray(this, arr)
|
|
2499
3276
|
}
|
|
2500
|
-
static nest(entity) {
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
}
|
|
3277
|
+
// static nest(entity) {
|
|
3278
|
+
// const { active, created, creator, deleted, modified, owner, ...rest } = entity
|
|
3279
|
+
// return { ...rest, meta: { active, created, creator, deleted, modified, owner } }
|
|
3280
|
+
// }
|
|
2504
3281
|
|
|
2505
3282
|
// getters
|
|
2506
3283
|
get isValid() {
|
|
2507
3284
|
return !!this
|
|
2508
3285
|
}
|
|
2509
|
-
|
|
3286
|
+
get active() {
|
|
3287
|
+
return this.meta?.active ?? this.active
|
|
3288
|
+
}
|
|
3289
|
+
get created() {
|
|
3290
|
+
return this.meta?.created ?? this.created
|
|
3291
|
+
}
|
|
3292
|
+
get creator() {
|
|
3293
|
+
return this.meta?.creator ?? this.creator
|
|
3294
|
+
}
|
|
3295
|
+
get deleted() {
|
|
3296
|
+
return this.meta?.deleted ?? this.deleted
|
|
3297
|
+
}
|
|
3298
|
+
get modified() {
|
|
3299
|
+
return this.meta?.modified ?? this.modified
|
|
3300
|
+
}
|
|
3301
|
+
get owner() {
|
|
3302
|
+
return this.meta?.owner ?? this.owner
|
|
3303
|
+
}
|
|
3304
|
+
changeCreatorOwner({ source, target }) {
|
|
3305
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3306
|
+
}
|
|
3307
|
+
delete() {
|
|
3308
|
+
return this.setDeleted()
|
|
3309
|
+
}
|
|
3310
|
+
setActive() {
|
|
3311
|
+
if (this.meta) {
|
|
3312
|
+
this.meta.active = true
|
|
3313
|
+
} else {
|
|
3314
|
+
this.active = true
|
|
3315
|
+
}
|
|
3316
|
+
return this
|
|
3317
|
+
}
|
|
3318
|
+
setDeleted() {
|
|
3319
|
+
if (this.meta) {
|
|
3320
|
+
this.meta.deleted = true
|
|
3321
|
+
} else {
|
|
3322
|
+
this.deleted = true
|
|
3323
|
+
}
|
|
3324
|
+
return this
|
|
3325
|
+
}
|
|
2510
3326
|
setModified() {
|
|
2511
3327
|
const timestamp = Date.now()
|
|
2512
3328
|
if (this.meta) {
|
|
@@ -2514,6 +3330,41 @@ class TrackedEntity {
|
|
|
2514
3330
|
} else {
|
|
2515
3331
|
this.modified = timestamp
|
|
2516
3332
|
}
|
|
3333
|
+
return this
|
|
3334
|
+
}
|
|
3335
|
+
setOwner(owner) {
|
|
3336
|
+
if (!owner) {
|
|
3337
|
+
return this
|
|
3338
|
+
}
|
|
3339
|
+
if (this.meta) {
|
|
3340
|
+
this.meta.owner = owner
|
|
3341
|
+
} else {
|
|
3342
|
+
this.owner = owner
|
|
3343
|
+
}
|
|
3344
|
+
return this
|
|
3345
|
+
}
|
|
3346
|
+
unsetActive() {
|
|
3347
|
+
if (this.meta) {
|
|
3348
|
+
this.meta.active = false
|
|
3349
|
+
} else {
|
|
3350
|
+
this.active = false
|
|
3351
|
+
}
|
|
3352
|
+
return this
|
|
3353
|
+
}
|
|
3354
|
+
unsetDeleted() {
|
|
3355
|
+
if (this.meta) {
|
|
3356
|
+
this.meta.deleted = false
|
|
3357
|
+
} else {
|
|
3358
|
+
this.deleted = false
|
|
3359
|
+
}
|
|
3360
|
+
return this
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
update(update) {
|
|
3364
|
+
if (update.meta) {
|
|
3365
|
+
this.meta = { ...this.meta, ...update.meta }
|
|
3366
|
+
}
|
|
3367
|
+
return this.setModified()
|
|
2517
3368
|
}
|
|
2518
3369
|
}
|
|
2519
3370
|
|
|
@@ -2524,6 +3375,8 @@ class TrackedEntity {
|
|
|
2524
3375
|
;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
|
|
2525
3376
|
|
|
2526
3377
|
|
|
3378
|
+
|
|
3379
|
+
|
|
2527
3380
|
class TenantAwareEntity extends TrackedEntity {
|
|
2528
3381
|
constructor(options = {}) {
|
|
2529
3382
|
options = options || {}
|
|
@@ -2538,6 +3391,9 @@ class TenantAwareEntity extends TrackedEntity {
|
|
|
2538
3391
|
super(options)
|
|
2539
3392
|
|
|
2540
3393
|
this._tenant = options._tenant
|
|
3394
|
+
|
|
3395
|
+
this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
|
|
3396
|
+
this.remarks = KeyValueObject.initOnlyValidFromArray(options.remarks)
|
|
2541
3397
|
this.tenantCode = options.tenantCode // Required for multi-tenancy
|
|
2542
3398
|
}
|
|
2543
3399
|
|
|
@@ -2553,6 +3409,41 @@ class TenantAwareEntity extends TrackedEntity {
|
|
|
2553
3409
|
get isValid() {
|
|
2554
3410
|
return super.isValid && !!this.tenantCode // Required for multi-tenancy
|
|
2555
3411
|
}
|
|
3412
|
+
|
|
3413
|
+
// instance methods
|
|
3414
|
+
getMetadata() {
|
|
3415
|
+
return this.metadata
|
|
3416
|
+
}
|
|
3417
|
+
getMetadataByKey(key) {
|
|
3418
|
+
return Metadata.foundByKey(this.metadata, key)
|
|
3419
|
+
}
|
|
3420
|
+
getMetadataValueByKey(key) {
|
|
3421
|
+
const found = this.getMetadataByKey(key)
|
|
3422
|
+
return found ? found.value : null
|
|
3423
|
+
}
|
|
3424
|
+
getRemarks() {
|
|
3425
|
+
return this.remarks
|
|
3426
|
+
}
|
|
3427
|
+
getRemarkByKey(key) {
|
|
3428
|
+
return KeyValueObject.foundByKey(this.remarks, key)
|
|
3429
|
+
}
|
|
3430
|
+
getRemarksValueByKey(key) {
|
|
3431
|
+
const found = this.getRemarkByKey(key)
|
|
3432
|
+
return found ? found.value : null
|
|
3433
|
+
}
|
|
3434
|
+
getTenantCode() {
|
|
3435
|
+
return this.tenantCode
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3438
|
+
update(update) {
|
|
3439
|
+
if (update.metadata && Array.isArray(update.metadata)) {
|
|
3440
|
+
this.metadata = Metadata.initOnlyValidFromArray(update.metadata)
|
|
3441
|
+
}
|
|
3442
|
+
if (update.remarks && Array.isArray(update.remarks)) {
|
|
3443
|
+
this.remarks = KeyValueObject.initOnlyValidFromArray(update.remarks)
|
|
3444
|
+
}
|
|
3445
|
+
return super.update(update)
|
|
3446
|
+
}
|
|
2556
3447
|
}
|
|
2557
3448
|
|
|
2558
3449
|
;// ./lib/models/tenantAwareEntity/index.js
|
|
@@ -2619,6 +3510,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2619
3510
|
|
|
2620
3511
|
|
|
2621
3512
|
|
|
3513
|
+
|
|
2622
3514
|
;// ./lib/index.js
|
|
2623
3515
|
|
|
2624
3516
|
|