@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.min.js
CHANGED
|
@@ -49,6 +49,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
49
49
|
// EXPORTS
|
|
50
50
|
__webpack_require__.d(__webpack_exports__, {
|
|
51
51
|
ApiResponse: () => (/* reexport */ ApiResponse),
|
|
52
|
+
AwsStsS3Client: () => (/* reexport */ AwsStsS3Client),
|
|
52
53
|
KeyValueObject: () => (/* reexport */ KeyValueObject),
|
|
53
54
|
Metadata: () => (/* reexport */ Metadata),
|
|
54
55
|
QMeta: () => (/* reexport */ QMeta),
|
|
@@ -59,8 +60,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
59
60
|
TrackedEntity: () => (/* reexport */ TrackedEntity),
|
|
60
61
|
UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
|
|
61
62
|
authorize: () => (/* reexport */ authorize),
|
|
63
|
+
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
62
64
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
63
65
|
convertString: () => (/* reexport */ convertString),
|
|
66
|
+
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
67
|
+
expressHelper: () => (/* reexport */ expressHelper),
|
|
68
|
+
extractEmails: () => (/* reexport */ extractEmails),
|
|
64
69
|
formatDate: () => (/* reexport */ formatDate),
|
|
65
70
|
generalPost: () => (/* reexport */ generalPost),
|
|
66
71
|
getValidation: () => (/* reexport */ getValidation),
|
|
@@ -70,9 +75,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
70
75
|
initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
|
|
71
76
|
makeApiResponse: () => (/* reexport */ makeApiResponse),
|
|
72
77
|
makeService: () => (/* reexport */ makeService),
|
|
78
|
+
mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
|
|
73
79
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
74
80
|
pReduce: () => (/* reexport */ pReduce),
|
|
75
81
|
padZeros: () => (/* reexport */ padZeros),
|
|
82
|
+
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
83
|
+
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
76
84
|
stringFormatter: () => (/* reexport */ stringFormatter),
|
|
77
85
|
stringHelper: () => (/* reexport */ stringHelper),
|
|
78
86
|
trackingPlugin: () => (/* reexport */ trackingPlugin)
|
|
@@ -113,6 +121,29 @@ function authorize({ allowOwner, query = {}, required, user }) {
|
|
|
113
121
|
;// ./lib/helpers/authorize/index.js
|
|
114
122
|
|
|
115
123
|
|
|
124
|
+
;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
|
|
125
|
+
function changeCreatorOwner(that, { source, target }) {
|
|
126
|
+
if (that.meta) {
|
|
127
|
+
if (!that.meta.creator || that.meta.creator === source.getId()) {
|
|
128
|
+
that.meta.creator = target.getId()
|
|
129
|
+
}
|
|
130
|
+
if (!that.meta.owner || that.meta.owner === source.getId()) {
|
|
131
|
+
that.meta.owner = target.getId()
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (!that.creator || that.creator === source.getId()) {
|
|
135
|
+
that.creator = target.getId()
|
|
136
|
+
}
|
|
137
|
+
if (!that.owner || that.owner === source.getId()) {
|
|
138
|
+
that.owner = target.getId()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return that
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
145
|
+
|
|
146
|
+
|
|
116
147
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
117
148
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
118
149
|
if (!rule) {
|
|
@@ -121,10 +152,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
121
152
|
if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
|
|
122
153
|
return false
|
|
123
154
|
}
|
|
124
|
-
const { key = '', value, keyValuePath = '' } = rule
|
|
155
|
+
const { key = '', value, placeholder, keyValuePath = '' } = rule
|
|
125
156
|
const [valueAttribute] = Object.keys(value)
|
|
126
157
|
|
|
127
|
-
if (!key) {
|
|
158
|
+
if (!key && typeof placeholder === 'undefined') {
|
|
128
159
|
switch (valueAttribute) {
|
|
129
160
|
case '$and': {
|
|
130
161
|
return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
@@ -136,14 +167,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
136
167
|
return false
|
|
137
168
|
}
|
|
138
169
|
}
|
|
139
|
-
|
|
140
|
-
let rowValue = getDataByKey(key, data)
|
|
141
|
-
|
|
142
|
-
// debugger
|
|
170
|
+
let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
|
|
143
171
|
|
|
144
172
|
// if KeyValue object
|
|
145
173
|
if (keyValuePath) {
|
|
146
|
-
console.log('keyValuePath', keyValuePath)
|
|
147
174
|
const rowValueData = KeyValueObject.toObject(rowValue)
|
|
148
175
|
rowValue = getDataByKey(keyValuePath, rowValueData)
|
|
149
176
|
}
|
|
@@ -162,6 +189,9 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
162
189
|
case '$gte': {
|
|
163
190
|
return rowValue >= value['$gte']
|
|
164
191
|
}
|
|
192
|
+
case '$hasOverlap': {
|
|
193
|
+
return _hasOverlap(rowValue, value['$hasOverlap'])
|
|
194
|
+
}
|
|
165
195
|
case '$lt': {
|
|
166
196
|
return rowValue < value['$lt']
|
|
167
197
|
}
|
|
@@ -238,6 +268,20 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
238
268
|
default:
|
|
239
269
|
return false
|
|
240
270
|
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function _hasOverlap(item1, item2) {
|
|
275
|
+
let arr1 = item1
|
|
276
|
+
let arr2 = item2
|
|
277
|
+
if (typeof arr1 === 'string') {
|
|
278
|
+
arr1 = arr1.split(',')
|
|
279
|
+
}
|
|
280
|
+
if (typeof arr2 === 'string') {
|
|
281
|
+
arr2 = arr2.split(',')
|
|
282
|
+
}
|
|
283
|
+
const set1 = new Set(arr1)
|
|
284
|
+
return arr2.find((i) => (set1.has(i)))
|
|
241
285
|
}
|
|
242
286
|
|
|
243
287
|
/* harmony default export */ const getValidation_getValidation = ({
|
|
@@ -1460,6 +1504,161 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1460
1504
|
;// ./lib/helpers/convertString/index.js
|
|
1461
1505
|
|
|
1462
1506
|
|
|
1507
|
+
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1508
|
+
function escapeRegex(string) {
|
|
1509
|
+
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
;// ./lib/helpers/escapeRegex/index.js
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
;// ./lib/helpers/expressHelper/customHandler.js
|
|
1516
|
+
function customHandler({ responseHelper, handler, ignoreError = false }) {
|
|
1517
|
+
return async (req, res, next) => {
|
|
1518
|
+
try {
|
|
1519
|
+
await handler({ req, res })
|
|
1520
|
+
await next()
|
|
1521
|
+
} catch (err) {
|
|
1522
|
+
if (ignoreError) {
|
|
1523
|
+
await next()
|
|
1524
|
+
} else {
|
|
1525
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
;// ./lib/helpers/expressHelper/findAllResult.js
|
|
1532
|
+
function findAllResult({ responseHelper, service }) {
|
|
1533
|
+
return async (req, res, next) => {
|
|
1534
|
+
try {
|
|
1535
|
+
const { query } = req
|
|
1536
|
+
const result = await service.findAll({ query })
|
|
1537
|
+
res.locals.findAllResult = result
|
|
1538
|
+
await next()
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
;// ./lib/helpers/expressHelper/findOneResult.js
|
|
1546
|
+
function findOneResult({ responseHelper, service }) {
|
|
1547
|
+
return async (req, res, next) => {
|
|
1548
|
+
try {
|
|
1549
|
+
const { params, query } = req
|
|
1550
|
+
const { id } = params
|
|
1551
|
+
const result = await service.findOne({
|
|
1552
|
+
query: {
|
|
1553
|
+
...query,
|
|
1554
|
+
id
|
|
1555
|
+
}
|
|
1556
|
+
})
|
|
1557
|
+
res.locals.findOneResult = result
|
|
1558
|
+
await next()
|
|
1559
|
+
} catch (err) {
|
|
1560
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
;// ./lib/helpers/expressHelper/postResult.js
|
|
1566
|
+
function postResult({ responseHelper, service }) {
|
|
1567
|
+
return async (req, res, next) => {
|
|
1568
|
+
try {
|
|
1569
|
+
const { body } = req
|
|
1570
|
+
let result
|
|
1571
|
+
if (Array.isArray(body)) {
|
|
1572
|
+
result = await service.saveAll({ docs: body })
|
|
1573
|
+
} else {
|
|
1574
|
+
result = await service.saveOne({ doc: body })
|
|
1575
|
+
}
|
|
1576
|
+
res.locals.postResult = result
|
|
1577
|
+
await next()
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
;// ./lib/helpers/expressHelper/updateOneResult.js
|
|
1585
|
+
function updateOneResult({ responseHelper, service }) {
|
|
1586
|
+
return async (req, res, next) => {
|
|
1587
|
+
try {
|
|
1588
|
+
const { body, params } = req
|
|
1589
|
+
const { id } = params
|
|
1590
|
+
if (id !== body.id) {
|
|
1591
|
+
throw new Error('id in params and body must be same')
|
|
1592
|
+
}
|
|
1593
|
+
const { data } = await service.findOne({ query: { id } })
|
|
1594
|
+
const doc = data[0]
|
|
1595
|
+
doc.update(body)
|
|
1596
|
+
const result = await service.saveOne({ doc })
|
|
1597
|
+
res.locals.updateOneResult = result
|
|
1598
|
+
await next()
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
;// ./lib/helpers/expressHelper/index.js
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
const expressHelper = {
|
|
1614
|
+
customHandler: customHandler,
|
|
1615
|
+
findAllResult: findAllResult,
|
|
1616
|
+
findOneResult: findOneResult,
|
|
1617
|
+
postResult: postResult,
|
|
1618
|
+
updateOneResult: updateOneResult,
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
;// ./lib/helpers/extractEmails/extractEmails.js
|
|
1622
|
+
/**
|
|
1623
|
+
* Extracts and normalizes unique email addresses from an array containing messy entries
|
|
1624
|
+
* @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
|
|
1625
|
+
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1626
|
+
*/
|
|
1627
|
+
function extractEmails(dirtyArray) {
|
|
1628
|
+
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
|
|
1629
|
+
const emails = new Set()
|
|
1630
|
+
|
|
1631
|
+
// Handle null/undefined input array
|
|
1632
|
+
if (!dirtyArray) return []
|
|
1633
|
+
|
|
1634
|
+
dirtyArray.forEach(entry => {
|
|
1635
|
+
// Skip null, undefined, empty, or whitespace-only entries
|
|
1636
|
+
if (!entry || typeof entry !== 'string' || !entry.trim()) return
|
|
1637
|
+
|
|
1638
|
+
try {
|
|
1639
|
+
const cleanEntry = entry
|
|
1640
|
+
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1641
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1642
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1643
|
+
.trim()
|
|
1644
|
+
|
|
1645
|
+
// Extract all email matches
|
|
1646
|
+
const matches = cleanEntry.match(emailRegex)
|
|
1647
|
+
if (matches) {
|
|
1648
|
+
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1649
|
+
}
|
|
1650
|
+
} catch (e) {
|
|
1651
|
+
console.warn('Failed to process entry:', entry, e)
|
|
1652
|
+
}
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
// Convert Set to array and sort alphabetically
|
|
1656
|
+
return Array.from(emails).sort((a, b) => a.localeCompare(b))
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
;// ./lib/helpers/extractEmails/index.js
|
|
1660
|
+
|
|
1661
|
+
|
|
1463
1662
|
;// ./lib/helpers/objectHelper/objectHelper.js
|
|
1464
1663
|
const objectHelper = {
|
|
1465
1664
|
get(obj, path) {
|
|
@@ -2071,6 +2270,64 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
2071
2270
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
2072
2271
|
|
|
2073
2272
|
|
|
2273
|
+
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2274
|
+
function mergeArraysByKey(arr1, arr2) {
|
|
2275
|
+
// Handle undefined/null inputs by defaulting to empty arrays
|
|
2276
|
+
const safeArr1 = Array.isArray(arr1) ? arr1 : []
|
|
2277
|
+
const safeArr2 = Array.isArray(arr2) ? arr2 : []
|
|
2278
|
+
|
|
2279
|
+
const mergedMap = new Map()
|
|
2280
|
+
|
|
2281
|
+
// Helper function to merge values based on their type
|
|
2282
|
+
const mergeValues = (existingValue, newValue) => {
|
|
2283
|
+
if (existingValue === undefined) return newValue
|
|
2284
|
+
|
|
2285
|
+
// Handle arrays by concatenating
|
|
2286
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2287
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
// Handle objects by merging
|
|
2291
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
2292
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2293
|
+
return { ...existingValue, ...newValue }
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// // Handle numbers by adding
|
|
2297
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2298
|
+
// return existingValue
|
|
2299
|
+
// }
|
|
2300
|
+
|
|
2301
|
+
// // Handle strings by concatenating
|
|
2302
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2303
|
+
// return existingValue
|
|
2304
|
+
// }
|
|
2305
|
+
|
|
2306
|
+
// Default: use the new value
|
|
2307
|
+
return newValue
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// Process first array
|
|
2311
|
+
safeArr1.forEach(item => {
|
|
2312
|
+
mergedMap.set(item.key, item.value)
|
|
2313
|
+
})
|
|
2314
|
+
|
|
2315
|
+
// Process second array and merge values
|
|
2316
|
+
safeArr2.forEach(item => {
|
|
2317
|
+
const existingValue = mergedMap.get(item.key)
|
|
2318
|
+
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2319
|
+
})
|
|
2320
|
+
|
|
2321
|
+
// Convert back to array format
|
|
2322
|
+
return Array.from(mergedMap.entries()).map(([key, value]) => ({
|
|
2323
|
+
key,
|
|
2324
|
+
value
|
|
2325
|
+
}))
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
;// ./lib/helpers/mergeArraysByKey/index.js
|
|
2329
|
+
|
|
2330
|
+
|
|
2074
2331
|
;// ./lib/helpers/padZeros/padZeros.js
|
|
2075
2332
|
function padZeros(num, minLength = 6) {
|
|
2076
2333
|
num = num.toString()
|
|
@@ -2092,6 +2349,102 @@ function padZeros(num, minLength = 6) {
|
|
|
2092
2349
|
|
|
2093
2350
|
|
|
2094
2351
|
|
|
2352
|
+
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2353
|
+
function replacePlaceholders({ content, mapping }) {
|
|
2354
|
+
let isObjectMode = false
|
|
2355
|
+
|
|
2356
|
+
if (typeof content === 'object' && content !== null) {
|
|
2357
|
+
content = JSON.stringify(content)
|
|
2358
|
+
isObjectMode = true
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2362
|
+
const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
|
|
2363
|
+
|
|
2364
|
+
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2365
|
+
|
|
2366
|
+
// Split the path into parts
|
|
2367
|
+
const keys = path.trim().split('.')
|
|
2368
|
+
|
|
2369
|
+
// Traverse the nested object structure
|
|
2370
|
+
let value = mapping
|
|
2371
|
+
for (const key of keys) {
|
|
2372
|
+
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2373
|
+
if (!key) continue
|
|
2374
|
+
|
|
2375
|
+
value = value?.[key]
|
|
2376
|
+
if (value === undefined) {
|
|
2377
|
+
break
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// Apply default if missing
|
|
2382
|
+
if (value === undefined) value = defaultValue?.trim();
|
|
2383
|
+
if (value === undefined) return isObjectMode ? undefined : match;
|
|
2384
|
+
|
|
2385
|
+
value = value !== undefined
|
|
2386
|
+
? leadingBrackets + value + trailingBrackets
|
|
2387
|
+
: match
|
|
2388
|
+
|
|
2389
|
+
// Return replacement or original if not found
|
|
2390
|
+
return value
|
|
2391
|
+
})
|
|
2392
|
+
|
|
2393
|
+
if (isObjectMode) {
|
|
2394
|
+
return JSON.parse(result)
|
|
2395
|
+
}
|
|
2396
|
+
return result
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
;// ./lib/helpers/replacePlaceholders/index.js
|
|
2400
|
+
|
|
2401
|
+
|
|
2402
|
+
;// ./lib/helpers/sanitizeText/sanitizeText.js
|
|
2403
|
+
/**
|
|
2404
|
+
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2405
|
+
* @param {string} input - The string to sanitize.
|
|
2406
|
+
* @param {Object} [options] - Configuration options.
|
|
2407
|
+
* @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
|
|
2408
|
+
* @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
|
|
2409
|
+
* @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
|
|
2410
|
+
* @returns {string} The sanitized string.
|
|
2411
|
+
*/
|
|
2412
|
+
function sanitizeText(input, options = {}) {
|
|
2413
|
+
const {
|
|
2414
|
+
normalizeWhitespace = true,
|
|
2415
|
+
removeNewlines = false,
|
|
2416
|
+
trim = true,
|
|
2417
|
+
} = options
|
|
2418
|
+
|
|
2419
|
+
if (typeof input !== 'string') {
|
|
2420
|
+
return input
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
let result = input
|
|
2424
|
+
|
|
2425
|
+
// Phase 1: Remove hidden/control characters
|
|
2426
|
+
result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2427
|
+
|
|
2428
|
+
// Phase 2: Handle whitespace transformations
|
|
2429
|
+
if (removeNewlines) {
|
|
2430
|
+
result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
if (normalizeWhitespace) {
|
|
2434
|
+
result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
// Phase 3: Final trimming
|
|
2438
|
+
if (trim) {
|
|
2439
|
+
result = result.trim()
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
return result
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
;// ./lib/helpers/sanitizeText/index.js
|
|
2446
|
+
|
|
2447
|
+
|
|
2095
2448
|
;// ./lib/helpers/stringFormatter/stringFormatter.js
|
|
2096
2449
|
function stringFormatter(str, delimiter = '_') {
|
|
2097
2450
|
if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
|
|
@@ -2217,10 +2570,18 @@ function toCamelCase(str) {
|
|
|
2217
2570
|
.join('')
|
|
2218
2571
|
}
|
|
2219
2572
|
|
|
2573
|
+
function toLowerCase(str) {
|
|
2574
|
+
if (!str) return ''
|
|
2575
|
+
return str
|
|
2576
|
+
.trim()
|
|
2577
|
+
.toLowerCase()
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2220
2580
|
const stringHelper = {
|
|
2221
2581
|
isSame,
|
|
2222
2582
|
setCode,
|
|
2223
2583
|
toCamelCase,
|
|
2584
|
+
toLowerCase,
|
|
2224
2585
|
}
|
|
2225
2586
|
|
|
2226
2587
|
|
|
@@ -2274,6 +2635,13 @@ function trackingPlugin(schema, options) {
|
|
|
2274
2635
|
|
|
2275
2636
|
|
|
2276
2637
|
|
|
2638
|
+
|
|
2639
|
+
|
|
2640
|
+
|
|
2641
|
+
|
|
2642
|
+
|
|
2643
|
+
|
|
2644
|
+
|
|
2277
2645
|
|
|
2278
2646
|
|
|
2279
2647
|
|
|
@@ -2284,6 +2652,196 @@ function trackingPlugin(schema, options) {
|
|
|
2284
2652
|
|
|
2285
2653
|
|
|
2286
2654
|
|
|
2655
|
+
;// ./lib/models/awsStsS3Client/awsStsS3Client.js
|
|
2656
|
+
class AwsStsS3Client {
|
|
2657
|
+
constructor(options) {
|
|
2658
|
+
options = options || {}
|
|
2659
|
+
|
|
2660
|
+
this.expiration = options.expiration || null
|
|
2661
|
+
this.s3Client = options.s3Client || null
|
|
2662
|
+
this.getIdToken = options.getIdToken
|
|
2663
|
+
this.region = options.region || 'ap-east-1'
|
|
2664
|
+
this.roleArn = options.roleArn
|
|
2665
|
+
this.roleSessionName = options.roleSessionName || 'web-identity-session'
|
|
2666
|
+
this.durationSession = options.durationSession || 3600
|
|
2667
|
+
this.awsClientSts = options.awsClientSts
|
|
2668
|
+
this.awsClientS3 = options.awsClientS3
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
static dummyData() {
|
|
2672
|
+
return {
|
|
2673
|
+
getIdToken: () => 'mock-web-identity-token',
|
|
2674
|
+
roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
|
|
2675
|
+
awsClientSts: {
|
|
2676
|
+
STSClient: class {},
|
|
2677
|
+
AssumeRoleWithWebIdentityCommand: class {}
|
|
2678
|
+
},
|
|
2679
|
+
awsClientS3: {
|
|
2680
|
+
S3Client: class {},
|
|
2681
|
+
PutObjectCommand: class {},
|
|
2682
|
+
GetObjectCommand: class {},
|
|
2683
|
+
DeleteObjectCommand: class {}
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
static init(options = {}) {
|
|
2689
|
+
if (options instanceof this) {
|
|
2690
|
+
return options
|
|
2691
|
+
}
|
|
2692
|
+
try {
|
|
2693
|
+
const instance = new this(options)
|
|
2694
|
+
if (!instance.isValid) {
|
|
2695
|
+
return null
|
|
2696
|
+
}
|
|
2697
|
+
return instance
|
|
2698
|
+
} catch (error) {
|
|
2699
|
+
return null
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
get isExpired() {
|
|
2704
|
+
if (!this.expiration) return true;
|
|
2705
|
+
const now = new Date();
|
|
2706
|
+
const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
|
|
2707
|
+
return now >= new Date(this.expiration.getTime() - bufferMs);
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
get isValid() {
|
|
2711
|
+
if (!this.getIdToken) {
|
|
2712
|
+
throw new Error('Missing required configuration: getIdToken function')
|
|
2713
|
+
}
|
|
2714
|
+
if (!this.roleArn) {
|
|
2715
|
+
throw new Error('Missing required configuration: roleArn')
|
|
2716
|
+
}
|
|
2717
|
+
if (!this.awsClientSts) {
|
|
2718
|
+
throw new Error('Missing required AWS awsClientSts client configuration')
|
|
2719
|
+
}
|
|
2720
|
+
if (!this.awsClientSts.STSClient) {
|
|
2721
|
+
throw new Error('Missing STSClient in AWS awsClientSts client configuration')
|
|
2722
|
+
}
|
|
2723
|
+
if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
|
|
2724
|
+
throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
|
|
2725
|
+
}
|
|
2726
|
+
if (!this.awsClientS3) {
|
|
2727
|
+
throw new Error('Missing required AWS awsClientS3 client configuration')
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
const requiredS3Components = [
|
|
2731
|
+
'S3Client',
|
|
2732
|
+
'PutObjectCommand',
|
|
2733
|
+
'GetObjectCommand',
|
|
2734
|
+
'DeleteObjectCommand'
|
|
2735
|
+
]
|
|
2736
|
+
|
|
2737
|
+
for (const component of requiredS3Components) {
|
|
2738
|
+
if (!this.awsClientS3[component]) {
|
|
2739
|
+
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
return true
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
async refreshCredentials() {
|
|
2747
|
+
try {
|
|
2748
|
+
const webIdentityToken = await this.getIdToken()
|
|
2749
|
+
if (!webIdentityToken) {
|
|
2750
|
+
throw new Error('getIdToken function returned empty or invalid token')
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2754
|
+
|
|
2755
|
+
const stsResponse = await stsClient.send(
|
|
2756
|
+
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2757
|
+
RoleArn: this.roleArn,
|
|
2758
|
+
RoleSessionName: this.roleSessionName,
|
|
2759
|
+
WebIdentityToken: await this.getIdToken(),
|
|
2760
|
+
DurationSeconds: this.durationSession,
|
|
2761
|
+
})
|
|
2762
|
+
)
|
|
2763
|
+
|
|
2764
|
+
const credentials = stsResponse.Credentials
|
|
2765
|
+
if (!credentials) {
|
|
2766
|
+
throw new Error('No credentials returned from awsClientSts')
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
this.expiration = credentials.Expiration
|
|
2770
|
+
|
|
2771
|
+
this.s3Client = new this.awsClientS3.S3Client({
|
|
2772
|
+
region: this.region,
|
|
2773
|
+
credentials: {
|
|
2774
|
+
accessKeyId: credentials.AccessKeyId,
|
|
2775
|
+
secretAccessKey: credentials.SecretAccessKey,
|
|
2776
|
+
sessionToken: credentials.SessionToken,
|
|
2777
|
+
}
|
|
2778
|
+
})
|
|
2779
|
+
|
|
2780
|
+
return this
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
throw new Error(`Failed to refresh credentials: ${error.message}`)
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
async getS3Client() {
|
|
2787
|
+
if (this.isExpired || !this.s3Client) {
|
|
2788
|
+
await this.refreshCredentials()
|
|
2789
|
+
}
|
|
2790
|
+
return this.s3Client
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
async putObject(params) {
|
|
2794
|
+
try {
|
|
2795
|
+
const client = await this.getS3Client()
|
|
2796
|
+
const command = new this.awsClientS3.PutObjectCommand(params)
|
|
2797
|
+
await client.send(command)
|
|
2798
|
+
const fileArr = params.Key.split('/')
|
|
2799
|
+
return {
|
|
2800
|
+
url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
|
|
2801
|
+
filename: fileArr.pop(),
|
|
2802
|
+
folder: params.Bucket,
|
|
2803
|
+
subFolders: fileArr
|
|
2804
|
+
}
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
throw new Error(`Failed to put object: ${error.message}`)
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
async getObject(params) {
|
|
2811
|
+
try {
|
|
2812
|
+
const client = await this.getS3Client()
|
|
2813
|
+
const command = new this.awsClientS3.GetObjectCommand(params)
|
|
2814
|
+
const response = await client.send(command)
|
|
2815
|
+
return {
|
|
2816
|
+
body: response.Body,
|
|
2817
|
+
contentType: response.ContentType,
|
|
2818
|
+
lastModified: response.LastModified,
|
|
2819
|
+
contentLength: response.ContentLength,
|
|
2820
|
+
}
|
|
2821
|
+
} catch (error) {
|
|
2822
|
+
throw new Error(`Failed to get object: ${error.message}`)
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
async deleteObject(params) {
|
|
2827
|
+
try {
|
|
2828
|
+
const client = await this.getS3Client()
|
|
2829
|
+
const command = new this.awsClientS3.DeleteObjectCommand(params)
|
|
2830
|
+
await client.send(command)
|
|
2831
|
+
return true
|
|
2832
|
+
} catch (error) {
|
|
2833
|
+
throw new Error(`Failed to delete object: ${error.message}`)
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
|
|
2839
|
+
|
|
2840
|
+
;// ./lib/models/awsStsS3Client/index.js
|
|
2841
|
+
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
|
|
2287
2845
|
;// ./lib/models/keyValueObject/keyValueObject.js
|
|
2288
2846
|
class KeyValueObject {
|
|
2289
2847
|
constructor(options = {}) {
|
|
@@ -2411,7 +2969,7 @@ class KeyValueObject {
|
|
|
2411
2969
|
return to.key === from.key
|
|
2412
2970
|
})
|
|
2413
2971
|
if (found) {
|
|
2414
|
-
found.value = (
|
|
2972
|
+
found.value = _mergeValues(from.value, found.value)
|
|
2415
2973
|
} else {
|
|
2416
2974
|
toArr.push(from)
|
|
2417
2975
|
}
|
|
@@ -2496,6 +3054,34 @@ class KeyValueObject {
|
|
|
2496
3054
|
}
|
|
2497
3055
|
}
|
|
2498
3056
|
|
|
3057
|
+
function _mergeValues(existingValue, newValue) {
|
|
3058
|
+
if (existingValue === undefined) return newValue
|
|
3059
|
+
|
|
3060
|
+
// Handle arrays by concatenating
|
|
3061
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3062
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// Handle objects by merging
|
|
3066
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3067
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3068
|
+
return { ...existingValue, ...newValue }
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
// // Handle numbers by adding
|
|
3072
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3073
|
+
// return existingValue
|
|
3074
|
+
// }
|
|
3075
|
+
|
|
3076
|
+
// // Handle strings by concatenating
|
|
3077
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3078
|
+
// return existingValue
|
|
3079
|
+
// }
|
|
3080
|
+
|
|
3081
|
+
// Default: use the new value
|
|
3082
|
+
return newValue
|
|
3083
|
+
}
|
|
3084
|
+
|
|
2499
3085
|
function _isSame(key1, key2) {
|
|
2500
3086
|
return key1 === key2
|
|
2501
3087
|
}
|
|
@@ -2534,7 +3120,7 @@ class Metadata extends KeyValueObject {
|
|
|
2534
3120
|
return metadata_isSame(to.key, from.key)
|
|
2535
3121
|
})
|
|
2536
3122
|
if (found) {
|
|
2537
|
-
found.value = (
|
|
3123
|
+
found.value = metadata_mergeValues(from.value, found.value)
|
|
2538
3124
|
} else {
|
|
2539
3125
|
toArr.push(from)
|
|
2540
3126
|
}
|
|
@@ -2550,6 +3136,34 @@ function metadata_isSame(key1, key2) {
|
|
|
2550
3136
|
return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
|
|
2551
3137
|
}
|
|
2552
3138
|
|
|
3139
|
+
function metadata_mergeValues(existingValue, newValue) {
|
|
3140
|
+
if (existingValue === undefined) return newValue
|
|
3141
|
+
|
|
3142
|
+
// Handle arrays by concatenating
|
|
3143
|
+
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3144
|
+
return [...new Set([...existingValue, ...newValue])]
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
// Handle objects by merging
|
|
3148
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object' &&
|
|
3149
|
+
!Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3150
|
+
return { ...existingValue, ...newValue }
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
// // Handle numbers by adding
|
|
3154
|
+
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3155
|
+
// return existingValue
|
|
3156
|
+
// }
|
|
3157
|
+
|
|
3158
|
+
// // Handle strings by concatenating
|
|
3159
|
+
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3160
|
+
// return existingValue
|
|
3161
|
+
// }
|
|
3162
|
+
|
|
3163
|
+
// Default: use the new value
|
|
3164
|
+
return newValue
|
|
3165
|
+
}
|
|
3166
|
+
|
|
2553
3167
|
|
|
2554
3168
|
|
|
2555
3169
|
;// ./lib/models/metadata/index.js
|
|
@@ -2687,6 +3301,9 @@ class TrackedEntity {
|
|
|
2687
3301
|
get owner() {
|
|
2688
3302
|
return this.meta?.owner ?? this.owner
|
|
2689
3303
|
}
|
|
3304
|
+
changeCreatorOwner({ source, target }) {
|
|
3305
|
+
return changeCreatorOwner(this, { source, target }).setModified()
|
|
3306
|
+
}
|
|
2690
3307
|
delete() {
|
|
2691
3308
|
return this.setDeleted()
|
|
2692
3309
|
}
|
|
@@ -2893,6 +3510,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
2893
3510
|
|
|
2894
3511
|
|
|
2895
3512
|
|
|
3513
|
+
|
|
2896
3514
|
;// ./lib/index.js
|
|
2897
3515
|
|
|
2898
3516
|
|