@tellescope/sdk 1.236.2 → 1.237.1

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.
Files changed (41) hide show
  1. package/lib/cjs/enduser.d.ts +1 -0
  2. package/lib/cjs/enduser.d.ts.map +1 -1
  3. package/lib/cjs/enduser.js +1 -0
  4. package/lib/cjs/enduser.js.map +1 -1
  5. package/lib/cjs/sdk.d.ts +1 -0
  6. package/lib/cjs/sdk.d.ts.map +1 -1
  7. package/lib/cjs/sdk.js +1 -0
  8. package/lib/cjs/sdk.js.map +1 -1
  9. package/lib/cjs/tests/api_tests/inbox_thread_assignment_updates.test.d.ts.map +1 -1
  10. package/lib/cjs/tests/api_tests/inbox_thread_assignment_updates.test.js +172 -64
  11. package/lib/cjs/tests/api_tests/inbox_thread_assignment_updates.test.js.map +1 -1
  12. package/lib/cjs/tests/api_tests/inbox_thread_mdb_filter.test.d.ts +6 -0
  13. package/lib/cjs/tests/api_tests/inbox_thread_mdb_filter.test.d.ts.map +1 -0
  14. package/lib/cjs/tests/api_tests/inbox_thread_mdb_filter.test.js +372 -0
  15. package/lib/cjs/tests/api_tests/inbox_thread_mdb_filter.test.js.map +1 -0
  16. package/lib/cjs/tests/tests.js +571 -105
  17. package/lib/cjs/tests/tests.js.map +1 -1
  18. package/lib/esm/enduser.d.ts +3 -0
  19. package/lib/esm/enduser.d.ts.map +1 -1
  20. package/lib/esm/enduser.js +1 -0
  21. package/lib/esm/enduser.js.map +1 -1
  22. package/lib/esm/sdk.d.ts +5 -2
  23. package/lib/esm/sdk.d.ts.map +1 -1
  24. package/lib/esm/sdk.js +1 -0
  25. package/lib/esm/sdk.js.map +1 -1
  26. package/lib/esm/tests/api_tests/inbox_thread_assignment_updates.test.d.ts.map +1 -1
  27. package/lib/esm/tests/api_tests/inbox_thread_assignment_updates.test.js +172 -64
  28. package/lib/esm/tests/api_tests/inbox_thread_assignment_updates.test.js.map +1 -1
  29. package/lib/esm/tests/api_tests/inbox_thread_mdb_filter.test.d.ts +6 -0
  30. package/lib/esm/tests/api_tests/inbox_thread_mdb_filter.test.d.ts.map +1 -0
  31. package/lib/esm/tests/api_tests/inbox_thread_mdb_filter.test.js +368 -0
  32. package/lib/esm/tests/api_tests/inbox_thread_mdb_filter.test.js.map +1 -0
  33. package/lib/esm/tests/tests.js +571 -105
  34. package/lib/esm/tests/tests.js.map +1 -1
  35. package/lib/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +10 -10
  37. package/src/enduser.ts +4 -0
  38. package/src/sdk.ts +4 -0
  39. package/src/tests/api_tests/inbox_thread_assignment_updates.test.ts +99 -0
  40. package/src/tests/tests.ts +399 -1
  41. package/test_generated.pdf +0 -0
@@ -354,6 +354,105 @@ export const inbox_thread_assignment_updates_tests = async ({ sdk, sdkNonAdmin }
354
354
  sdk.api.sms_messages.deleteOne(upsertSMS.id),
355
355
  ])
356
356
 
