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