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