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