@tellescope/sdk 1.256.0 → 1.256.2

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 (59) hide show
  1. package/lib/cjs/sdk.d.ts +2 -2
  2. package/lib/cjs/tests/api_tests/appointment_link_expiration.test.d.ts +6 -0
  3. package/lib/cjs/tests/api_tests/appointment_link_expiration.test.d.ts.map +1 -0
  4. package/lib/cjs/tests/api_tests/appointment_link_expiration.test.js +163 -0
  5. package/lib/cjs/tests/api_tests/appointment_link_expiration.test.js.map +1 -0
  6. package/lib/cjs/tests/api_tests/beluga_trigger_refill.test.d.ts +6 -0
  7. package/lib/cjs/tests/api_tests/beluga_trigger_refill.test.d.ts.map +1 -0
  8. package/lib/cjs/tests/api_tests/beluga_trigger_refill.test.js +224 -0
  9. package/lib/cjs/tests/api_tests/beluga_trigger_refill.test.js.map +1 -0
  10. package/lib/cjs/tests/api_tests/embeddables_auth_token.test.d.ts +6 -0
  11. package/lib/cjs/tests/api_tests/embeddables_auth_token.test.d.ts.map +1 -0
  12. package/lib/cjs/tests/api_tests/embeddables_auth_token.test.js +354 -0
  13. package/lib/cjs/tests/api_tests/embeddables_auth_token.test.js.map +1 -0
  14. package/lib/cjs/tests/api_tests/start_ai_conversation.test.d.ts +6 -0
  15. package/lib/cjs/tests/api_tests/start_ai_conversation.test.d.ts.map +1 -0
  16. package/lib/cjs/tests/api_tests/start_ai_conversation.test.js +351 -0
  17. package/lib/cjs/tests/api_tests/start_ai_conversation.test.js.map +1 -0
  18. package/lib/cjs/tests/tests.d.ts.map +1 -1
  19. package/lib/cjs/tests/tests.js +217 -189
  20. package/lib/cjs/tests/tests.js.map +1 -1
  21. package/lib/cjs/tests/unit_tests/phone_validation.test.d.ts +3 -0
  22. package/lib/cjs/tests/unit_tests/phone_validation.test.d.ts.map +1 -0
  23. package/lib/cjs/tests/unit_tests/phone_validation.test.js +96 -0
  24. package/lib/cjs/tests/unit_tests/phone_validation.test.js.map +1 -0
  25. package/lib/esm/sdk.d.ts +2 -2
  26. package/lib/esm/tests/api_tests/appointment_link_expiration.test.d.ts +6 -0
  27. package/lib/esm/tests/api_tests/appointment_link_expiration.test.d.ts.map +1 -0
  28. package/lib/esm/tests/api_tests/appointment_link_expiration.test.js +156 -0
  29. package/lib/esm/tests/api_tests/appointment_link_expiration.test.js.map +1 -0
  30. package/lib/esm/tests/api_tests/beluga_trigger_refill.test.d.ts +6 -0
  31. package/lib/esm/tests/api_tests/beluga_trigger_refill.test.d.ts.map +1 -0
  32. package/lib/esm/tests/api_tests/beluga_trigger_refill.test.js +220 -0
  33. package/lib/esm/tests/api_tests/beluga_trigger_refill.test.js.map +1 -0
  34. package/lib/esm/tests/api_tests/embeddables_auth_token.test.d.ts +6 -0
  35. package/lib/esm/tests/api_tests/embeddables_auth_token.test.d.ts.map +1 -0
  36. package/lib/esm/tests/api_tests/embeddables_auth_token.test.js +347 -0
  37. package/lib/esm/tests/api_tests/embeddables_auth_token.test.js.map +1 -0
  38. package/lib/esm/tests/api_tests/start_ai_conversation.test.d.ts +6 -0
  39. package/lib/esm/tests/api_tests/start_ai_conversation.test.d.ts.map +1 -0
  40. package/lib/esm/tests/api_tests/start_ai_conversation.test.js +347 -0
  41. package/lib/esm/tests/api_tests/start_ai_conversation.test.js.map +1 -0
  42. package/lib/esm/tests/tests.d.ts.map +1 -1
  43. package/lib/esm/tests/tests.js +217 -189
  44. package/lib/esm/tests/tests.js.map +1 -1
  45. package/lib/esm/tests/unit_tests/phone_validation.test.d.ts +3 -0
  46. package/lib/esm/tests/unit_tests/phone_validation.test.d.ts.map +1 -0
  47. package/lib/esm/tests/unit_tests/phone_validation.test.js +93 -0
  48. package/lib/esm/tests/unit_tests/phone_validation.test.js.map +1 -0
  49. package/lib/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +10 -10
  51. package/src/tests/api_tests/appointment_link_expiration.test.ts +92 -0
  52. package/src/tests/api_tests/beluga_trigger_refill.test.ts +152 -0
  53. package/src/tests/api_tests/embeddables_auth_token.test.ts +417 -0
  54. package/src/tests/api_tests/security/F-0015-webhook-outbound-ssrf.test.ts +292 -0
  55. package/src/tests/api_tests/security/F-0025-proxy-image-unauth-ssrf.test.ts +179 -0
  56. package/src/tests/api_tests/start_ai_conversation.test.ts +256 -0
  57. package/src/tests/tests.ts +14 -0
  58. package/src/tests/unit_tests/phone_validation.test.ts +108 -0
  59. package/test_generated.pdf +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/sdk",
