@tellescope/sdk 1.4.105 → 1.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/sdk",
3
- "version": "1.4.105",
3
+ "version": "1.5.1",
4
4
  "description": "Code for interacting with the Tellescope API",
5
5
  "main": "./lib/cjs/sdk.js",
6
6
  "module": "./lib/esm/sdk.js",
@@ -32,14 +32,14 @@
32
32
  },
33
33
  "homepage": "https://github.com/tellescope-os/tellescope#readme",
34
34
  "dependencies": {
35
- "@tellescope/constants": "^1.4.104",
36
- "@tellescope/schema": "^1.4.105",
37
- "@tellescope/testing": "^1.4.48",
38
- "@tellescope/types-client": "^1.4.104",
39
- "@tellescope/types-models": "^1.4.104",
40
- "@tellescope/types-utilities": "^1.4.27",
41
- "@tellescope/utilities": "^1.4.105",
42
- "@tellescope/validation": "^1.4.105",
35
+ "@tellescope/constants": "^1.5.1",
36
+ "@tellescope/schema": "^1.5.1",
37
+ "@tellescope/testing": "^1.5.1",
38
+ "@tellescope/types-client": "^1.5.1",
39
+ "@tellescope/types-models": "^1.5.1",
40
+ "@tellescope/types-utilities": "^1.5.1",
41
+ "@tellescope/utilities": "^1.5.1",
42
+ "@tellescope/validation": "^1.5.1",
43
43
  "axios": "^0.21.1",
44
44
  "dotenv": "^14.2.0",
45
45
  "express": "^4.17.1",
@@ -58,5 +58,5 @@
58
58
  "publishConfig": {
59
59
  "access": "public"
60
60
  },
61
- "gitHead": "f0dd59b66f81a25758d01848a94a211f1cebf6a4"
61
+ "gitHead": "d4235f7b61b4b067da331ea7149058871f53379b"
62
62
  }
package/src/sdk.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  SearchOptions,
14
14
  AccessPermissions,
15
15
  OrganizationLimits,
16
+ SortBy,
16
17
  } from "@tellescope/types-models"
17
18
 
18
19
  import {
@@ -38,6 +39,7 @@ export interface LoadFunctionArguments <T> {
38
39
  lastId?: string,
39
40
  limit?: number,
40
41
  sort?: SortOption,
42
+ sortBy?: SortBy,
41
43
  from?: Date | number,
42
44
  threadKey?: string,
43
45
  filter?: ReadFilter<T>,
@@ -2465,6 +2465,95 @@ export const formsUnsubmittedTest = async () => {
2465
2465
  ])
2466
2466
  }
2467
2467
 
