@questwork/q-utilities 0.1.14 → 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 +627 -9
- package/dist/q-utilities.esm.js +620 -10
- package/dist/q-utilities.min.js +627 -9
- package/package.json +5 -1
package/dist/q-utilities.esm.js
CHANGED
|
@@ -34,6 +34,29 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
34
34
|
;// ./lib/helpers/authorize/index.js
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
|
|
38
|
+
function changeCreatorOwner(that, { source, target }) {
|
|
39
|
+
if (that.meta) {
|
|
40
|
+
if (!that.meta.creator || that.meta.creator === source.getId()) {
|
|
41
|
+
that.meta.creator = target.getId()
|
|
42
|
+
}
|
|
43
|
+
if (!that.meta.owner || that.meta.owner === source.getId()) {
|
|
44
|
+
that.meta.owner = target.getId()
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
if (!that.creator || that.creator === source.getId()) {
|
|
48
|
+
that.creator = target.getId()
|
|
49
|
+
}
|
|
50
|
+
if (!that.owner || that.owner === source.getId()) {
|
|
51
|
+
that.owner = target.getId()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return that
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
58
|
+
|
|
59
|
+
|
|
37
60
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
38
61
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
39
62
|
if (!rule) {
|
|
@@ -42,10 +65,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
42
65
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
43
66
|
return false
|
|
44
67
|
}
|
|
45
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
68
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
46
69
|
const [valueAttribute] = Object.keys(value)
|
|
47
70
|
|
|
48
|
-
if (!key) {
|
|
71
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
49
72
|
switch (valueAttribute) {
|
|
50
73
|
case '$and': {
|
|
51
74
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -57,14 +80,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
57
80
|
return false
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
|
-
|
|
61
|
-
let rowValue = getDataByKey(key, data)
|
|
62
|
-
|
|
63
|
-
// debugger
|
|
83
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
64
84
|
|
|
65
85
|
// if KeyValue object
|
|
66
86
|
if (keyValuePath) {
|
|
67
|
-
console.log('keyValuePath', keyValuePath)
|
|
68
87
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
69
88
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
70
89
|
}
|
|
@@ -83,6 +102,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
83
102
|
case '$gte': {
|
|
84
103
|
return rowValue >= value['$gte']
|
|
85
104
|
}
|
|
105
|
+
case '$hasOverlap': {
|
|
106
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
107
|
+
}
|
|
86
108
|
case '$lt': {
|
|
87
109
|
return rowValue < value['$lt']
|
|
88
110
|
}
|
|
@@ -159,6 +181,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
159
181
|
default:
|
|
160
182
|
return false
|
|
161
183
|
}
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function _hasOverlap(item1, item2) {
|
|
188
|
+
let arr1 = item1
|
|
189
|
+
let arr2 = item2
|
|
190
|
+
if (typeof arr1 === 'string') {
|
|
191
|
+
arr1 = arr1.split(',')
|
|
192
|
+
}
|
|
193
|
+
if (typeof arr2 === 'string') {
|
|
194
|
+
arr2 = arr2.split(',')
|
|
195
|
+
}
|
|
196
|
+
const set1 = new Set(arr1)
|
|
197
|
+
return arr2.find((i) => (set1.has(i)))
|
|
162
198
|
}
|
|
163
199
|
|
|
164
200
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -1381,6 +1417,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1381
1417
|
;// ./lib/helpers/convertString/index.js
|
|
1382
1418
|
|
|
1383
1419
|
|
|
1420
|
+
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1421
|
+
function escapeRegex(string) {
|
|
1422
|
+
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
;// ./lib/helpers/escapeRegex/index.js
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
;// ./lib/helpers/expressHelper/customHandler.js
|
|
1429
|
+
function customHandler({ responseHelper, handler, ignoreError = false }) {
|
|
1430
|
+
return async (req, res, next) => {
|
|
1431
|
+
try {
|
|
1432
|
+
await handler({ req, res })
|
|
1433
|
+
await next()
|
|
1434
|
+
} catch (err) {
|
|
1435
|
+
if (ignoreError) {
|
|
1436
|
+
await next()
|
|
1437
|
+
} else {
|
|
1438
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
;// ./lib/helpers/expressHelper/findAllResult.js
|
|
1445
|
+
function findAllResult({ responseHelper, service }) {
|
|
1446
|
+
return async (req, res, next) => {
|
|
1447
|
+
try {
|
|
1448
|
+
const { query } = req
|
|
1449
|
+
const result = await service.findAll({ query })
|
|
1450
|
+
res.locals.findAllResult = result
|
|
1451
|
+
await next()
|
|
1452
|
+
} catch (err) {
|
|
1453
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
;// ./lib/helpers/expressHelper/findOneResult.js
|
|
1459
|
+
function findOneResult({ responseHelper, service }) {
|
|
1460
|
+
return async (req, res, next) => {
|
|
1461
|
+
try {
|
|
1462
|
+
const { params, query } = req
|
|
1463
|
+
const { id } = params
|
|
1464
|
+
const result = await service.findOne({
|
|
1465
|
+
query: {
|
|
1466
|
+
...query,
|
|
1467
|
+
id
|
|
1468
|
+
}
|
|
1469
|
+
})
|
|
1470
|
+
res.locals.findOneResult = result
|
|
1471
|
+
await next()
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
;// ./lib/helpers/expressHelper/postResult.js
|
|
1479
|
+
function postResult({ responseHelper, service }) {
|
|
1480
|
+
return async (req, res, next) => {
|
|
1481
|
+
try {
|
|
1482
|
+
const { body } = req
|
|
1483
|
+
let result
|
|
1484
|
+
if (Array.isArray(body)) {
|
|
1485
|
+
result = await service.saveAll({ docs: body })
|
|
1486
|
+
} else {
|
|
1487
|
+
result = await service.saveOne({ doc: body })
|
|
1488
|
+
}
|
|
1489
|
+
res.locals.postResult = result
|
|
1490
|
+
await next()
|
|
1491
|
+
} catch (err) {
|
|
1492
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
;// ./lib/helpers/expressHelper/updateOneResult.js
|
|
1498
|
+
function updateOneResult({ responseHelper, service }) {
|
|
1499
|
+
return async (req, res, next) => {
|
|
1500
|
+
try {
|
|
1501
|
+
const { body, params } = req
|
|
1502
|
+
const { id } = params
|
|
1503
|
+
if (id !== body.id) {
|
|
1504
|
+
throw new Error('id in params and body must be same')
|
|
1505
|
+
}
|
|
1506
|
+
const { data } = await service.findOne({ query: { id } })
|
|
1507
|
+
const doc = data[0]
|
|
1508
|
+
doc.update(body)
|
|
1509
|
+
const result = await service.saveOne({ doc })
|
|
1510
|
+
res.locals.updateOneResult = result
|
|
1511
|
+
await next()
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
;// ./lib/helpers/expressHelper/index.js
|
|
1519
|
+
|
|
1520
|
+
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
const expressHelper = {
|
|
1527
|
+
customHandler: customHandler,
|
|
1528
|
+
findAllResult: findAllResult,
|
|
1529
|
+
findOneResult: findOneResult,
|
|
1530
|
+
postResult: postResult,
|
|
1531
|
+
updateOneResult: updateOneResult,
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
;// ./lib/helpers/extractEmails/extractEmails.js
|
|
1535
|
+
/**
|
|
1536
|
+
* Extracts and normalizes unique email addresses from an array containing messy entries
|
|
1537
|
+
* @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
|
|
1538
|
+
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1539
|
+
*/
|
|
1540
|
+
function extractEmails(dirtyArray) {
|
|
1541
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
|
|
1542
|
+
const emails = new Set()
|
|
1543
|
+
|
|
1544
|
+
// Handle null/undefined input array
|
|
1545
|
+
if (!dirtyArray) return []
|
|
1546
|
+
|
|
1547
|
+
dirtyArray.forEach(entry => {
|
|
1548
|
+
// Skip null, undefined, empty, or whitespace-only entries
|
|
1549
|
+
if (!entry || typeof entry !== 'string' || !entry.trim()) return
|
|
1550
|
+
|
|
1551
|
+
try {
|
|
1552
|
+
const cleanEntry = entry
|
|
1553
|
+
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1554
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1555
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1556
|
+
.trim()
|
|
1557
|
+
|
|
1558
|
+
// Extract all email matches
|
|
1559
|
+
const matches = cleanEntry.match(emailRegex)
|
|
1560
|
+
if (matches) {
|
|
1561
|
+
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1562
|
+
}
|
|
1563
|
+
} catch (e) {
|
|
1564
|
+
console.warn('Failed to process entry:', entry, e)
|
|
1565
|
+
}
|
|
1566
|
+
})
|
|
1567
|
+
|
|
1568
|
+
// Convert Set to array and sort alphabetically
|
|
1569
|
+
return Array.from(emails).sort((a, b) => a.localeCompare(b))
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
;// ./lib/helpers/extractEmails/index.js
|
|
1573
|
+
|
|
1574
|
+
|
|
1384
1575
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1385
1576
|
const objectHelper = {
|
|
1386
1577
|
get(obj, path) {
|
|
@@ -1992,6 +2183,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
1992
2183
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
1993
2184
|
|
|
1994
2185
|
|
|
2186
|
+
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2187
|
+
function mergeArraysByKey(arr1, arr2) {
|
|
2188
|
+
// Handle undefined/null inputs by defaulting to empty arrays
|
|
2189
|
+
const safeArr1 = Array.isArray(arr1) ? arr1 : []
|
|
2190
|
+
const safeArr2 = Array.isArray(arr2) ? arr2 : []
|
|
2191
|
+
|
|
2192
|
+
const mergedMap = new Map()
|
|
2193
|
+
|
|
2194
|
+
// Helper function to merge values based on their type
|
|
2195
|
+
const mergeValues = (existingValue, newValue) => {
|
|
2196
|
+
if (existingValue === undefined) return newValue
|
|
2197
|
+
|
|
2198
|
+
// Handle arrays by concatenating
|
|
2199
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2200
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
// Handle objects by merging
|
|
2204
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2205
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2206
|
+
return { ...existingValue, ...newValue }
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
// // Handle numbers by adding
|
|
2210
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2211
|
+
// return existingValue
|
|
2212
|
+
// }
|
|
2213
|
+
|
|
2214
|
+
// // Handle strings by concatenating
|
|
2215
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2216
|
+
// return existingValue
|
|
2217
|
+
// }
|
|
2218
|
+
|
|
2219
|
+
// Default: use the new value
|
|
2220
|
+
return newValue
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
// Process first array
|
|
2224
|
+
safeArr1.forEach(item => {
|
|
2225
|
+
mergedMap.set(item.key, item.value)
|
|
2226
|
+
})
|
|
2227
|
+
|
|
2228
|
+
// Process second array and merge values
|
|
2229
|
+
safeArr2.forEach(item => {
|
|
2230
|
+
const existingValue = mergedMap.get(item.key)
|
|
2231
|
+
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2232
|
+
})
|
|
2233
|
+
|
|
2234
|
+
// Convert back to array format
|
|
2235
|
+
return Array.from(mergedMap.entries()).map(([key, value]) => ({
|
|
2236
|
+
key,
|
|
2237
|
+
value
|
|
2238
|
+
}))
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
;// ./lib/helpers/mergeArraysByKey/index.js
|
|
2242
|
+
|
|
2243
|
+
|
|
1995
2244
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
1996
2245
|
function padZeros(num, minLength = 6) {
|
|
1997
2246
|
num = num.toString()
|
|
@@ -2013,6 +2262,102 @@ function padZeros(num, minLength = 6) {
|
|
|
2013
2262
|
|
|
2014
2263
|
|
|
2015
2264
|
|
|
2265
|
+
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2266
|
+
function replacePlaceholders({ content, mapping }) {
|
|
2267
|
+
let isObjectMode = false
|
|
2268
|
+
|
|
2269
|
+
if (typeof content === 'object' && content !== null) {
|
|
2270
|
+
content = JSON.stringify(content)
|
|
2271
|
+
isObjectMode = true
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2275
|
+
const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
|
|
2276
|
+
|
|
2277
|
+
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2278
|
+
|
|
2279
|
+
// Split the path into parts
|
|
2280
|
+
const keys = path.trim().split('.')
|
|
2281
|
+
|
|
2282
|
+
// Traverse the nested object structure
|
|
2283
|
+
let value = mapping
|
|
2284
|
+
for (const key of keys) {
|
|
2285
|
+
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2286
|
+
if (!key) continue
|
|
2287
|
+
|
|
2288
|
+
value = value?.[key]
|
|
2289
|
+
if (value === undefined) {
|
|
2290
|
+
break
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// Apply default if missing
|
|
2295
|
+
if (value === undefined) value = defaultValue?.trim();
|
|
2296
|
+
if (value === undefined) return isObjectMode ? undefined : match;
|
|
2297
|
+
|
|
2298
|
+
value = value !== undefined
|
|
2299
|
+
? leadingBrackets + value + trailingBrackets
|
|
2300
|
+
: match
|
|
2301
|
+
|
|
2302
|
+
// Return replacement or original if not found
|
|
2303
|
+
return value
|
|
2304
|
+
})
|
|
2305
|
+
|
|
2306
|
+
if (isObjectMode) {
|
|
2307
|
+
return JSON.parse(result)
|
|
2308
|
+
}
|
|
2309
|
+
return result
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
;// ./lib/helpers/replacePlaceholders/index.js
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
;// ./lib/helpers/sanitizeText/sanitizeText.js
|
|
2316
|
+
/**
|
|
2317
|
+
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2318
|
+
* @param {string} input - The string to sanitize.
|
|
2319
|
+
* @param {Object} [options] - Configuration options.
|
|
2320
|
+
* @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
|
|
2321
|
+
* @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
|
|
2322
|
+
* @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
|
|
2323
|
+
* @returns {string} The sanitized string.
|
|
2324
|
+
*/
|
|
2325
|
+
function sanitizeText(input, options = {}) {
|
|
2326
|
+
const {
|
|
2327
|
+
normalizeWhitespace = true,
|
|
2328
|
+
removeNewlines = false,
|
|
2329
|
+
trim = true,
|
|
2330
|
+
} = options
|
|
2331
|
+
|
|
2332
|
+
if (typeof input !== 'string') {
|
|
2333
|
+
return input
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
let result = input
|
|
2337
|
+
|
|
2338
|
+
// Phase 1: Remove hidden/control characters
|
|
2339
|
+
result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2340
|
+
|
|
2341
|
+
// Phase 2: Handle whitespace transformations
|
|
2342
|
+
if (removeNewlines) {
|
|
2343
|
+
result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
if (normalizeWhitespace) {
|
|
2347
|
+
result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
// Phase 3: Final trimming
|
|
2351
|
+
if (trim) {
|
|
2352
|
+
result = result.trim()
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
return result
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
;// ./lib/helpers/sanitizeText/index.js
|
|
2359
|
+
|
|
2360
|
+
|
|
2016
2361
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
2017
2362
|
function stringFormatter(str, delimiter = '_') {
|
|
2018
2363
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2138,10 +2483,18 @@ function toCamelCase(str) {
|
|
|
2138
2483
|
.join('')
|
|
2139
2484
|
}
|
|
2140
2485
|
|
|
2486
|
+
function toLowerCase(str) {
|
|
2487
|
+
if (!str) return ''
|
|
2488
|
+
return str
|
|
2489
|
+
.trim()
|
|
2490
|
+
.toLowerCase()
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2141
2493
|
const stringHelper = {
|
|
2142
2494
|
isSame,
|
|
2143
2495
|
setCode,
|
|
2144
2496
|
toCamelCase,
|
|
2497
|
+
toLowerCase,
|
|
2145
2498
|
}
|
|
2146
2499
|
|
|
2147
2500
|
|
|
@@ -2195,6 +2548,13 @@ function trackingPlugin(schema, options) {
|
|
|
2195
2548
|
|
|
2196
2549
|
|
|
2197
2550
|
|
|
2551
|
+
|
|
2552
|
+
|
|
2553
|
+
|
|
2554
|
+
|
|
2555
|
+
|
|
2556
|
+
|
|
2557
|
+
|
|
2198
2558
|
|
|
2199
2559
|
|
|
2200
2560
|
|
|
@@ -2205,6 +2565,196 @@ function trackingPlugin(schema, options) {
|
|
|
2205
2565
|
|
|
2206
2566
|
|
|
2207
2567
|
|
|
2568
|
+
;// ./lib/models/awsStsS3Client/awsStsS3Client.js
|
|
2569
|
+
class AwsStsS3Client {
|
|
2570
|
+
constructor(options) {
|
|
2571
|
+
options = options || {}
|
|
2572
|
+
|
|
2573
|
+
this.expiration = options.expiration || null
|
|
2574
|
+
this.s3Client = options.s3Client || null
|
|
2575
|
+
this.getIdToken = options.getIdToken
|
|
2576
|
+
this.region = options.region || 'ap-east-1'
|
|
2577
|
+
this.roleArn = options.roleArn
|
|
2578
|
+
this.roleSessionName = options.roleSessionName || 'web-identity-session'
|
|
2579
|
+
this.durationSession = options.durationSession || 3600
|
|
2580
|
+
this.awsClientSts = options.awsClientSts
|
|
2581
|
+
this.awsClientS3 = options.awsClientS3
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
static dummyData() {
|
|
2585
|
+
return {
|
|
2586
|
+
getIdToken: () => 'mock-web-identity-token',
|
|
2587
|
+
roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
|
|
2588
|
+
awsClientSts: {
|
|
2589
|
+
STSClient: class {},
|
|
2590
|
+
AssumeRoleWithWebIdentityCommand: class {}
|
|
2591
|
+
},
|
|
2592
|
+
awsClientS3: {
|
|
2593
|
+
S3Client: class {},
|
|
2594
|
+
PutObjectCommand: class {},
|
|
2595
|
+
GetObjectCommand: class {},
|
|
2596
|
+
DeleteObjectCommand: class {}
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
static init(options = {}) {
|
|
2602
|
+
if (options instanceof this) {
|
|
2603
|
+
return options
|
|
2604
|
+
}
|
|
2605
|
+
try {
|
|
2606
|
+
const instance = new this(options)
|
|
2607
|
+
if (!instance.isValid) {
|
|
2608
|
+
return null
|
|
2609
|
+
}
|
|
2610
|
+
return instance
|
|
2611
|
+
} catch (error) {
|
|
2612
|
+
return null
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
get isExpired() {
|
|
2617
|
+
if (!this.expiration) return true;
|
|
2618
|
+
const now = new Date();
|
|
2619
|
+
const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
|
|
2620
|
+
return now >= new Date(this.expiration.getTime() - bufferMs);
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
get isValid() {
|
|
2624
|
+
if (!this.getIdToken) {
|
|
2625
|
+
throw new Error('Missing required configuration: getIdToken function')
|
|
2626
|
+
}
|
|
2627
|
+
if (!this.roleArn) {
|
|
2628
|
+
throw new Error('Missing required configuration: roleArn')
|
|
2629
|
+
}
|
|
2630
|
+
if (!this.awsClientSts) {
|
|
2631
|
+
throw new Error('Missing required AWS awsClientSts client configuration')
|
|
2632
|
+
}
|
|
2633
|
+
if (!this.awsClientSts.STSClient) {
|
|
2634
|
+
throw new Error('Missing STSClient in AWS awsClientSts client configuration')
|
|
2635
|
+
}
|
|
2636
|
+
if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
|
|
2637
|
+
throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
|
|
2638
|
+
}
|
|
2639
|
+
if (!this.awsClientS3) {
|
|
2640
|
+
throw new Error('Missing required AWS awsClientS3 client configuration')
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
const requiredS3Components = [
|
|
2644
|
+
'S3Client',
|
|
2645
|
+
'PutObjectCommand',
|
|
2646
|
+
'GetObjectCommand',
|
|
2647
|
+
'DeleteObjectCommand'
|
|
2648
|
+
]
|
|
2649
|
+
|
|
2650
|
+
for (const component of requiredS3Components) {
|
|
2651
|
+
if (!this.awsClientS3[component]) {
|
|
2652
|
+
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
return true
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
async refreshCredentials() {
|
|
2660
|
+
try {
|
|
2661
|
+
const webIdentityToken = await this.getIdToken()
|
|
2662
|
+
if (!webIdentityToken) {
|
|
2663
|
+
throw new Error('getIdToken function returned empty or invalid token')
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2667
|
+
|
|
2668
|
+
const stsResponse = await stsClient.send(
|
|
2669
|
+
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2670
|
+
RoleArn: this.roleArn,
|
|
2671
|
+
RoleSessionName: this.roleSessionName,
|
|
2672
|
+
WebIdentityToken: await this.getIdToken(),
|
|
2673
|
+
DurationSeconds: this.durationSession,
|
|
2674
|
+
})
|
|
2675
|
+
)
|
|
2676
|
+
|
|
2677
|
+
const credentials = stsResponse.Credentials
|
|
2678
|
+
if (!credentials) {
|
|
2679
|
+
throw new Error('No credentials returned from awsClientSts')
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
this.expiration = credentials.Expiration
|
|
2683
|
+
|
|
2684
|
+
this.s3Client = new this.awsClientS3.S3Client({
|
|
2685
|
+
region: this.region,
|
|
2686
|
+
credentials: {
|
|
2687
|
+
accessKeyId: credentials.AccessKeyId,
|
|
2688
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
2689
|
+
sessionToken: credentials.SessionToken,
|
|
2690
|
+
}
|
|
2691
|
+
})
|
|
2692
|
+
|
|
2693
|
+
return this
|
|
2694
|
+
} catch (error) {
|
|
2695
|
+
throw new Error(`Failed to refresh credentials: ${error.message}`)
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
async getS3Client() {
|
|
2700
|
+
if (this.isExpired || !this.s3Client) {
|
|
2701
|
+
await this.refreshCredentials()
|
|
2702
|
+
}
|
|
2703
|
+
return this.s3Client
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
async putObject(params) {
|
|
2707
|
+
try {
|
|
2708
|
+
const client = await this.getS3Client()
|
|
2709
|
+
const command = new this.awsClientS3.PutObjectCommand(params)
|
|
2710
|
+
await client.send(command)
|
|
2711
|
+
const fileArr = params.Key.split('/')
|
|
2712
|
+
return {
|
|
2713
|
+
url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
|
|
2714
|
+
filename: fileArr.pop(),
|
|
2715
|
+
folder: params.Bucket,
|
|
2716
|
+
subFolders: fileArr
|
|
2717
|
+
}
|
|
2718
|
+
} catch (error) {
|
|
2719
|
+
throw new Error(`Failed to put object: ${error.message}`)
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
async getObject(params) {
|
|
2724
|
+
try {
|
|
2725
|
+
const client = await this.getS3Client()
|
|
2726
|
+
const command = new this.awsClientS3.GetObjectCommand(params)
|
|
2727
|
+
const response = await client.send(command)
|
|
2728
|
+
return {
|
|
2729
|
+
body: response.Body,
|
|
2730
|
+
contentType: response.ContentType,
|
|
2731
|
+
lastModified: response.LastModified,
|
|
2732
|
+
contentLength: response.ContentLength,
|
|
2733
|
+
}
|
|
2734
|
+
} catch (error) {
|
|
2735
|
+
throw new Error(`Failed to get object: ${error.message}`)
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
async deleteObject(params) {
|
|
2740
|
+
try {
|
|
2741
|
+
const client = await this.getS3Client()
|
|
2742
|
+
const command = new this.awsClientS3.DeleteObjectCommand(params)
|
|
2743
|
+
await client.send(command)
|
|
2744
|
+
return true
|
|
2745
|
+
} catch (error) {
|
|
2746
|
+
throw new Error(`Failed to delete object: ${error.message}`)
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
|
|
2752
|
+
|
|
2753
|
+
;// ./lib/models/awsStsS3Client/index.js
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
|
|
2757
|
+
|
|
2208
2758
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2209
2759
|
class KeyValueObject {
|
|
2210
2760
|
constructor(options = {}) {
|
|
@@ -2332,7 +2882,7 @@ class KeyValueObject {
|
|
|
2332
2882
|
return to.key === from.key
|
|
2333
2883
|
})
|
|
2334
2884
|
if (found) {
|
|
2335
|
-
found.value = (
|
|
2885
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2336
2886
|
} else {
|
|
2337
2887
|
toArr.push(from)
|
|
2338
2888
|
}
|
|
@@ -2417,6 +2967,34 @@ class KeyValueObject {
|
|
|
2417
2967
|
}
|
|
2418
2968
|
}
|
|
2419
2969
|
|
|
2970
|
+
function _mergeValues(existingValue, newValue) {
|
|
2971
|
+
if (existingValue === undefined) return newValue
|
|
2972
|
+
|
|
2973
|
+
// Handle arrays by concatenating
|
|
2974
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2975
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
// Handle objects by merging
|
|
2979
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2980
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2981
|
+
return { ...existingValue, ...newValue }
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
// // Handle numbers by adding
|
|
2985
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2986
|
+
// return existingValue
|
|
2987
|
+
// }
|
|
2988
|
+
|
|
2989
|
+
// // Handle strings by concatenating
|
|
2990
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2991
|
+
// return existingValue
|
|
2992
|
+
// }
|
|
2993
|
+
|
|
2994
|
+
// Default: use the new value
|
|
2995
|
+
return newValue
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2420
2998
|
function _isSame(key1, key2) {
|
|
2421
2999
|
return key1 === key2
|
|
2422
3000
|
}
|
|
@@ -2455,7 +3033,7 @@ class Metadata extends KeyValueObject {
|
|
|
2455
3033
|
return metadata_isSame(to.key, from.key)
|
|
2456
3034
|
})
|
|
2457
3035
|
if (found) {
|
|
2458
|
-
found.value = (
|
|
3036
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2459
3037
|
} else {
|
|
2460
3038
|
toArr.push(from)
|
|
2461
3039
|
}
|
|
@@ -2471,6 +3049,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2471
3049
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2472
3050
|
}
|
|
2473
3051
|
|
|
3052
|
+
function metadata_mergeValues(existingValue, newValue) {
|
|
3053
|
+
if (existingValue === undefined) return newValue
|
|
3054
|
+
|
|
3055
|
+
// Handle arrays by concatenating
|
|
3056
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3057
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// Handle objects by merging
|
|
3061
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3062
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3063
|
+
return { ...existingValue, ...newValue }
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
// // Handle numbers by adding
|
|
3067
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3068
|
+
// return existingValue
|
|
3069
|
+
// }
|
|
3070
|
+
|
|
3071
|
+
// // Handle strings by concatenating
|
|
3072
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3073
|
+
// return existingValue
|
|
3074
|
+
// }
|
|
3075
|
+
|
|
3076
|
+
// Default: use the new value
|
|
3077
|
+
return newValue
|
|
3078
|
+
}
|
|
3079
|
+
|
|
2474
3080
|
|
|
2475
3081
|
|
|
2476
3082
|
;// ./lib/models/metadata/index.js
|
|
@@ -2608,6 +3214,9 @@ class TrackedEntity {
|
|
|
2608
3214
|
get owner() {
|
|
2609
3215
|
return this.meta?.owner ?? this.owner
|
|
2610
3216
|
}
|
|
3217
|
+
changeCreatorOwner({ source, target }) {
|
|
3218
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3219
|
+
}
|
|
2611
3220
|
delete() {
|
|
2612
3221
|
return this.setDeleted()
|
|
2613
3222
|
}
|
|
@@ -2814,6 +3423,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2814
3423
|
|
|
2815
3424
|
|
|
2816
3425
|
|
|
3426
|
+
|
|
2817
3427
|
;// ./lib/index.js
|
|
2818
3428
|
|
|
2819
3429
|
|
|
@@ -2821,4 +3431,4 @@ function _makeSetCode(fieldName, options) {
|
|
|
2821
3431
|
;// ./index.js
|
|
2822
3432
|
|
|
2823
3433
|
|
|
2824
|
-
export { ApiResponse, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, concatStringByArray, convertString, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, objectHelper, pReduce, padZeros, stringFormatter, stringHelper, trackingPlugin };
|
|
3434
|
+
export { ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, stringFormatter, stringHelper, trackingPlugin };
|