357
+ // Test 10: returnCount parameter - basic count
358
+ console.log("Testing load_threads returnCount parameter...")
359
+
360
+ const countResult = await sdk.api.inbox_threads.load_threads({ returnCount: true })
361
+ assert(typeof countResult.count === 'number', "returnCount should return a count field with a number")
362
+ assert(countResult.threads === undefined, "returnCount should not return threads array")
363
+
364
+ // Verify count matches actual thread count
365
+ const allThreads = await sdk.api.inbox_threads.load_threads({})
366
+ assert(countResult.count === allThreads.threads.length, `Count (${countResult.count}) should match threads length (${allThreads.threads.length})`)
367
+
368
+ console.log("✅ returnCount basic test passed")
369
+
370
+ // Test 11: returnCount with enduserIds filter
371
+ console.log("Testing returnCount with enduserIds filter...")
372
+
373
+ const filteredThreads = await sdk.api.inbox_threads.load_threads({ enduserIds: [testEnduser.id] })
374
+ const filteredCount = await sdk.api.inbox_threads.load_threads({ enduserIds: [testEnduser.id], returnCount: true })
375
+
376
+ assert(typeof filteredCount.count === 'number', "Filtered returnCount should return a count")
377
+ assert(filteredCount.count === filteredThreads.threads.length, `Filtered count (${filteredCount.count}) should match filtered threads length (${filteredThreads.threads.length})`)
378
+
379
+ console.log("✅ returnCount with enduserIds filter test passed")
380
+
381
+ // Test 12: returnCount returns 0 for non-matching filters
382
+ console.log("Testing returnCount returns 0 for non-matching filters...")
383
+
384
+ const nonMatchingCount = await sdk.api.inbox_threads.load_threads({
385
+ enduserIds: ['000000000000000000000000'], // Non-existent enduser ID
386
+ returnCount: true
387
+ })
388
+
389
+ assert(nonMatchingCount.count === 0, `Non-matching filter count should be 0, got ${nonMatchingCount.count}`)
390
+
391
+ console.log("✅ returnCount with non-matching filter test passed")
392
+
393
+ // Test 13: mdbFilter - filter by type
394
+ console.log("Testing mdbFilter - filter by type...")
395
+ const emailTypeFilter = await sdk.api.inbox_threads.load_threads({
396
+ mdbFilter: { type: 'Email' }
397
+ })
398
+ const foundEmailByType = emailTypeFilter.threads.find(t => t.id === emailThread.id)
399
+ const foundSmsByType = emailTypeFilter.threads.find(t => t.id === smsThread.id)
400
+ assert(!!foundEmailByType, 'Email thread should be found when filtering by Email type')
401
+ assert(!foundSmsByType, 'SMS thread should not be found when filtering by Email type')
402
+ console.log("✅ mdbFilter type filter test passed")
403
+
404
+ // Test 14: mdbFilter - filter by multiple types ($in)
405
+ console.log("Testing mdbFilter - filter by multiple types...")
406
+ const multiTypeFilter = await sdk.api.inbox_threads.load_threads({
407
+ mdbFilter: { type: { $in: ['Email', 'SMS'] } }
408
+ })
409
+ const foundEmailMulti = multiTypeFilter.threads.find(t => t.id === emailThread.id)
410
+ const foundSmsMulti = multiTypeFilter.threads.find(t => t.id === smsThread.id)
411
+ const foundChatMulti = multiTypeFilter.threads.find(t => t.id === chatThread.id)
412
+ assert(!!foundEmailMulti, 'Email thread should be found')
413
+ assert(!!foundSmsMulti, 'SMS thread should be found')
414
+ assert(!foundChatMulti, 'Chat thread should not be found when filtering Email/SMS')
415
+ console.log("✅ mdbFilter multiple types filter test passed")
416
+
417
+ // Test 15: mdbFilter - filter by assignedTo
418
+ console.log("Testing mdbFilter - filter by assignedTo...")
419
+ // First assign the email thread (may already be assigned from earlier tests)
420
+ await sdk.api.inbox_threads.updateOne(emailThread.id, { assignedTo: [testUser.id] })
421
+ const assigneeFilter = await sdk.api.inbox_threads.load_threads({
422
+ mdbFilter: { assignedTo: testUser.id }
423
+ })
424
+ const foundAssigned = assigneeFilter.threads.find(t => t.id === emailThread.id)
425
+ assert(!!foundAssigned, 'Email thread should be found when filtering by assignee')
426
+ console.log("✅ mdbFilter assignedTo filter test passed")
427
+
428
+ // Test 16: mdbFilter - combined with existing params
429
+ console.log("Testing mdbFilter combined with enduserIds...")
430
+ const combinedFilter = await sdk.api.inbox_threads.load_threads({
431
+ enduserIds: [testEnduser.id],
432
+ mdbFilter: { type: 'Email' }
433
+ })
434
+ const foundCombined = combinedFilter.threads.find(t => t.id === emailThread.id)
435
+ assert(!!foundCombined, 'Email thread should be found with combined filters')
436
+ console.log("✅ mdbFilter combined filter test passed")
437
+
438
+ // Test 17: mdbFilter with returnCount
439
+ console.log("Testing mdbFilter with returnCount...")
440
+ const mdbFilterCount = await sdk.api.inbox_threads.load_threads({
441
+ mdbFilter: { type: 'Email' },
442
+ returnCount: true
443
+ })
444
+ assert(typeof mdbFilterCount.count === 'number', 'mdbFilter with returnCount should return count')
445
+ assert((mdbFilterCount.count ?? 0) >= 1, 'Count should be at least 1 for Email type')
446
+ console.log("✅ mdbFilter with returnCount test passed")
447
+
448
+ // Test 18: mdbFilter with empty object (should return all)
449
+ console.log("Testing mdbFilter with empty object...")
450
+ const emptyMdbFilter = await sdk.api.inbox_threads.load_threads({
451
+ mdbFilter: {}
452
+ })
453
+ assert(emptyMdbFilter.threads.length > 0, 'Empty mdbFilter should return threads')
454
+ console.log("✅ mdbFilter empty object test passed")
455
+
357
456
  console.log("🎉 All InboxThread assignment update tests passed!")