3
- "version": "1.256.0",
3
+ "version": "1.256.2",
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.256.0",
36
- "@tellescope/schema": "1.256.0",
37
- "@tellescope/testing": "1.256.0",
38
- "@tellescope/types-client": "1.256.0",
39
- "@tellescope/types-models": "1.256.0",
40
- "@tellescope/types-utilities": "1.256.0",
41
- "@tellescope/utilities": "1.256.0",
42
- "@tellescope/validation": "1.256.0",
35
+ "@tellescope/constants": "1.256.2",
36
+ "@tellescope/schema": "1.256.2",
37
+ "@tellescope/testing": "1.256.2",
38
+ "@tellescope/types-client": "1.256.2",
39
+ "@tellescope/types-models": "1.256.2",
40
+ "@tellescope/types-utilities": "1.256.2",
41
+ "@tellescope/utilities": "1.256.2",
42
+ "@tellescope/validation": "1.256.2",
43
43
  "axios": "0.30.3",
44
44
  "dotenv": "14.3.2",
45
45
  "form-data": "4.0.4",
@@ -55,5 +55,5 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  },
58
- "gitHead": "192f635da723d16ea20c4517d932da211110ffd5"
58
+ "gitHead": "a796b01e2a6ccc1f40aeb07084d8b8922e4d078e"
59
59
  }
