@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/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),
|
|
@@ -60,8 +61,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
60
61
|
TrackedEntity: () => (/* reexport */ TrackedEntity),
|
|
61
62
|
UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
|
|
62
63
|
authorize: () => (/* reexport */ authorize),
|
|
64
|
+
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
63
65
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
64
66
|
convertString: () => (/* reexport */ convertString),
|
|
67
|
+
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
68
|
+
expressHelper: () => (/* reexport */ expressHelper),
|
|
69
|
+
extractEmails: () => (/* reexport */ extractEmails),
|
|
65
70
|
formatDate: () => (/* reexport */ formatDate),
|
|
66
71
|
generalPost: () => (/* reexport */ generalPost),
|
|
67
72
|
getValidation: () => (/* reexport */ getValidation),
|
|
@@ -71,9 +76,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
71
76
|
initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
|
|
72
77
|
makeApiResponse: () => (/* reexport */ makeApiResponse),
|
|
73
78
|
makeService: () => (/* reexport */ makeService),
|
|
79
|
+
mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
|
|
74
80
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
75
81
|
pReduce: () => (/* reexport */ pReduce),
|
|
76
82
|
padZeros: () => (/* reexport */ padZeros),
|
|
83
|
+
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
84
|
+
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
77
85
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
78
86
|
stringHelper: () => (/* reexport */ stringHelper),
|
|
79
87
|
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
@@ -114,6 +122,29 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
114
122
|
;// ./lib/helpers/authorize/index.js
|
|
115
123
|
|
|
116
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
|
+
|
|
117
148
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
118
149
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
119
150
|
if (!rule) {
|
|
@@ -122,10 +153,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
122
153
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
123
154
|
return false
|
|
124
155
|
}
|
|
125
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
156
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
126
157
|
const [valueAttribute] = Object.keys(value)
|
|
127
158
|
|
|
128
|
-
if (!key) {
|
|
159
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
129
160
|
switch (valueAttribute) {
|
|
130
161
|
case '$and': {
|
|
131
162
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -137,14 +168,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
137
168
|
return false
|
|
138
169
|
}
|
|
139
170
|
}
|
|
140
|
-
|
|
141
|
-
let rowValue = getDataByKey(key, data)
|
|
142
|
-
|
|
143
|
-
// debugger
|
|
171
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
144
172
|
|
|
145
173
|
// if KeyValue object
|
|
146
174
|
if (keyValuePath) {
|
|
147
|
-
console.log('keyValuePath', keyValuePath)
|
|
148
175
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
149
176
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
150
177
|
}
|
|
@@ -163,6 +190,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
163
190
|
case '$gte': {
|
|
164
191
|
return rowValue >= value['$gte']
|
|
165
192
|
}
|
|
193
|
+
case '$hasOverlap': {
|
|
194
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
195
|
+
}
|
|
166
196
|
case '$lt': {
|
|
167
197
|
return rowValue < value['$lt']
|
|
168
198
|
}
|
|
@@ -239,6 +269,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
239
269
|
default:
|
|
240
270
|
return false
|
|
241
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)))
|
|
242
286
|
}
|
|
243
287
|
|
|
244
288
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -1461,6 +1505,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1461
1505
|
;// ./lib/helpers/convertString/index.js
|
|
1462
1506
|
|
|
1463
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
|
+
|
|
1464
1663
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1465
1664
|
const objectHelper = {
|
|
1466
1665
|
get(obj, path) {
|
|
@@ -2072,6 +2271,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
2072
2271
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
2073
2272
|
|
|
2074
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
|
+
|
|
2075
2332
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
2076
2333
|
function padZeros(num, minLength = 6) {
|
|
2077
2334
|
num = num.toString()
|
|
@@ -2093,6 +2350,102 @@ function padZeros(num, minLength = 6) {
|
|
|
2093
2350
|
|
|
2094
2351
|
|
|
2095
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
|
+
|
|
2096
2449
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
2097
2450
|
function stringFormatter(str, delimiter = '_') {
|
|
2098
2451
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2218,10 +2571,18 @@ function toCamelCase(str) {
|
|
|
2218
2571
|
.join('')
|
|
2219
2572
|
}
|
|
2220
2573
|
|
|
2574
|
+
function toLowerCase(str) {
|
|
2575
|
+
if (!str) return ''
|
|
2576
|
+
return str
|
|
2577
|
+
.trim()
|
|
2578
|
+
.toLowerCase()
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2221
2581
|
const stringHelper = {
|
|
2222
2582
|
isSame,
|
|
2223
2583
|
setCode,
|
|
2224
2584
|
toCamelCase,
|
|
2585
|
+
toLowerCase,
|
|
2225
2586
|
}
|
|
2226
2587
|
|
|
2227
2588
|
|
|
@@ -2275,6 +2636,13 @@ function trackingPlugin(schema, options) {
|
|
|
2275
2636
|
|
|
2276
2637
|
|
|
2277
2638
|
|
|
2639
|
+
|
|
2640
|
+
|
|
2641
|
+
|
|
2642
|
+
|
|
2643
|
+
|
|
2644
|
+
|
|
2645
|
+
|
|
2278
2646
|
|
|
2279
2647
|
|
|
2280
2648
|
|
|
@@ -2285,6 +2653,196 @@ function trackingPlugin(schema, options) {
|
|
|
2285
2653
|
|
|
2286
2654
|
|
|
2287
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
|
+
|
|
2288
2846
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2289
2847
|
class KeyValueObject {
|
|
2290
2848
|
constructor(options = {}) {
|
|
@@ -2412,7 +2970,7 @@ class KeyValueObject {
|
|
|
2412
2970
|
return to.key === from.key
|
|
2413
2971
|
})
|
|
2414
2972
|
if (found) {
|
|
2415
|
-
found.value = (
|
|
2973
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2416
2974
|
} else {
|
|
2417
2975
|
toArr.push(from)
|
|
2418
2976
|
}
|
|
@@ -2497,6 +3055,34 @@ class KeyValueObject {
|
|
|
2497
3055
|
}
|
|
2498
3056
|
}
|
|
2499
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
|
+
|
|
2500
3086
|
function _isSame(key1, key2) {
|
|
2501
3087
|
return key1 === key2
|
|
2502
3088
|
}
|
|
@@ -2535,7 +3121,7 @@ class Metadata extends KeyValueObject {
|
|
|
2535
3121
|
return metadata_isSame(to.key, from.key)
|
|
2536
3122
|
})
|
|
2537
3123
|
if (found) {
|
|
2538
|
-
found.value = (
|
|
3124
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2539
3125
|
} else {
|
|
2540
3126
|
toArr.push(from)
|
|
2541
3127
|
}
|
|
@@ -2551,6 +3137,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2551
3137
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2552
3138
|
}
|
|
2553
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
|
+
|
|
2554
3168
|
|
|
2555
3169
|
|
|
2556
3170
|
;// ./lib/models/metadata/index.js
|
|
@@ -2688,6 +3302,9 @@ class TrackedEntity {
|
|
|
2688
3302
|
get owner() {
|
|
2689
3303
|
return this.meta?.owner ?? this.owner
|
|
2690
3304
|
}
|
|
3305
|
+
changeCreatorOwner({ source, target }) {
|
|
3306
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3307
|
+
}
|
|
2691
3308
|
delete() {
|
|
2692
3309
|
return this.setDeleted()
|
|
2693
3310
|
}
|
|
@@ -2894,6 +3511,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2894
3511
|
|
|
2895
3512
|
|
|
2896
3513
|
|
|
3514
|
+
|
|
2897
3515
|
;// ./lib/index.js
|
|
2898
3516
|
|
|
2899
3517
|
|