358
457
 
359
458
  } finally {
@@ -12911,6 +12911,403 @@ const inbox_threads_loading_tests = async () => {
12911
12911
  ])
12912
12912
  }
12913
12913
 
12914
+ const inbox_threads_new_fields_tests = async () => {
12915
+ log_header("Inbox Thread New Fields Tests (archivedAt, trashedAt, senderIds)")
12916
+
12917
+ const e = await sdk.api.endusers.createOne({ fname: 'Test', lname: 'NewFields' })
12918
+
12919
+ // Use the new reset_threads endpoint for full resets (delete threads + reset dates)
12920
+ const resetThreadsAndDates = () => sdk.api.inbox_threads.reset_threads()
12921
+
12922
+ // Keep separate helper for just resetting dates - needed for merge tests
12923
+ // where we want to keep existing threads but allow rebuild
12924
+ let i = 0
12925
+ const start = new Date()
12926
+ const resetThreadBuildingDates = () => (
12927
+ sdk.api.organizations.updateOne(businessId, { // Uses global businessId constant
12928
+ inboxThreadsBuiltFrom: new Date(start.getTime() + (i++)),
12929
+ inboxThreadsBuiltTo: new Date(start.getTime() + (i++))
12930
+ })
12931
+ )
12932
+ // Start with clean state
12933
+ await resetThreadsAndDates()
12934
+ const from = new Date(start.getTime() - 10000)
12935
+
12936
+ // Test 1: Sender ID Tests - Email
12937
+ log_header("Sender ID Tests - Email")
12938
+ await sdk.api.emails.createOne({
12939
+ logOnly: true,
12940
+ subject: 'Test Email Inbound',
12941
+ textContent: 'Inbound email',
12942
+ enduserId: e.id,
12943
+ inbound: true,
12944
+ userId: sdk.userInfo.id,
12945
+ })
12946
+ await sdk.api.emails.createOne({
12947
+ logOnly: true,
12948
+ subject: 'Test Email Inbound', // Same subject to be same thread
12949
+ textContent: 'Outbound email',
12950
+ enduserId: e.id,
12951
+ inbound: false,
12952
+ userId: sdk.userInfo.id,
12953
+ })
12954
+
12955
+ await async_test(
12956
+ 'build email threads with sender IDs',
12957
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
12958
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
12959
+ )
12960
+ await async_test(
12961
+ 'verify email thread has correct sender IDs',
12962
+ () => sdk.api.inbox_threads.load_threads({ }),
12963
+ { onResult: ({ threads }) => {
12964
+ const emailThread = threads.find(t => t.type === 'Email')
12965
+ return !!emailThread
12966
+ && emailThread.recentOutboundUserId === sdk.userInfo.id
12967
+ && emailThread.recentInboundEnduserId === e.id
12968
+ }}
12969
+ )
12970
+
12971
+ // Test 2: Sender ID Tests - SMS
12972
+ log_header("Sender ID Tests - SMS")
12973
+ await resetThreadsAndDates()
12974
+ await sdk.api.sms_messages.createOne({
12975
+ logOnly: true,
12976
+ inbound: true,
12977
+ enduserId: e.id,
12978
+ message: 'Inbound SMS',
12979
+ userId: sdk.userInfo.id,
12980
+ phoneNumber: '+15555555555',
12981
+ enduserPhoneNumber: '+15555555556',
12982
+ })
12983
+ await sdk.api.sms_messages.createOne({
12984
+ logOnly: true,
12985
+ inbound: false,
12986
+ enduserId: e.id,
12987
+ message: 'Outbound SMS',
12988
+ userId: sdk.userInfo.id,
12989
+ phoneNumber: '+15555555555',
12990
+ enduserPhoneNumber: '+15555555556',
12991
+ })
12992
+
12993
+ await async_test(
12994
+ 'build SMS threads with sender IDs',
12995
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
12996
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
12997
+ )
12998
+ await async_test(
12999
+ 'verify SMS thread has correct sender IDs',
13000
+ () => sdk.api.inbox_threads.load_threads({ }),
13001
+ { onResult: ({ threads }) => {
13002
+ const smsThread = threads.find(t => t.type === 'SMS')
13003
+ return !!smsThread
13004
+ && smsThread.recentOutboundUserId === sdk.userInfo.id
13005
+ && smsThread.recentInboundEnduserId === e.id
13006
+ }}
13007
+ )
13008
+
13009
+ // Test 3: Sender ID Tests - ChatRoom
13010
+ log_header("Sender ID Tests - ChatRoom")
13011
+ await resetThreadsAndDates()
13012
+ const chatRoom = await sdk.api.chat_rooms.createOne({
13013
+ title: 'Test Chat Room',
13014
+ userIds: [sdk.userInfo.id],
13015
+ enduserIds: [e.id],
13016
+ })
13017
+ // First message from user (outbound)
13018
+ await sdk.api.chats.createOne({ roomId: chatRoom.id, message: 'User message', senderId: sdk.userInfo.id })
13019
+ await wait(undefined, 500)
13020
+
13021
+ await async_test(
13022
+ 'build chat threads after user message',
13023
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13024
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13025
+ )
13026
+ await async_test(
13027
+ 'verify chat thread has outbound userId only',
13028
+ () => sdk.api.inbox_threads.load_threads({ }),
13029
+ { onResult: ({ threads }) => {
13030
+ const chatThread = threads.find(t => t.type === 'Chat')
13031
+ return !!chatThread
13032
+ && chatThread.recentOutboundUserId === sdk.userInfo.id
13033
+ && !chatThread.recentInboundEnduserId
13034
+ }}
13035
+ )
13036
+
13037
+ // Now enduser sends a message (becomes recentSender, but merge preserves previous outbound userId)
13038
+ await sdk.api.chats.createOne({ roomId: chatRoom.id, message: 'Enduser message', enduserId: e.id, senderId: e.id })
13039
+ await wait(undefined, 500)
13040
+ await resetThreadBuildingDates() // Only reset dates, keep existing thread for merge test
13041
+
13042
+ await async_test(
13043
+ 'rebuild chat threads after enduser message',
13044
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13045
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13046
+ )
13047
+ await async_test(
13048
+ 'verify chat thread has both sender IDs (merge preserves previous)',
13049
+ () => sdk.api.inbox_threads.load_threads({ }),
13050
+ { onResult: ({ threads }) => {
13051
+ const chatThread = threads.find(t => t.type === 'Chat')
13052
+ // ChatRoom only tracks one recentSender at a time, but merge preserves both IDs
13053
+ return !!chatThread
13054
+ && chatThread.recentOutboundUserId === sdk.userInfo.id // preserved from previous build
13055
+ && chatThread.recentInboundEnduserId === e.id // from current build
13056
+ }}
13057
+ )
13058
+
13059
+ // Test 4: Sender ID Tests - GroupMMS
13060
+ log_header("Sender ID Tests - GroupMMS")
13061
+ await resetThreadsAndDates()
13062
+ const groupMMS = await sdk.api.group_mms_conversations.createOne({
13063
+ enduserIds: [e.id],
13064
+ userIds: [sdk.userInfo.id],
13065
+ userStates: [],
13066
+ messages: [
13067
+ { message: 'Inbound message', sender: e.id, timestamp: Date.now() - 1000, logOnly: true },
13068
+ { message: 'Outbound message', sender: sdk.userInfo.id, timestamp: Date.now(), logOnly: true },
13069
+ ],
13070
+ })
13071
+
13072
+ await async_test(
13073
+ 'build GroupMMS threads with sender IDs',
13074
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13075
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13076
+ )
13077
+ await async_test(
13078
+ 'verify GroupMMS thread has correct sender IDs',
13079
+ () => sdk.api.inbox_threads.load_threads({ }),
13080
+ { onResult: ({ threads }) => {
13081
+ const groupMMSThread = threads.find(t => t.type === 'GroupMMS')
13082
+ return !!groupMMSThread
13083
+ && groupMMSThread.recentOutboundUserId === sdk.userInfo.id
13084
+ && groupMMSThread.recentInboundEnduserId === e.id
13085
+ }}
13086
+ )
13087
+
13088
+ // Test 5: Sender ID Tests - PhoneCall
13089
+ log_header("Sender ID Tests - PhoneCall")
13090
+ await resetThreadsAndDates()
13091
+ const inboundCall = await sdk.api.phone_calls.createOne({
13092
+ enduserId: e.id,
13093
+ inbound: true,
13094
+ to: '+15555555555',
13095
+ from: '+15555555556',
13096
+ userId: sdk.userInfo.id,
13097
+ })
13098
+
13099
+ await async_test(
13100
+ 'build phone call threads (inbound)',
13101
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13102
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13103
+ )
13104
+ await async_test(
13105
+ 'verify inbound phone call thread has enduserId',
13106
+ () => sdk.api.inbox_threads.load_threads({ }),
13107
+ { onResult: ({ threads }) => {
13108
+ const callThread = threads.find(t => t.type === 'Phone' && t.threadId === inboundCall.id)
13109
+ return !!callThread
13110
+ && !callThread.recentOutboundUserId
13111
+ && callThread.recentInboundEnduserId === e.id
13112
+ }}
13113
+ )
13114
+
13115
+ // Test outbound call separately to avoid date range issues
13116
+ await resetThreadsAndDates()
13117
+ const outboundCall = await sdk.api.phone_calls.createOne({
13118
+ enduserId: e.id,
13119
+ inbound: false,
13120
+ to: '+15555555556',
13121
+ from: '+15555555555',
13122
+ userId: sdk.userInfo.id,
13123
+ })
13124
+
13125
+ await async_test(
13126
+ 'build phone call threads (outbound)',
13127
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13128
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13129
+ )
13130
+ await async_test(
13131
+ 'verify outbound phone call thread has userId',
13132
+ () => sdk.api.inbox_threads.load_threads({ }),
13133
+ { onResult: ({ threads }) => {
13134
+ const callThread = threads.find(t => t.type === 'Phone' && t.threadId === outboundCall.id)
13135
+ return !!callThread
13136
+ && callThread.recentOutboundUserId === sdk.userInfo.id
13137
+ && !callThread.recentInboundEnduserId
13138
+ }}
13139
+ )
13140
+
13141
+ // Test 6: Archive/Trash Tests - Propagation
13142
+ log_header("Archive/Trash Tests - Propagation")
13143
+ await resetThreadsAndDates()
13144
+ const archivedDate = new Date()
13145
+ await sdk.api.emails.createOne({
13146
+ logOnly: true,
13147
+ subject: 'Archived Email',
13148
+ textContent: 'This email is archived',
13149
+ enduserId: e.id,
13150
+ inbound: true,
13151
+ userId: sdk.userInfo.id,
13152
+ archivedAt: archivedDate,
13153
+ })
13154
+
13155
+ await async_test(
13156
+ 'build threads with archived email',
13157
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13158
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13159
+ )
13160
+ await async_test(
13161
+ 'verify thread has archivedAt populated',
13162
+ () => sdk.api.inbox_threads.load_threads({ }),
13163
+ { onResult: ({ threads }) => {
13164
+ const emailThread = threads.find(t => t.type === 'Email')
13165
+ return !!emailThread
13166
+ && !!emailThread.archivedAt
13167
+ && new Date(emailThread.archivedAt).getTime() === archivedDate.getTime()
13168
+ }}
13169
+ )
13170
+
13171
+ // Test 7: Archive/Trash Tests - Clearing (new message clears archived status)
13172
+ log_header("Archive/Trash Tests - Clearing")
13173
+ await sdk.api.emails.createOne({
13174
+ logOnly: true,
13175
+ subject: 'Archived Email', // Same subject = same thread
13176
+ textContent: 'This email is NOT archived',
13177
+ enduserId: e.id,
13178
+ inbound: true,
13179
+ userId: sdk.userInfo.id,
13180
+ // No archivedAt
13181
+ })
13182
+ await resetThreadBuildingDates() // Only reset dates, keep existing thread for merge test
13183
+
13184
+ await async_test(
13185
+ 'rebuild threads after non-archived message',
13186
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13187
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13188
+ )
13189
+ await async_test(
13190
+ 'verify thread archivedAt is cleared',
13191
+ () => sdk.api.inbox_threads.load_threads({ }),
13192
+ { onResult: ({ threads }) => {
13193
+ const emailThread = threads.find(t => t.type === 'Email')
13194
+ return !!emailThread && emailThread.archivedAt === ''
13195
+ }}
13196
+ )
13197
+
13198
+ // Test 8: Archive/Trash Tests - trashedAt propagation
13199
+ log_header("Archive/Trash Tests - Trashed Propagation")
13200
+ await resetThreadsAndDates()
13201
+ const trashedDate = new Date()
13202
+ await sdk.api.sms_messages.createOne({
13203
+ logOnly: true,
13204
+ inbound: true,
13205
+ enduserId: e.id,
13206
+ message: 'Trashed SMS',
13207
+ userId: sdk.userInfo.id,
13208
+ phoneNumber: '+15555555557',
13209
+ enduserPhoneNumber: '+15555555558',
13210
+ trashedAt: trashedDate,
13211
+ })
13212
+
13213
+ await async_test(
13214
+ 'build threads with trashed SMS',
13215
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13216
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13217
+ )
13218
+ await async_test(
13219
+ 'verify thread has trashedAt populated',
13220
+ () => sdk.api.inbox_threads.load_threads({ }),
13221
+ { onResult: ({ threads }) => {
13222
+ const smsThread = threads.find(t => t.type === 'SMS' && t.phoneNumber === '+15555555557')
13223
+ return !!smsThread
13224
+ && !!smsThread.trashedAt
13225
+ && new Date(smsThread.trashedAt).getTime() === trashedDate.getTime()
13226
+ }}
13227
+ )
13228
+
13229
+ // Test 9: Archive/Trash Tests - Most Recent Archived, Older Not
13230
+ log_header("Archive/Trash Tests - Most Recent Archived, Older Not")
13231
+ await resetThreadsAndDates()
13232
+ // Create non-archived message first (older)
13233
+ await sdk.api.emails.createOne({
13234
+ logOnly: true,
13235
+ subject: 'Archive Order Test',
13236
+ textContent: 'Older non-archived email',
13237
+ enduserId: e.id,
13238
+ inbound: true,
13239
+ userId: sdk.userInfo.id,
13240
+ // No archivedAt
13241
+ })
13242
+
13243
+ await wait(undefined, 100) // Small delay to ensure ordering
13244
+
13245
+ // Create archived message second (newer = most recent)
13246
+ await sdk.api.emails.createOne({
13247
+ logOnly: true,
13248
+ subject: 'Archive Order Test', // Same subject = same thread
13249
+ textContent: 'Newer archived email',
13250
+ enduserId: e.id,
13251
+ inbound: true,
13252
+ userId: sdk.userInfo.id,
13253
+ archivedAt: new Date(),
13254
+ })
13255
+
13256
+ await async_test(
13257
+ 'build threads for archive order test',
13258
+ () => sdk.api.inbox_threads.build_threads({ from, to: new Date() }),
13259
+ { onResult: ({ alreadyBuilt }) => !alreadyBuilt }
13260
+ )
13261
+ await async_test(
13262
+ 'verify thread archivedAt follows most recent message (IS archived)',
13263
+ () => sdk.api.inbox_threads.load_threads({ }),
13264
+ { onResult: ({ threads }) => {
13265
+ const emailThread = threads.find(t => t.type === 'Email')
13266
+ // Most recent message is archived, so thread should be archived
13267
+ return !!emailThread && !!emailThread.archivedAt
13268
+ }}
13269
+ )
13270
+
13271
+ // Test 10: Reset Threads Endpoint - Comprehensive Coverage
13272
+ log_header("Reset Threads Endpoint Test")
13273
+
13274
+ // Test 10a: Verify threads are deleted and count returned
13275
+ const beforeReset = await sdk.api.inbox_threads.load_threads({})
13276
+ assert(beforeReset.threads.length > 0, 'no threads before reset test', 'threads exist before reset test')
13277
+
13278
+ const resetResult = await sdk.api.inbox_threads.reset_threads()
13279
+ assert(resetResult.deletedCount > 0, 'no threads deleted by reset', 'reset_threads deleted threads')
13280
+
13281
+ const afterReset = await sdk.api.inbox_threads.load_threads({})
13282
+ assert(afterReset.threads.length === 0, 'threads remain after reset', 'all threads deleted after reset')
13283
+
13284
+ // Test 10b: Verify organization dates are reset to epoch
13285
+ const org = await sdk.api.organizations.getOne(businessId)
13286
+ const epochTime = new Date(0).getTime()
13287
+ assert(
13288
+ new Date(org.inboxThreadsBuiltFrom ?? 0).getTime() === epochTime,
13289
+ 'inboxThreadsBuiltFrom not reset to epoch',
13290
+ 'organization inboxThreadsBuiltFrom reset to epoch'
13291
+ )
13292
+ assert(
13293
+ new Date(org.inboxThreadsBuiltTo ?? 0).getTime() === epochTime,
13294
+ 'inboxThreadsBuiltTo not reset to epoch',
13295
+ 'organization inboxThreadsBuiltTo reset to epoch'
13296
+ )
13297
+
13298
+ // Test 10c: Verify reset with no threads returns deletedCount: 0
13299
+ const emptyResetResult = await sdk.api.inbox_threads.reset_threads()
13300
+ assert(emptyResetResult.deletedCount === 0, 'deletedCount should be 0 when no threads', 'reset with no threads returns 0')
13301
+
13302
+ // Cleanup
13303
+ await Promise.all([
13304
+ sdk.api.endusers.deleteOne(e.id),
13305
+ sdk.api.chat_rooms.deleteOne(chatRoom.id).catch(() => {}),
13306
+ sdk.api.group_mms_conversations.deleteOne(groupMMS.id).catch(() => {}),
13307
+ resetThreadsAndDates(), // Use the new endpoint for cleanup
13308
+ ])
13309
+ }
13310
+
12914
13311
  const get_next_reminder_timestamp_tests = () => {
12915
13312
  log_header("Get Next Reminder Timestamp Tests")
12916
13313
 
@@ -13173,6 +13570,8 @@ const ip_address_form_tests = async () => {
13173
13570
  await replace_enduser_template_values_tests()
13174
13571
  await mfa_tests()
13175
13572
  await setup_tests(sdk, sdkNonAdmin)
13573
+ await inbox_threads_new_fields_tests()
13574
+ await inbox_thread_assignment_updates_tests({ sdk, sdkNonAdmin })
13176
13575
  await auto_merge_form_submission_tests({ sdk, sdkNonAdmin })
13177
13576
  await threadKeyTests()
13178
13577
  await automation_trigger_tests()
@@ -13187,7 +13586,6 @@ const ip_address_form_tests = async () => {
13187
13586
  await test_ticket_automation_assignment_and_optimization()
13188
13587
  await monthly_availability_restrictions_tests({ sdk, sdkNonAdmin })
13189
13588
  await journey_error_branching_tests({ sdk, sdkNonAdmin })
13190
- await inbox_thread_assignment_updates_tests({ sdk, sdkNonAdmin })
13191
13589
  await message_assignment_trigger_tests({ sdk })
13192
13590
  await inbox_threads_building_tests()
13193
13591
  await inbox_threads_loading_tests()
Binary file