@@ -0,0 +1,92 @@
1
+ require('source-map-support').install();
2
+
3
+ import axios from "axios"
4
+
5
+ import { Session } from "../../sdk"
6
+ import { log_header, async_test } from "@tellescope/testing"
7
+ import { setup_tests } from "../setup"
8
+
9
+ const host = process.env.API_URL || 'http://localhost:8080'
10
+
11
+ const ONE_DAY_IN_SECONDS = 86400
12
+ const EVENT_DAYS_OUT = 120 // under the old expiry (event lead time + 4 weeks) this token lived ~148 days
13
+
14
+ // Decode a JWT payload WITHOUT verifying it — the signing key is server-side only, and the only
15
+ // thing under test is the lifetime the server stamped on the token.
16
+ const decode_jwt_payload = (token: string) => {
17
+ const [, payload] = token.split('.')
18
+ if (!payload) throw new Error("Not a JWT")
19
+ return JSON.parse(
20
+ Buffer.from(payload.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')
21
+ ) as { iat: number, exp: number }
22
+ }
23
+
24
+ // The API returns a /r/<token> shortlink, not the destination — follow one hop and pull the
25
+ // `token` query param out of the URL the patient actually lands on.
26
+ const resolve_redirect_token = async (link: string) => {
27
+ const { status, headers } = await axios.get(link, {
28
+ maxRedirects: 0,
29
+ validateStatus: () => true,
30
+ })
31
+ const location = headers['location']
32
+ if (!location) throw new Error(`Expected a redirect from ${link}, got status ${status}`)
33
+
34
+ const token = new URL(location).searchParams.get('token')
35
+ if (!token) throw new Error(`No token query param in redirect destination: ${location}`)
36
+
37
+ return token
38
+ }
39
+
40
+ export const appointment_link_expiration_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
41
+ log_header("Appointment Link Expiration")
42
+
43
+ const enduser = await sdk.api.endusers.createOne({
44
+ email: `appointment-link-expiration-${Date.now()}@tellescope.com`,
45
+ })
46
+ const event = await sdk.api.calendar_events.createOne({
47
+ title: 'Appointment Link Expiration Test',
48
+ durationInMinutes: 30,
49
+ startTimeInMS: Date.now() + EVENT_DAYS_OUT * ONE_DAY_IN_SECONDS * 1000,
50
+ enableVideoCall: true,
51
+ attendees: [{ type: 'enduser', id: enduser.id }],
52
+ })
53
+
54
+ try {
55
+ const { link } = await sdk.api.calendar_events.generate_meeting_link({
56
+ eventId: event.id,
57
+ enduserId: enduser.id,
58
+ })
59
+ const { iat, exp } = decode_jwt_payload(await resolve_redirect_token(link))
60
+ const lifetimeInSeconds = exp - iat
61
+
62
+ await async_test(
63
+ `meeting link token for an event ${EVENT_DAYS_OUT} days out expires within 24h`,
64
+ async () => lifetimeInSeconds,
65
+ { onResult: (lifetime: number) => lifetime > 0 && lifetime <= ONE_DAY_IN_SECONDS },
66
+ )
67
+ } finally {
68
+ await sdk.api.calendar_events.deleteOne(event.id).catch(console.error)
69
+ await sdk.api.endusers.deleteOne(enduser.id).catch(console.error)
70
+ }
71
+ }
72
+
73
+ // Allow running this test file independently
74
+ if (require.main === module) {
75
+ const sdk = new Session({ host })
76
+ const sdkNonAdmin = new Session({ host })
77
+
78
+ const runTests = async () => {
79
+ await setup_tests(sdk, sdkNonAdmin)
80
+ await appointment_link_expiration_tests({ sdk, sdkNonAdmin })
81
+ }
82
+
83
+ runTests()
84
+ .then(() => {
85
+ console.log("✅ Appointment link expiration test suite completed successfully")
86
+ process.exit(0)
87
+ })
88
+ .catch((error) => {
89
+ console.error("❌ Appointment link expiration test suite failed:", error)
90
+ process.exit(1)
91
+ })
92
+ }
@@ -0,0 +1,152 @@
1
+ require('source-map-support').install();
2
+
3
+ import { Session } from "../../sdk"
4
+ import {
5
+ async_test,
6
+ log_header,
7
+ passOnAnyResult,
8
+ } from "@tellescope/testing"
9
+ import { setup_tests } from "../setup"
10
+
11
+ const host = process.env.API_URL || 'http://localhost:8080' as const
12
+
13
+ // Beluga Trigger Refill journey action tests (CU-86e2gbv7y).
14
+ //
15
+ // Validator-acceptance only: verifies that automation steps configured with the new
16
+ // belugaTriggerRefill action (org-mapping and inline-medIds variants) pass validation, and that
17
+ // invalid shapes are rejected. No live Beluga call is made — external/triggerRefill requires
18
+ // sandbox credentials, and the process endpoint's guard branches (missing integration, missing
19
+ // preferences) mirror the already-tested belugaAutoRx/belugaUpdateVisit handlers.
20
+ export const beluga_trigger_refill_tests = async ({ sdk, sdkNonAdmin }: { sdk: Session, sdkNonAdmin: Session }) => {
21
+ log_header("Beluga Trigger Refill Journey Action Tests")
22
+
23
+ let journeyId: string | undefined
24
+ let formId: string | undefined
25
+ const stepIds: string[] = []
26
+
27
+ try {
28
+ const journey = await sdk.api.journeys.createOne({ title: 'Beluga Trigger Refill Test Journey' })
29
+ journeyId = journey.id
30
+
31
+ const form = await sdk.api.forms.createOne({ title: 'Beluga Trigger Refill Test Form' })
32
+ formId = form.id
33
+
34
+ // Inline med IDs variant
35
+ await async_test(
36
+ "belugaTriggerRefill step accepted (inline medIds)",
37
+ () => sdk.api.automation_steps.createOne({
38
+ journeyId: journey.id,
39
+ events: [{ type: 'onJourneyStart', info: {} }],
40
+ action: {
41
+ type: 'belugaTriggerRefill',
42
+ info: {
43
+ formId: form.id,
44
+ patientPreferences: [{ medId: 'med-123' }, { medId: 'med-456' }],
45
+ customFieldName: 'Refill Medication',
46
+ },
47
+ },
48
+ }).then(s => { stepIds.push(s.id); return s }),
49
+ passOnAnyResult,
50
+ )
51
+
52
+ // Organization mapping variant
53
+ await async_test(
54
+ "belugaTriggerRefill step accepted (organization mapping)",
55
+ () => sdk.api.automation_steps.createOne({
56
+ journeyId: journey.id,
57
+ events: [{ type: 'onJourneyStart', info: {} }],
58
+ action: {
59
+ type: 'belugaTriggerRefill',
60
+ info: {
61
+ formId: form.id,
62
+ useOrganizationMapping: true,
63
+ },
64
+ },
65
+ }).then(s => { stepIds.push(s.id); return s }),
66
+ passOnAnyResult,
67
+ )
68
+
69
+ // Invalid formId (not a mongo id) rejected
70
+ await async_test(
71
+ "belugaTriggerRefill step rejected (invalid formId)",
72
+ () => sdk.api.automation_steps.createOne({
73
+ journeyId: journey.id,
74
+ events: [{ type: 'onJourneyStart', info: {} }],
75
+ action: {
76
+ type: 'belugaTriggerRefill',
77
+ info: {
78
+ formId: 'not-a-mongo-id',
79
+ patientPreferences: [{ medId: 'med-123' }],
80
+ },
81
+ } as any,
82
+ }),
83
+ { shouldError: true, onError: () => true },
84
+ )
85
+
86
+ // Missing formId rejected
87
+ await async_test(
88
+ "belugaTriggerRefill step rejected (missing formId)",
89
+ () => sdk.api.automation_steps.createOne({
90
+ journeyId: journey.id,
91
+ events: [{ type: 'onJourneyStart', info: {} }],
92
+ action: {
93
+ type: 'belugaTriggerRefill',
94
+ info: {
95
+ patientPreferences: [{ medId: 'med-123' }],
96
+ },
97
+ } as any,
98
+ }),
99
+ { shouldError: true, onError: () => true },
100
+ )
101
+
102
+ // Unexpected fields in a patient preference are stripped by objectValidator, not rejected —
103
+ // assert they never reach the stored config (the step itself is accepted)
104
+ await async_test(
105
+ "belugaTriggerRefill step strips unexpected patientPreferences field",
106
+ () => sdk.api.automation_steps.createOne({
107
+ journeyId: journey.id,
108
+ events: [{ type: 'onJourneyStart', info: {} }],
109
+ action: {
110
+ type: 'belugaTriggerRefill',
111
+ info: {
112
+ formId: form.id,
113
+ patientPreferences: [{ medId: 'med-123', pharmacyId: 'not-allowed' }],
114
+ },
115
+ } as any,
116
+ }).then(s => { stepIds.push(s.id); return s }),
117
+ {
118
+ onResult: s => {
119
+ const preference = (s.action.info as any).patientPreferences?.[0]
120
+ return preference?.medId === 'med-123' && preference?.pharmacyId === undefined
121
+ },
122
+ },
123
+ )
124
+ } finally {
125
+ for (const id of stepIds) {
126
+ await sdk.api.automation_steps.deleteOne(id).catch(console.error)
127
+ }
128
+ if (formId) await sdk.api.forms.deleteOne(formId).catch(console.error)
129
+ if (journeyId) await sdk.api.journeys.deleteOne(journeyId).catch(console.error)
130
+ }
131
+ }
132
+
133
+ if (require.main === module) {
134
+ console.log(`Using API URL: ${host}`)
135
+ const sdk = new Session({ host })
136
+ const sdkNonAdmin = new Session({ host })
137
+
138
+ const runTests = async () => {
139
+ await setup_tests(sdk, sdkNonAdmin)
140
+ await beluga_trigger_refill_tests({ sdk, sdkNonAdmin })
141
+ }
142
+
143
+ runTests()
144
+ .then(() => {
145
+ console.log("✅ Beluga trigger refill test suite completed successfully")
146
+ process.exit(0)
147
+ })
148
+ .catch((error) => {
149
+ console.error("❌ Beluga trigger refill test suite failed:", error)
150
+ process.exit(1)
151
+ })
152
+ }