2468
+ export const formsSubmittedNoUnsubmittedTest = async () => {
2469
+ log_header("formsSubmitted, with no unsubmitted branch, Tests")
2470
+
2471
+ const enduser = await sdk.api.endusers.createOne({ email: 'deletemeee@tellescope.com' })
2472
+ const journey = await sdk.api.journeys.createOne({ title: 'test journey '})
2473
+ const form = await sdk.api.forms.createOne({ title: 'test form' })
2474
+ const field = await sdk.api.form_fields.createOne({
2475
+ formId: form.id, title: 'question', type: 'string',
2476
+ previousFields: [{ type: 'root', info: {} }]
2477
+ })
2478
+
2479
+ // this action won't be fired, because patient isn't added to journey as part of tests
2480
+ const triggerStep = await sdk.api.automation_steps.createOne({
2481
+ journeyId: journey.id,
2482
+ events: [{ type: 'onJourneyStart', info: { } }],
2483
+ // in practice, this would send a form, so that the next step(s) could handle the response
2484
+ // but we don't want to send emails in testing, and can still attach this Id to a form response to test a trigger
2485
+ action: {
2486
+ type: 'setEnduserStatus',
2487
+ info: { status: 'start' },
2488
+ },
2489
+ })
2490
+
2491
+ // test for all forms submitted triggering update
2492
+ await sdk.api.automation_steps.createOne({
2493
+ journeyId: journey.id,
2494
+ events: [{
2495
+ type: 'formResponses',
2496
+ info: { automationStepId: triggerStep.id }
2497
+ }],
2498
+ action: {
2499
+ type: 'setEnduserStatus',
2500
+ info: { status: 'formsSubmitted' },
2501
+ },
2502
+ })
2503
+
2504
+ // simulates sending 2 outstanding forms to pt with expected follow-up
2505
+ await sdk.api.templates.get_templated_message({
2506
+ channel: 'Email',
2507
+ enduserId: enduser.id,
2508
+ message: `{{forms.${form.id}.link:title}} {{forms.${form.id}.link:title}}`,
2509
+ userId: sdk.userInfo.id,
2510
+ automationStepId: triggerStep.id,
2511
+ })
2512
+
2513
+ const form_responses = await sdk.api.form_responses.getSome()
2514
+
2515
+ // trigger submission
2516
+ await sdk.api.form_responses.submit_form_response({ accessCode: form_responses[0].accessCode!, automationStepId: triggerStep.id, responses: [{
2517
+ answer: {
2518
+ type: 'string',
2519
+ value: 'answer'
2520
+ },
2521
+ fieldId: field.id,
2522
+ fieldTitle: field.title,
2523
+ }] })
2524
+ await wait(undefined, 5000) // allow background creation with generous pause
2525
+
2526
+ await async_test(
2527
+ `formResponses not triggered yet after 1 form remaining`,
2528
+ () => sdk.api.endusers.getOne(enduser.id),
2529
+ { onResult: e => e?.journeys?.[journey.id] !== 'formsSubmitted' }
2530
+ )
2531
+
2532
+ await sdk.api.form_responses.submit_form_response({ accessCode: form_responses[1].accessCode!, automationStepId: triggerStep.id, responses: [{
2533
+ answer: {
2534
+ type: 'string',
2535
+ value: 'answer'
2536
+ },
2537
+ fieldId: field.id,
2538
+ fieldTitle: field.title,
2539
+ }] })
2540
+
2541
+ await wait(undefined, 5000) // allow background creation with generous pause
2542
+
2543
+ await async_test(
2544
+ `formResponses triggered after both forms submitted`,
2545
+ () => sdk.api.endusers.getOne(enduser.id),
2546
+ { onResult: e => e?.journeys?.[journey.id] === 'formsSubmitted' }
2547
+ )
2548
+
2549
+ await Promise.all([
2550
+ sdk.api.forms.deleteOne(form.id),
2551
+ sdk.api.journeys.deleteOne(journey.id),
2552
+ sdk.api.endusers.deleteOne(enduser.id)
2553
+ ])
2554
+ }
2555
+
2556
+
2468
2557
  // ensure child steps come from the same journey
