@tellescope/sdk 1.74.3 → 1.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/session.ts CHANGED
@@ -366,62 +366,59 @@ export class Session {
366
366
  }
367
367
 
368
368
  authenticate_socket = () => {
369
- if (this.userInfo.requiresMFA) return
370
- if (this.lastSocketConnection + 2500 > Date.now()) return
371
- this.lastSocketConnection = Date.now()
369
+ // if (this.userInfo.requiresMFA) return
370
+ // if (this.lastSocketConnection + 2500 > Date.now()) return
371
+ // this.lastSocketConnection = Date.now()
372
372
 
373
- if (this.enableSocketLogging) console.log('authenticating socket')
373
+ // if (this.enableSocketLogging) console.log('authenticating socket')
374
374
 
375
- this.initialize_socket()
376
- if (!this.socket) {
377
- console.warn("failed to initialize_socket")
378
- return
379
- }
375
+ // this.initialize_socket()
376
+ // if (!this.socket) {
377
+ // console.warn("failed to initialize_socket")
378
+ // return
379
+ // }
380
380
 
381
- this.socket.removeAllListeners()
382
-
383
- this.socket.on('ping', () => {
384
- if (this.enableSocketLogging) { this.socket_log("pong") }
385
- })
386
-
387
- // handle events which are sent when handlers may be off
388
- this.socket?.onAny((e, v)=> {
389
- if (this.handlers[e] && v) {
390
- this.handlers[e](v)
391
- } else if (Array.isArray(v)) {
392
- if (!this.loadedSocketEvents[e]) {
393
- this.loadedSocketEvents[e] = []
394
- }
395
- this.loadedSocketEvents[e].push(...v)
396
- }
397
- })
398
-
399
- this.socket.on('connect', () => {
400
- if (this.enableSocketLogging) { this.socket_log(`connect, authenticated=${this.socketAuthenticated}`) }
401
- })
402
-
403
- this.socket.on('disconnect', () => {
404
- this.socketAuthenticated = false
405
- if (this.enableSocketLogging) { this.socket_log("disconnect") }
406
- })
407
- this.socket.on('authenticated', () => {
408
- this.socketAuthenticated = true
409
- // if (this.enableSocketLogging) {
410
- this.socket_log("authenticated")
411
- // }
412
- })
413
- this.socket.on('error', (error: any) => {
414
- console.warn('socket error: ', error)
415
- })
416
- this.socket.on('connect_error', (error: any) => {
417
- console.warn('connect_error: ', error)
418
- // setTimeout(() => {
419
- // this.socket?.connect()
420
- // })
421
- })
422
-
423
- // no longer necessary
424
- // this.socket.emit('authenticate', this.authToken)
381
+ // this.socket.removeAllListeners()
382
+
383
+ // this.socket.on('ping', () => {
384
+ // if (this.enableSocketLogging) { this.socket_log("pong") }
385
+ // })
386
+
387
+ // // handle events which are sent when handlers may be off
388
+ // this.socket?.onAny((e, v)=> {
389
+ // if (this.handlers[e] && v) {
390
+ // this.handlers[e](v)
391
+ // } else if (Array.isArray(v)) {
392
+ // if (!this.loadedSocketEvents[e]) {
393
+ // this.loadedSocketEvents[e] = []
394
+ // }
395
+ // this.loadedSocketEvents[e].push(...v)
396
+ // }
397
+ // })
398
+
399
+ // this.socket.on('connect', () => {
400
+ // if (this.enableSocketLogging) { this.socket_log(`connect, authenticated=${this.socketAuthenticated}`) }
401
+ // })
402
+
403
+ // this.socket.on('disconnect', () => {
404
+ // this.socketAuthenticated = false
405
+ // if (this.enableSocketLogging) { this.socket_log("disconnect") }
406
+ // })
407
+ // this.socket.on('authenticated', () => {
408
+ // this.socketAuthenticated = true
409
+ // // if (this.enableSocketLogging) {
410
+ // this.socket_log("authenticated")
411
+ // // }
412
+ // })
413
+ // this.socket.on('error', (error: any) => {
414
+ // console.warn('socket error: ', error)
415
+ // })
416
+ // this.socket.on('connect_error', (error: any) => {
417
+ // console.warn('connect_error: ', error)
418
+ // // setTimeout(() => {
419
+ // // this.socket?.connect()
420
+ // // })
421
+ // })
425
422
  }
