@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.
@@ -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 = (found.value || []).concat(from.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 = (found.value || []).concat(from.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 };