2469
2558
  export const automationSameJourneyTests = async () => {
2470
2559
  log_header("automationSameJourney")
@@ -2533,6 +2622,14 @@ const addToJourneyTests = async () => {
2533
2622
 
2534
2623
  // add to journey and re-add
2535
2624
  await sdk.api.endusers.add_to_journey({ enduserIds: [enduser.id], journeyId: journey.id })
2625
+
2626
+ await wait (undefined, 250)
2627
+ await async_test(
2628
+ `Journey state correctly set by add_to_journey (to default state)`,
2629
+ () => sdk.api.endusers.getOne(enduser.id),
2630
+ { onResult: e => e.journeys?.[journey.id] === 'New' }
2631
+ )
2632
+
2536
2633
  await wait(undefined, 4000) // allow onJourneyStart step to trigger
2537
2634
  await sdk.api.endusers.add_to_journey({ enduserIds: [enduser.id], journeyId: journey.id })
2538
2635
  await wait(undefined, 4000) // allow onJourneyStart step to trigger
@@ -2555,6 +2652,7 @@ const addToJourneyTests = async () => {
2555
2652
 
2556
2653
  const automation_events_tests = async () => {
2557
2654
  log_header("Automation Events")
2655
+ await formsSubmittedNoUnsubmittedTest()
2558
2656
  await automationSameJourneyTests()
2559
2657
  await formsUnsubmittedTest()
2560
2658
  await formsUnsubmittedCancelConditionTest()
@@ -3795,11 +3893,11 @@ const auto_reply_tests = async () => {
3795
3893
 
3796
3894
  const NO_TEST = () => {}
3797
3895
  const tests: { [K in keyof ClientModelForName]: () => void } = {
3896
+ automation_steps: automation_events_tests,
3798
3897
  background_errors: NO_TEST,
3799
3898
  enduser_views: NO_TEST,
3800
3899
  availability_blocks: NO_TEST,
3801
3900
  analytics_frames: NO_TEST,
3802
- automation_steps: automation_events_tests,
3803
3901
  products: NO_TEST,
3804
3902
  purchase_credits: NO_TEST,
3805
3903
  purchases: NO_TEST,
@@ -293,6 +293,74 @@ const sub_organization_tests = async (isSubscribed: boolean) => {
293
293
  await sdk.api.endusers.deleteOne(enduserSub.id)
294
294
  }
295
295
 
296
+
297
+ const form_response_tests = async (isSubscribed: boolean) => {
298
+ log_header(`Form Response Tests, isSubscribed=${isSubscribed}`)
299
+
300
+ if (isSubscribed) {
301
+ await sdk.api.webhooks.update({ subscriptionUpdates: {
302
+ ...emptySubscription,
303
+ form_responses: { create: true },
304
+ }})
305
+ }
306
+
307
+ const form = await sdk.api.forms.createOne({ title: 'test form' })
308
+ const field = await sdk.api.form_fields.createOne({
309
+ title: 'test',
310
+ formId: form.id,
311
+ type: 'string',
312
+ previousFields: [],
313
+ })
314
+
315
+ const enduser = await sdk.api.endusers.createOne({ email: 'deleteme@tellescope.com' })
316
+ const { accessCode } = await sdk.api.form_responses.prepare_form_response({
317
+ enduserId: enduser.id,
318
+ formId: form.id,
319
+ })
320
+
321
+ const { formResponse } = await sdk.api.form_responses.submit_form_response({
322
+ accessCode,
323
+ responses: [
324
+ {
325
+ fieldId: field.id,
326
+ fieldTitle: 'test',
327
+ answer: {
328
+ type: 'string',
329
+ value: 'testing value',
330
+ }
331
+ }
332
+ ]
333
+ })
334
+
335
+ await check_next_webhook(
336
+ a => {
337
+ const hook = a.records[0]
338
+
339
+ return (
340
+ hook.id === formResponse.id
341
+ && hook.businessId === formResponse.businessId
342
+ && hook.enduserId === formResponse.enduserId
343
+ && objects_equivalent(formResponse.responses, hook.responses)
344
+ )
345
+ },
346
+ 'Form response on submit error', 'Form response on submit', isSubscribed
347
+ )
348
+
349
+ // cleanup
350
+ if (isSubscribed) {
351
+ await sdk.api.webhooks.update({ subscriptionUpdates: {
352
+ ...emptySubscription,
353
+ chats: { create: true },
354
+ meetings: { create: true, update: true, delete: false },
355
+ }})
356
+ }
357
+
358
+ await Promise.all([
359
+ sdk.api.endusers.deleteOne(enduser.id),
360
+ sdk.api.forms.deleteOne(form.id),
361
+ ])
362
+ }
363
+
296
364
  const AUTOMATION_POLLING_DELAY_MS = 3000 - CHECK_WEBHOOK_DELAY_MS
297
365
  const test_automation_webhooks = async () => {
298
366
  log_header("Automation Events")
@@ -437,6 +505,7 @@ const calendar_event_reminders_tests = async (isSubscribed: boolean) => {
437
505
  }
438
506
 
439
507
  const tests: { [K in WebhookSupportedModel | 'calendarEventReminders' | 'sub']?: (isSubscribed: boolean) => Promise<void> } = {
508
+ form_responses: form_response_tests,
440
509
  sub: sub_organization_tests,
441
510
  endusers: endusers_tests,
442
511
  chats: chats_tests,