426
423
 
427
424
  /** @deprecated */
@@ -140,6 +140,8 @@ const setup_tests = async () => {
140
140
  { expectedResult: 'Authenticated!' }
141
141
  )
142
142
 
143
+
144
+
143
145
  await sdk.logout()
144
146
  await async_test<string, string>('test_authenticated - (logout invalidates jwt)', sdk.test_authenticated, { shouldError: true, onError: e => e === 'Unauthenticated' })
145
147
  await sdk.authenticate(email, password)
@@ -4085,8 +4087,10 @@ export const self_serve_appointment_booking_tests = async () => {
4085
4087
 
4086
4088
  const e1 = await sdk.api.endusers.createOne({ email: 'sebass+ny@tellescope.com', state: 'NY' })
4087
4089
  const e2 = await sdk.api.endusers.createOne({ email: 'sebass+ca@tellescope.com', state: 'CA' })
4090
+ const e3 = await sdk.api.endusers.createOne({ email: 'sebass+3@tellescope.com' })
4088
4091
  await sdk.api.endusers.set_password({ id: e1.id, password })
4089
4092
  await sdk.api.endusers.set_password({ id: e2.id, password })
4093
+ await sdk.api.endusers.set_password({ id: e3.id, password })
4090
4094
 
4091
4095
  const event15min = await sdk.api.calendar_event_templates.createOne({
4092
4096
  title: 'test 2', durationInMinutes: 15,
@@ -4098,6 +4102,12 @@ export const self_serve_appointment_booking_tests = async () => {
4098
4102
  confirmationEmailDisabled: true,
4099
4103
  confirmationSMSDisabled: true,
4100
4104
  })
4105
+ const event30minGroup = await sdk.api.calendar_event_templates.createOne({
4106
+ title: 'test group', durationInMinutes: 30,
4107
+ confirmationEmailDisabled: true,
4108
+ confirmationSMSDisabled: true,
4109
+ enduserAttendeeLimit: 2,
4110
+ })
4101
4111
 
4102
4112
  // ensure it doesn't match current day, to avoid errors on testing
4103
4113
  const dayOfWeekStartingSundayIndexedByZero = (new Date().getDay() + 1) % 7
@@ -4135,6 +4145,12 @@ export const self_serve_appointment_booking_tests = async () => {
4135
4145
  replaceObjectFields: true,
4136
4146
  })
4137
4147
 
4148
+ const enduserSDK2 = new EnduserSession({ host, businessId })
4149
+ await enduserSDK2.authenticate('sebass+ca@tellescope.com', password).catch(console.error)
4150
+
4151
+ const enduserSDK3 = new EnduserSession({ host, businessId })
4152
+ await enduserSDK3.authenticate('sebass+3@tellescope.com', password).catch(console.error)
4153
+
4138
4154
  // NY Enduser Tests
4139
4155
  await enduserSDK.authenticate('sebass+ny@tellescope.com', password).catch(console.error)
4140
4156
  await async_test(
@@ -4258,6 +4274,78 @@ export const self_serve_appointment_booking_tests = async () => {
4258
4274
  handleAnyError
4259
4275
  )
4260
4276
 
4277
+ // test group bookings
4278
+ await sdk.api.calendar_events.updateOne(conflict.id, { enduserAttendeeLimit: 2 })
4279
+ await async_test(
4280
+ '[group booking] different event type conflict as group still blocks availability',
4281
+ () => enduserSDK.api.calendar_events.get_appointment_availability({
4282
+ calendarEventTemplateId: event30minGroup.id,
4283
+ from: new Date(Date.now() - 10000),
4284
+ to: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
4285
+ }),
4286
+ { onResult: r => r.availabilityBlocks.length === 2 },
4287
+ )
4288
+ await sdk.api.calendar_events.deleteOne(conflict.id)
4289
+ await async_test(
4290
+ '[group booking] availability',
4291
+ () => enduserSDK.api.calendar_events.get_appointment_availability({
4292
+ calendarEventTemplateId: event30minGroup.id,
4293
+ from: new Date(Date.now() - 10000),
4294
+ to: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
4295
+ }),
4296
+ { onResult: r => r.availabilityBlocks.length === 3 },
4297
+ )
4298
+ const groupEvent = (await enduserSDK.api.calendar_events.book_appointment({
4299
+ calendarEventTemplateId: event30minGroup.id,
4300
+ startTime: new Date(nySlots.availabilityBlocks[1].startTimeInMS),
4301
+ userId: nySlots.availabilityBlocks[1].userId,
4302
+ })).createdEvent
4303
+ await async_test(
4304
+ '[group booking] more booking allowed',
4305
+ () => enduserSDK.api.calendar_events.get_appointment_availability({
4306
+ calendarEventTemplateId: event30minGroup.id,
4307
+ from: new Date(Date.now() - 10000),
4308
+ to: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
4309
+ }),
4310
+ { onResult: r => r.availabilityBlocks.length === 3 },
4311
+ )
4312
+ await async_test(
4313
+ '[group booking] prevent double-book same-enduser',
4314
+ () => enduserSDK.api.calendar_events.book_appointment({
4315
+ calendarEventTemplateId: event30minGroup.id,
4316
+ startTime: new Date(nySlots.availabilityBlocks[1].startTimeInMS),
4317
+ userId: nySlots.availabilityBlocks[1].userId,
4318
+ }),
4319
+ handleAnyError
4320
+ )
4321
+ await async_test(
4322
+ '[group booking] allow other enduser to book',
4323
+ () => enduserSDK2.api.calendar_events.book_appointment({
4324
+ calendarEventTemplateId: event30minGroup.id,
4325
+ startTime: new Date(nySlots.availabilityBlocks[1].startTimeInMS),
4326
+ userId: nySlots.availabilityBlocks[1].userId,
4327
+ }),
4328
+ passOnAnyResult
4329
+ )
4330
+ await async_test(
4331
+ '[group booking] no more booking allowed',
4332
+ () => enduserSDK.api.calendar_events.get_appointment_availability({
4333
+ calendarEventTemplateId: event30minGroup.id,
4334
+ from: new Date(Date.now() - 10000),
4335
+ to: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
4336
+ }),
4337
+ { onResult: r => r.availabilityBlocks.length === 2 },
4338
+ )
4339
+ await async_test(
4340
+ '[group booking] other enduser cant book over capacity',
4341
+ () => enduserSDK3.api.calendar_events.book_appointment({
4342
+ calendarEventTemplateId: event30minGroup.id,
4343
+ startTime: new Date(nySlots.availabilityBlocks[1].startTimeInMS),
4344
+ userId: nySlots.availabilityBlocks[1].userId,
4345
+ }),
4346
+ handleAnyError
4347
+ )
4348
+
4261
4349
  // test 'multi' flag for booking multiple providers for a given patient
4262
4350
  await sdk.api.users.updateOne(sdk.userInfo.id, {
4263
4351
  weeklyAvailabilities: [
@@ -4341,11 +4429,13 @@ export const self_serve_appointment_booking_tests = async () => {
4341
4429
  await Promise.all([
4342
4430
  sdk.api.endusers.deleteOne(e1.id),
4343
4431
  sdk.api.endusers.deleteOne(e2.id),
4432
+ sdk.api.endusers.deleteOne(e3.id),
4344
4433
  sdk.api.calendar_event_templates.deleteOne(event30min.id),
4434
+ sdk.api.calendar_event_templates.deleteOne(event30minGroup.id),
4345
4435
  sdk.api.calendar_event_templates.deleteOne(event15min.id),
4346
4436
  sdk.api.calendar_events.deleteOne(bookedAppointment.id),
4347
- sdk.api.calendar_events.deleteOne(conflict.id),
4348
4437
  sdk.api.calendar_events.deleteOne(bookedMultiAppointment.id),
4438
+ sdk.api.calendar_events.deleteOne(groupEvent.id),
4349
4439
  ])
4350
4440
  }
4351
4441
 
@@ -5850,6 +5940,7 @@ export const alternate_phones_tests = async () => {
5850
5940
 
5851
5941
  const NO_TEST = () => {}
5852
5942
  const tests: { [K in keyof ClientModelForName]: () => void } = {
5943
+ enduser_encounters: NO_TEST,
5853
5944
  enduser_orders: NO_TEST,
5854
5945
  ticket_queues: NO_TEST,
5855
5946
  phone_trees: NO_TEST,
@@ -6618,6 +6709,185 @@ const test_send_with_template = async () => {
6618
6709
  ])
6619
6710
  }
6620
6711
 
6712
+ const delete_user_tests = async () => {
6713
+ log_header("Delete user tests")
6714
+ // delete if previous test failed and user still exists
6715
+ const existing = await sdk.api.users.getSome({ filter: { email: 'deleteme@tellescope.com'}})
6716
+ if (existing[0]?.email === 'deleteme@tellescope.com') {
6717
+ await sdk.api.users.deleteOne(existing[0].id)
6718
+ }
6719
+
6720
+ const u = await sdk.api.users.createOne({ email: 'deleteme@tellescope.com', verifiedEmail: true })
6721
+
6722
+ const { authToken } = await sdk.api.users.generate_auth_token({ id: u.id })
6723
+ const createdUserSDK = new Session({ host, authToken })
6724
+
6725
+ await async_test(
6726
+ "Authenticated",
6727
+ createdUserSDK.test_authenticated,
6728
+ passOnAnyResult
6729
+ )
6730
+
6731
+ await sdk.api.users.deleteOne(u.id)
6732
+ await wait(undefined, 250)
6733
+ await async_test(
6734
+ "De-authenticated after deletion",
6735
+ createdUserSDK.test_authenticated,
6736
+ handleAnyError
6737
+ )
6738
+
6739
+ const enduser = await sdk.api.endusers.createOne({ })
6740
+ const { authToken: enduserAuthToken } = await sdk.api.endusers.generate_auth_token({ id: enduser.id })
6741
+ const enduserSDK = new EnduserSession({ host, businessId, authToken: enduserAuthToken })
6742
+
6743
+ await async_test(
6744
+ "Enduser Authenticated",
6745
+ () => enduserSDK.api.endusers.getSome(),
6746
+ passOnAnyResult
6747
+ )
6748
+
6749
+ await sdk.api.endusers.deleteOne(enduser.id)
6750
+ await wait(undefined, 250)
6751
+ await async_test(
6752
+ "Enduser De-authenticated after deletion",
6753
+ () => enduserSDK.api.endusers.getSome(),
6754
+ handleAnyError
6755
+ )
6756
+ }
6757
+
6758
+ const sdkMfaApiKeyUserId = '6525a43e1e75f0350d62afc4'
6759
+ const lockout_tests = async () => {
6760
+ log_header("Lockout tests")
6761
+
6762
+ await async_test(
6763
+ "API Key is authenticated",
6764
+ sdkMfaApiKey.test_authenticated,
6765
+ passOnAnyResult,
6766
+ )
6767
+ await async_test(
6768
+ "API Key lock to future date",
6769
+ () => sdk.api.users.updateOne(sdkMfaApiKeyUserId, { lockedOutUntil: 0 }),
6770
+ passOnAnyResult
6771
+ )
6772
+ await wait(undefined, 250)
6773
+ await async_test(
6774
+ "API Key is de-authenticated when locked",
6775
+ sdkMfaApiKey.test_authenticated,
6776
+ handleAnyError,
6777
+ )
6778
+ await async_test(
6779
+ "API Key unlock to -1",
6780
+ () => sdk.api.users.updateOne(sdkMfaApiKeyUserId, { lockedOutUntil: -1 }),
6781
+ passOnAnyResult
6782
+ )
6783
+ await async_test(
6784
+ "API Key is authenticated",
6785
+ sdkMfaApiKey.test_authenticated,
6786
+ passOnAnyResult,
6787
+ )
6788
+
6789
+ const nonAdminId = sdkNonAdmin.userInfo.id
6790
+ await async_test(
6791
+ "users cannot update own lock status",
6792
+ () => sdk.api.users.updateOne(sdk.userInfo.id, { lockedOutUntil: -1 }),
6793
+ handleAnyError,
6794
+ )
6795
+ await async_test(
6796
+ "non-admin can't lock out others",
6797
+ () => sdkNonAdmin.api.users.updateOne(sdk.userInfo.id, { lockedOutUntil: Date.now() }),
6798
+ handleAnyError
6799
+ )
6800
+ await async_test(
6801
+ "non-admin is authenticated",
6802
+ sdkNonAdmin.test_authenticated,
6803
+ passOnAnyResult,
6804
+ )
6805
+ await async_test(
6806
+ "admin unlock to -1",
6807
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: -1 }),
6808
+ passOnAnyResult,
6809
+ )
6810
+ await async_test(
6811
+ "non-admin is authenticated (-1)",
6812
+ sdkNonAdmin.test_authenticated,
6813
+ passOnAnyResult,
6814
+ )
6815
+ await async_test(
6816
+ "admin lock to past date",
6817
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: Date.now() - 1000 }),
6818
+ passOnAnyResult,
6819
+ )
6820
+ await async_test(
6821
+ "non-admin is authenticated (past date)",
6822
+ sdkNonAdmin.test_authenticated,
6823
+ passOnAnyResult,
6824
+ )
6825
+
6826
+ await async_test(
6827
+ "admin lock to 0 (indefinite)",
6828
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: 0 }),
6829
+ passOnAnyResult
6830
+ )
6831
+ await wait(undefined, 250)
6832
+ await async_test(
6833
+ "non-admin is de-authenticated when locked to 0",
6834
+ sdkNonAdmin.test_authenticated,
6835
+ handleAnyError,
6836
+ )
6837
+ await async_test(
6838
+ "non-admin can't authenciate when locked to 0",
6839
+ () => sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
6840
+ handleAnyError,
6841
+ )
6842
+ await async_test(
6843
+ "admin unlock to -1",
6844
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: -1 }),
6845
+ passOnAnyResult
6846
+ )
6847
+ await async_test(
6848
+ "non-admin can re authenciate when locked to 0",
6849
+ () => sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
6850
+ passOnAnyResult,
6851
+ )
6852
+ await async_test(
6853
+ "non-admin is authenticated",
6854
+ sdkNonAdmin.test_authenticated,
6855
+ passOnAnyResult,
6856
+ )
6857
+
6858
+ await async_test(
6859
+ "admin lock to future date",
6860
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: Date.now() + 10000 }),
6861
+ passOnAnyResult
6862
+ )
6863
+ await wait(undefined, 250)
6864
+ await async_test(
6865
+ "non-admin is de-authenticated when locked to future date",
6866
+ sdkNonAdmin.test_authenticated,
6867
+ handleAnyError,
6868
+ )
6869
+ await async_test(
6870
+ "non-admin can't authenciate when locked to future date",
6871
+ () => sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
6872
+ handleAnyError,
6873
+ )
6874
+ await async_test(
6875
+ "admin unlock to -1",
6876
+ () => sdk.api.users.updateOne(nonAdminId, { lockedOutUntil: -1 }),
6877
+ passOnAnyResult
6878
+ )
6879
+ await async_test(
6880
+ "non-admin can re authenciate when locked to future date",
6881
+ () => sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
6882
+ passOnAnyResult,
6883
+ )
6884
+ await async_test(
6885
+ "non-admin is authenticated",
6886
+ sdkNonAdmin.test_authenticated,
6887
+ passOnAnyResult,
6888
+ )
6889
+ }
6890
+
6621
6891
  (async () => {
6622
6892
  log_header("API")
6623
6893
 
@@ -6660,8 +6930,10 @@ const test_send_with_template = async () => {
6660
6930
  await mfa_tests()
6661
6931
  await setup_tests()
6662
6932
  await multi_tenant_tests() // should come right after setup tests
6663
- // await test_send_with_template()
6933
+ await lockout_tests()
6664
6934
  await self_serve_appointment_booking_tests()
6935
+ await delete_user_tests()
6936
+ // await test_send_with_template()
6665
6937
  await bulk_read_tests()
6666
6938
  await ticket_reminder_tests()
6667
6939
  await enduser_access_tags_tests()
Binary file