@tellescope/sdk 0.0.16 → 0.0.20

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 (48) hide show
  1. package/lib/cjs/enduser.d.ts +8 -3
  2. package/lib/cjs/enduser.d.ts.map +1 -1
  3. package/lib/cjs/enduser.js +6 -3
  4. package/lib/cjs/enduser.js.map +1 -1
  5. package/lib/cjs/sdk.d.ts +10 -6
  6. package/lib/cjs/sdk.d.ts.map +1 -1
  7. package/lib/cjs/sdk.js +7 -6
  8. package/lib/cjs/sdk.js.map +1 -1
  9. package/lib/cjs/session.d.ts +4 -21
  10. package/lib/cjs/session.d.ts.map +1 -1
  11. package/lib/cjs/session.js +1 -0
  12. package/lib/cjs/session.js.map +1 -1
  13. package/lib/cjs/tests/public_endpoint_tests.js +1 -1
  14. package/lib/cjs/tests/public_endpoint_tests.js.map +1 -1
  15. package/lib/cjs/tests/socket_tests.d.ts +1 -1
  16. package/lib/cjs/tests/socket_tests.d.ts.map +1 -1
  17. package/lib/cjs/tests/socket_tests.js +124 -7
  18. package/lib/cjs/tests/socket_tests.js.map +1 -1
  19. package/lib/cjs/tests/tests.js +147 -107
  20. package/lib/cjs/tests/tests.js.map +1 -1
  21. package/lib/esm/enduser.d.ts +8 -3
  22. package/lib/esm/enduser.d.ts.map +1 -1
  23. package/lib/esm/enduser.js +6 -3
  24. package/lib/esm/enduser.js.map +1 -1
  25. package/lib/esm/sdk.d.ts +10 -6
  26. package/lib/esm/sdk.d.ts.map +1 -1
  27. package/lib/esm/sdk.js +7 -6
  28. package/lib/esm/sdk.js.map +1 -1
  29. package/lib/esm/session.d.ts +4 -21
  30. package/lib/esm/session.d.ts.map +1 -1
  31. package/lib/esm/session.js +1 -0
  32. package/lib/esm/session.js.map +1 -1
  33. package/lib/esm/tests/public_endpoint_tests.js +1 -1
  34. package/lib/esm/tests/public_endpoint_tests.js.map +1 -1
  35. package/lib/esm/tests/socket_tests.d.ts +1 -1
  36. package/lib/esm/tests/socket_tests.d.ts.map +1 -1
  37. package/lib/esm/tests/socket_tests.js +122 -7
  38. package/lib/esm/tests/socket_tests.js.map +1 -1
  39. package/lib/esm/tests/tests.js +147 -107
  40. package/lib/esm/tests/tests.js.map +1 -1
  41. package/lib/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +11 -11
  43. package/src/enduser.ts +12 -7
  44. package/src/sdk.ts +23 -13
  45. package/src/session.ts +3 -23
  46. package/src/tests/public_endpoint_tests.ts +1 -1
  47. package/src/tests/socket_tests.ts +67 -4
  48. package/src/tests/tests.ts +52 -31
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@tellescope/sdk",
3
- "version": "0.0.16",
3
+ "version": "0.0.20",
4
4
  "description": "Code for interacting with the Tellescope API",
5
5
  "main": "./lib/cjs/sdk.js",
6
6
  "module": "./lib/esm/sdk.js",
7
7
  "types": "./lib/esm/sdk.d.ts",
8
8
  "scripts": {
9
9
  "test": "npm run-script build:cjs && npm run-script retest",
10
- "retest": "npm run-script retest-sockets && npm run-script retest-api && npm run-script retest-public-api",
10
+ "retest": "npm run-script retest-api && npm run-script retest-public-api && npm run-script retest-sockets",
11
11
  "test-api": "npm run-script build:cjs && npm run-script retest-api",
12
12
  "retest-api": "node lib/cjs/tests/tests.js",
13
13
  "test-public-api": "npm run-script build:cjs && npm run-script retest-public-api",
@@ -30,14 +30,14 @@
30
30
  },
31
31
  "homepage": "https://github.com/tellescope-os/tellescope#readme",
32
32
  "dependencies": {
33
- "@tellescope/constants": "^0.0.16",
34
- "@tellescope/schema": "^0.0.16",
35
- "@tellescope/testing": "^0.0.16",
36
- "@tellescope/types-client": "^0.0.16",
37
- "@tellescope/types-models": "^0.0.16",
38
- "@tellescope/types-utilities": "^0.0.16",
39
- "@tellescope/utilities": "^0.0.16",
40
- "@tellescope/validation": "^0.0.16",
33
+ "@tellescope/constants": "^0.0.20",
34
+ "@tellescope/schema": "^0.0.20",
35
+ "@tellescope/testing": "^0.0.20",
36
+ "@tellescope/types-client": "^0.0.20",
37
+ "@tellescope/types-models": "^0.0.20",
38
+ "@tellescope/types-utilities": "^0.0.20",
39
+ "@tellescope/utilities": "^0.0.20",
40
+ "@tellescope/validation": "^0.0.20",
41
41
  "axios": "^0.21.1",
42
42
  "form-data": "^4.0.0",
43
43
  "socket.io-client": "^4.2.0",
@@ -53,5 +53,5 @@
53
53
  "publishConfig": {
54
54
  "access": "public"
55
55
  },
56
- "gitHead": "06e581f4d3a6c5b57fd0cfcc22103b94125f9da4"
56
+ "gitHead": "99ef9475f430b7021166b8f47f9863c2e1fed8aa"
57
57
  }
package/src/enduser.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { io } from 'socket.io-client'
2
2
 
3
- import { Session, SessionOptions, APIQuery } from "./session"
3
+ import { Session, SessionOptions } from "./session"
4
+ import { APIQuery } from "./sdk"
4
5
  import { url_safe_path } from "@tellescope/utilities"
5
6
 
6
7
  import { S3PresignedPost, UserIdentity } from "@tellescope/types-utilities"
@@ -14,7 +15,6 @@ import {
14
15
  Enduser,
15
16
  File,
16
17
  } from "@tellescope/types-client"
17
- import { stringValidator } from "@tellescope/validation";
18
18
 
19
19
  export interface EnduserSessionOptions extends SessionOptions {}
20
20
 
@@ -30,8 +30,9 @@ export const defaultQueries = <N extends keyof ClientModelForName>(
30
30
  return {
31
31
  createOne: o => s._POST(`/v1/${singularName}`, o),
32
32
  createSome: os => s._POST(`/v1/${safeName}`, { create: os }),
33
- getOne: (id, filter) => s._GET(`/v1/${singularName}/${id}`, { filter }),
34
- getSome: (o) => s._GET(`/v1/${safeName}`, o),
33
+ getOne: (argument) => typeof argument === 'string' ? s._GET(`/v1/${singularName}/${argument}`)
34
+ : s._GET(`/v1/${singularName}`, { filter: argument}),
35
+ getSome: o => s._GET(`/v1/${safeName}`, o),
35
36
  updateOne: (id, updates, options) => s._PATCH(`/v1/${singularName}/${id}`, { updates, options }),
36
37
  deleteOne: id => s._DELETE(`/v1/${singularName}/${id}`),
37
38
  }
@@ -67,8 +68,9 @@ export class EnduserSession extends Session {
67
68
  userInfo!: Enduser;
68
69
  api: EnduserQueries;
69
70
 
70
- constructor(o?: EnduserSessionOptions) {
71
+ constructor(o?: EnduserSessionOptions & { enduser?: Enduser }) {
71
72
  super({ ...o, cacheKey: o?.cacheKey || "tellescope_enduser" })
73
+ if (o?.enduser) this.userInfo = o.enduser
72
74
 
73
75
  this.api = loadDefaultQueries(this) as EnduserQueries
74
76
 
@@ -124,8 +126,11 @@ export class EnduserSession extends Session {
124
126
  return { authToken, enduser }
125
127
  }
126
128
 
127
- authenticate = async (email: string, password: string) => this.handle_new_session(
128
- await this.POST<{email: string, password: string }, { authToken: string, enduser: Enduser }>('/v1/login-enduser', { email, password })
129
+ authenticate = async (email: string, password: string, o?: { expirationInSeconds?: number }) => this.handle_new_session(
130
+ await this.POST<
131
+ {email: string, password: string, expirationInSeconds?: number },
132
+ { authToken: string, enduser: Enduser }
133
+ >('/v1/login-enduser', { email, password, ...o })
129
134
  )
130
135
 
131
136
  refresh_session = async () => {
package/src/sdk.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  AttendeeInfo,
3
3
  JourneyState,
4
- MeetingStatus,
5
4
  Meeting,
6
5
  UserSession,
7
6
  MeetingInfo,
7
+ ReadFilter,
8
8
  } from "@tellescope/types-models"
9
9
 
10
10
  import {
@@ -19,12 +19,18 @@ import {
19
19
  import { CustomUpdateOptions, SortOption, S3PresignedPost, UserIdentity } from "@tellescope/types-utilities"
20
20
  import { url_safe_path } from "@tellescope/utilities"
21
21
 
22
- import { Session as SessionManager, SessionOptions, Filter } from "./session"
22
+ import { Session as SessionManager, SessionOptions } from "./session"
23
23
 
24
24
  export * from "./public"
25
25
  export * from "./enduser"
26
26
 
27
- export type LoadFunction<T> = (o?: { lastId?: string, limit?: number, sort?: SortOption, threadKey?: string, filter?: Filter<Partial<T>> }) => Promise<T[]>
27
+ export type LoadFunction<T> = (o?: {
28
+ lastId?: string,
29
+ limit?: number,
30
+ sort?: SortOption,
31
+ threadKey?: string,
32
+ filter?: ReadFilter<T>,
33
+ }) => Promise<T[]>
28
34
 
29
35
  export interface APIQuery<
30
36
  N extends keyof ClientModelForName,
@@ -36,7 +42,7 @@ export interface APIQuery<
36
42
  {
37
43
  createOne: (t: CREATE) => Promise<T>;
38
44
  createSome: (ts: CREATE[]) => Promise<{ created: T[], errors: object[] }>;
39
- getOne: (id: string, filter?: Filter<Partial<T>>) => Promise<T>;
45
+ getOne: (argument: string | ReadFilter<T>) => Promise<T>;
40
46
  getSome: LoadFunction<T>;
41
47
  updateOne: (id: string, updates: UPDATE, options?: CustomUpdateOptions) => Promise<T>;
42
48
  deleteOne: (id: string) => Promise<void>;
@@ -52,7 +58,8 @@ export const defaultQueries = <N extends keyof ClientModelForName>(
52
58
  return {
53
59
  createOne: o => s._POST(`/v1/${singularName}`, o),
54
60
  createSome: os => s._POST(`/v1/${safeName}`, { create: os }),
55
- getOne: (id, filter) => s._GET(`/v1/${singularName}/${id}`, { filter }),
61
+ getOne: (argument) => typeof argument === 'string' ? s._GET(`/v1/${singularName}/${argument}`)
62
+ : s._GET(`/v1/${singularName}`, { filter: argument }),
56
63
  getSome: (o) => s._GET(`/v1/${safeName}`, o),
57
64
  updateOne: (id, updates, options) => s._PATCH(`/v1/${singularName}/${id}`, { updates, options }),
58
65
  deleteOne: id => s._DELETE(`/v1/${singularName}/${id}`),
@@ -109,8 +116,10 @@ export class Session extends SessionManager {
109
116
  api: Queries;
110
117
  userInfo!: UserSession;
111
118
 
112
- constructor(o?: SessionOptions) {
119
+ constructor(o?: SessionOptions & { userInfo?: UserSession }) {
113
120
  super({ ...o, cacheKey: o?.cacheKey || "tellescope_user" })
121
+ if (o?.userInfo) this.userInfo = o.userInfo
122
+
114
123
  const queries = loadDefaultQueries(this) as Queries
115
124
 
116
125
  queries.journeys.update_state = ({id, name, updates}) => this._PATCH(`/v1/journey/${id}/state/${name}`, { updates })
@@ -173,13 +182,14 @@ export class Session extends SessionManager {
173
182
  if (this.AUTO_REFRESH_MS < elapsedSessionMS) { return await this.refresh_session()}
174
183
  }
175
184
 
176
- authenticate = async (email: string, password: string, url?: string) => {
177
- if (url) this.host = url
178
-
179
- return this.handle_new_session(
180
- await this.POST<{email: string, password: string }, UserSession & { authToken: string }>('/submit-login', { email, password })
181
- )
182
- }
185
+ authenticate = async (email: string, password: string, o?: { expirationInSeconds?: number }) => (
186
+ this.handle_new_session(
187
+ await this.POST<
188
+ {email: string, password: string, expirationInSeconds?: number },
189
+ UserSession & { authToken: string }
190
+ >('/submit-login', { email, password, ...o })
191
+ )
192
+ )
183
193
  logout = async () => {
184
194
  this.clearState()
185
195
  await this.POST('/logout-api').catch(console.error)
package/src/session.ts CHANGED
@@ -3,16 +3,11 @@ import NodeFormData from "form-data"
3
3
  import { Socket, io } from 'socket.io-client'
4
4
 
5
5
  import {
6
- CustomUpdateOptions,
7
6
  FileBlob,
8
- SortOption,
9
7
  S3PresignedPost,
10
8
  } from "@tellescope/types-utilities"
11
9
  import {
12
10
  ClientModelForName,
13
- ClientModelForName_required,
14
- ClientModelForName_readonly,
15
- ClientModelForName_updatesDisabled
16
11
  } from "@tellescope/types-client"
17
12
 
18
13
  export const DEFAULT_HOST = 'https://api.tellescope.com'
@@ -22,6 +17,7 @@ export interface SessionOptions {
22
17
  authToken?: string;
23
18
  host?: string;
24
19
  cacheKey?: string;
20
+ expirationInSeconds?: number,
25
21
  handleUnauthenticated?: () => Promise<void>;
26
22
  }
27
23
 
@@ -29,24 +25,6 @@ interface RequestOptions {
29
25
  refresh_session?: () => Promise<any>,
30
26
  }
31
27
 
32
- export type Filter<T> = { [K in keyof T]: T[K] }
33
-
34
- export interface APIQuery<
35
- N extends keyof ClientModelForName,
36
- T=ClientModelForName[N],
37
- Req=ClientModelForName_required[N],
38
- CREATE=Omit<Req & Partial<T>, keyof ClientModelForName_readonly[N]>,
39
- UPDATE=Omit<Partial<T>, keyof (ClientModelForName_readonly[N] & ClientModelForName_updatesDisabled[N])>,
40
- >
41
- {
42
- createOne: (t: CREATE) => Promise<T>;
43
- createSome: (ts: CREATE[]) => Promise<{ created: T[], errors: object[] }>;
44
- getOne: (id: string, filter?: Filter<Partial<T>>) => Promise<T>;
45
- getSome: (o?: { lastId?: string, limit?: number, sort?: SortOption, threadKey?: string }, f?: Filter<Partial<T>>) => Promise<T[]>
46
- updateOne: (id: string, updates: UPDATE, options?: CustomUpdateOptions) => Promise<T>;
47
- deleteOne: (id: string) => Promise<void>;
48
- }
49
-
50
28
  const generateBearer = (authToken: string) => `Bearer ${authToken}`
51
29
 
52
30
  const parseError = (err: any) => {
@@ -71,6 +49,7 @@ export class Session {
71
49
  apiKey?: string;
72
50
  socket?: Socket;
73
51
  handleUnauthenticated?: SessionOptions['handleUnauthenticated']
52
+ expirationInSeconds?: number;
74
53
  socketAuthenticated: boolean;
75
54
  userInfo: { businessId?: string };
76
55
  sessionStart = Date.now();
@@ -81,6 +60,7 @@ export class Session {
81
60
  constructor(o={} as SessionOptions & RequestOptions) {
82
61
  this.host= o.host ?? DEFAULT_HOST
83
62
  this.apiKey = o.apiKey ?? '';
63
+ this.expirationInSeconds = o.expirationInSeconds
84
64
  this.socket = undefined as Socket | undefined
85
65
  this.socketAuthenticated = false
86
66
  this.handleUnauthenticated = o.handleUnauthenticated
@@ -58,7 +58,7 @@ const enduser_login_tests = async () => {
58
58
  log_header("Public Endpoints")
59
59
 
60
60
  try {
61
- await sdk.authenticate(email, password, host)
61
+ await sdk.authenticate(email, password)
62
62
  await sdk.reset_db()
63
63
 
64
64
  await enduser_login_tests()
@@ -1,3 +1,4 @@
1
+ import { createHash } from "crypto"
1
2
  import {
2
3
  assert,
3
4
  async_test,
@@ -17,6 +18,7 @@ import { EnduserSession } from "../enduser"
17
18
  import { Session, /* APIQuery */ } from "../sdk"
18
19
  import { PLACEHOLDER_ID } from "@tellescope/constants"
19
20
 
21
+ export const get_sha256 = (s='') => createHash('sha256').update(s).digest('hex')
20
22
 
21
23
  const host = process.env.TEST_URL || 'http://localhost:8080'
22
24
  const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
@@ -198,28 +200,89 @@ const enduser_tests = async () => {
198
200
  // await user1.api.chats.deleteOne(messageToUser.id)
199
201
  }
200
202
 
203
+ const TEST_SESSION_DURATION = 2 // seconds
204
+ const SESSION_TIMEOUT_DELAY = 2000 // ms
205
+ const deauthentication_tests = async (byTimeout=false) => {
206
+ log_header(`Unauthenticated Tests ${byTimeout ? '- With Timeout, requires Worker' : '- With Manual Logout' }`)
207
+
208
+ const enduser = await user1.api.endusers.createOne({ email: "socketenduser@tellescope.com" })
209
+ await user1.api.endusers.set_password({ id: enduser.id, password: 'enduserPassword!' })
210
+ await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!', { expirationInSeconds: byTimeout ? TEST_SESSION_DURATION : undefined })
211
+ await wait(undefined, 25)
212
+
213
+ const room = await user1.api.chat_rooms.createOne({
214
+ type: 'external',
215
+ userIds: [user1.userInfo.id],
216
+ enduserIds: [enduser.id],
217
+ })
218
+
219
+ const userEvents = [] as ChatMessage[]
220
+ const enduserEvents = [] as ChatMessage[]
221
+ user1.subscribe({ [room.id]: 'chats' })
222
+ enduserSDK.subscribe({ [room.id]: 'chats' })
223
+ user1.handle_events({ 'created-chats': rs => userEvents.push(...rs) })
224
+ enduserSDK.handle_events({ 'created-chats': rs => enduserEvents.push(...rs) })
225
+ await wait(undefined, 10)
226
+
227
+ if (!byTimeout) {
228
+ await enduserSDK.api.endusers.logout()
229
+ } else {
230
+ await wait(undefined, TEST_SESSION_DURATION * 1000 + SESSION_TIMEOUT_DELAY)
231
+ }
232
+ await user1.api.chats.createOne({ roomId: room.id, message: "Hello!" })
233
+ await wait(undefined, 25)
234
+ assert(objects_equivalent(enduserEvents[0], undefined), 'enduser got message after logout on socket', 'enduser logged out')
235
+
236
+ // re-authenticate enduser to send message to user
237
+ await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!')
238
+
239
+ // ensure user logged out appropriately for not receiving message
240
+ await user1.logout()
241
+ if (byTimeout) {
242
+ await user1.authenticate(email, password, { expirationInSeconds: byTimeout ? TEST_SESSION_DURATION : undefined } )
243
+ await wait(undefined, TEST_SESSION_DURATION * 1000 + SESSION_TIMEOUT_DELAY)
244
+ }
245
+ await enduserSDK.api.chats.createOne({ roomId: room.id, message: "Hello right back!" })
246
+ await wait(undefined, 25)
247
+ assert(objects_equivalent(userEvents[0], undefined), 'user got message after logout', 'user logged out')
248
+
249
+ // must come before cleanup, so cleanup works
250
+ await user1.authenticate(email, password), // reauthenticate for later tests as needed
251
+
252
+ // cleanup
253
+ await Promise.all([
254
+ user1.api.endusers.deleteOne(enduser.id),
255
+ user1.api.chat_rooms.deleteOne(room.id), // deletes chats as side effect
256
+ ])
257
+ }
258
+
201
259
  (async () => {
202
260
  log_header("Sockets")
203
261
 
204
262
  try {
205
- await user1.authenticate(email, password, host)
263
+ await user1.authenticate(email, password)
206
264
  await user1.reset_db()
207
- await user2.authenticate(email2, password2, host) // generate authToken + socket connection for API keyj
265
+ await user2.authenticate(email2, password2) // generate authToken + socket connection for API keyj
208
266
  await wait(undefined, 25)
209
267
 
210
268
  let loopCount = 0
211
269
  while (!(user1.socketAuthenticated && user2.socketAuthenticated) && ++loopCount < 10) {
212
- user2.authenticate_socket()
270
+ if (!user1.socketAuthenticated) user1.authenticate_socket()
271
+ if (!user2.socketAuthenticated) user2.authenticate_socket()
213
272
  await wait(undefined, 100)
214
273
  }
215
274
  if (loopCount === 10) {
216
275
  console.log("Failed to authenticate")
217
276
  process.exit()
218
277
  }
219
-
278
+
220
279
  await enduser_tests()
221
280
  await basic_tests()
222
281
  await access_tests()
282
+
283
+ await deauthentication_tests() // should come last!
284
+ await deauthentication_tests(true) // should come last!
285
+
223
286
  } catch(err) {
224
287
  console.error(err)
225
288
  }
@@ -71,7 +71,7 @@ const userId = '60398b0231a295e64f084fd9'
71
71
  // await sdk.api.endusers.deleteOne(enduser.id)
72
72
  // }
73
73
 
74
- const sdk = new Session()
74
+ const sdk = new Session({ host })
75
75
  const sdkOther = new Session({ host, apiKey: "ba745e25162bb95a795c5fa1af70df188d93c4d3aac9c48b34a5c8c9dd7b80f7" })
76
76
  const enduserSDK = new EnduserSession({ host })
77
77
  // const sdkOtherEmail = "sebass@tellescope.com"
@@ -90,8 +90,6 @@ const setup_tests = async () => {
90
90
  await async_test('test_online', sdk.test_online, { expectedResult: 'API V1 Online' })
91
91
  await async_test('test_authenticated', sdk.test_authenticated, { expectedResult: 'Authenticated!' })
92
92
 
93
- // console.log(await sdk.api.api_keys.createOne({}))
94
-
95
93
  await async_test(
96
94
  'test_authenticated (with API Key)',
97
95
  (new Session({ host, apiKey: '3n5q0SCBT_iUvZz-b9BJtX7o7HQUVJ9v132PgHJNJsg.' /* local test key */ })).test_authenticated,
@@ -100,7 +98,7 @@ const setup_tests = async () => {
100
98
 
101
99
  await sdk.logout()
102
100
  await async_test<string, string>('test_authenticated - (logout invalidates jwt)', sdk.test_authenticated, { shouldError: true, onError: e => e === 'Unauthenticated' })
103
- await sdk.authenticate(email, password, host)
101
+ await sdk.authenticate(email, password)
104
102
  await async_test('test_authenticated (re-authenticated)', sdk.test_authenticated, { expectedResult: 'Authenticated!' })
105
103
 
106
104
  await async_test('reset_db', () => sdk.reset_db(), passOnVoid)
@@ -191,6 +189,20 @@ const threadKeyTests = async () => {
191
189
  ])
192
190
  }
193
191
 
192
+ const badInputTests = async () => {
193
+ log_header("Bad Input Tests")
194
+ await async_test(
195
+ `_-prefixed fields are not allowed`,
196
+ () => sdk.api.endusers.createOne({ email: 'failure@tellescope.com', fields: { "_notallowed": 'hello' } }),
197
+ { shouldError: true, onError: e => e.message === "Error parsing field fields: Fields that start with '_' are not allowed" },
198
+ )
199
+ await async_test(
200
+ `_-prefixed fields are not allowed`,
201
+ () => sdk.api.notes.createOne({ enduserId: PLACEHOLDER_ID, fields: { "_notallowed": 'hello' } }),
202
+ { shouldError: true, onError: e => e.message === "Error parsing field fields: Fields that start with '_' are not allowed" },
203
+ )
204
+ }
205
+
194
206
  const filterTests = async () => {
195
207
  const enduser = await sdk.api.endusers.createOne({ email: 'filtertests@tellescope.com', fname: 'test', fields: { field1: 'value1', field2: 'value2' } })
196
208
  const otherEnduser = await sdk.api.endusers.createOne({ email: 'other@tellescope.com' })
@@ -199,6 +211,17 @@ const filterTests = async () => {
199
211
  () => sdk.api.endusers.getSome({ filter: { email: 'filtertests@tellescope.com' }}),
200
212
  { onResult: es => es.length === 1 && es[0].id === enduser.id },
201
213
  )
214
+ await async_test(
215
+ `find enduser by _exists filter`,
216
+ () => sdk.api.endusers.getSome({ filter: { fname: { _exists: true } }}),
217
+ { onResult: es => es.length === 1 && es[0].id === enduser.id },
218
+ )
219
+ await async_test(
220
+ `find enduser by _exists filter (findOne)`,
221
+ // () => sdk.api.endusers.getOne({ fname: { _exists: true } }),
222
+ () => sdk.api.endusers.getOne({ fname: { _exists: true } }),
223
+ { onResult: e => e.id === enduser.id },
224
+ )
202
225
  await async_test(
203
226
  `find enduser by compound filter`,
204
227
  () => sdk.api.endusers.getSome({ filter: { email: 'filtertests@tellescope.com', fname: 'test' }}),
@@ -265,13 +288,21 @@ const updatesTests = async () => {
265
288
 
266
289
  const generateEnduserAuthTests = async () => {
267
290
  log_header("Generated Enduser authToken Tests")
268
- const e = await sdk.api.endusers.createOne({ email: 'generated@tellescope.com', phone: '+15555555555', externalId: '1029f9v9sjd0as' })
291
+ const externalId = '1029f9v9sjd0as'
292
+ const e = await sdk.api.endusers.createOne({ email: 'generated@tellescope.com', phone: '+15555555555', externalId })
293
+
269
294
  const { authToken, enduser } = await sdk.api.endusers.generate_auth_token({ id: e.id })
270
295
  assert(!!authToken && !!enduser, 'invalid returned values', 'Generate authToken and get enduser')
271
-
272
296
  const { isAuthenticated } = await sdk.api.endusers.is_authenticated({ id: enduser.id, authToken })
273
297
  assert(isAuthenticated, 'invalid authToken generated for enduser', 'Generate authToken for enduser is valid')
274
298
 
299
+ const { authToken: authTokenUID, enduser: enduser2 } = await sdk.api.endusers.generate_auth_token({ externalId })
300
+ assert(!!authTokenUID && !!enduser2, 'invalid returned values eid', 'Generate authToken and get enduser eid')
301
+ assert((
302
+ await sdk.api.endusers.is_authenticated({ id: enduser2.id, authToken: authTokenUID })).isAuthenticated,
303
+ 'invalid authToken generated for enduser', 'Generate authToken for enduser is valid'
304
+ )
305
+
275
306
  await async_test(
276
307
  `auth by externalId`, () => sdk.api.endusers.generate_auth_token({ externalId: e.externalId }), passOnVoid,
277
308
  )
@@ -419,7 +450,7 @@ const run_generated_tests = async <N extends ModelName>({ queries, model, name,
419
450
  }
420
451
  await async_test(
421
452
  `get-${singularName}`,
422
- () => queries.getOne(_id, filter),
453
+ () => queries.getOne(_id),
423
454
  { onResult: d => {
424
455
  if (!d?.id) return false
425
456
 
@@ -452,7 +483,7 @@ const run_generated_tests = async <N extends ModelName>({ queries, model, name,
452
483
  )
453
484
  await async_test(
454
485
  `get-${singularName} (verify delete)`,
455
- () => queries.getOne(_id, filter),
486
+ () => queries.getOne(_id),
456
487
  { shouldError: true, onError: e => e.message === 'Could not find a record for the given id' }
457
488
  )
458
489
  }
@@ -840,32 +871,22 @@ const chat_tests = async() => {
840
871
  const chat = await sdk.api.chats.createOne({ roomId: room.id, message: "Hello!" })
841
872
  const chat2 = await sdk.api.chats.createOne({ roomId: room.id, message: "Hello..." })
842
873
 
843
- await async_test(
844
- `get-chat (without filter)`,
845
- () => sdk.api.chats.getOne(chat.id),
846
- { shouldError: true, onError: () => true }
847
- )
874
+ // await async_test(
875
+ // `get-chat (without filter)`,
876
+ // () => sdk.api.chats.getOne(chat.id),
877
+ // { shouldError: true, onError: () => true }
878
+ // )
848
879
  await async_test(
849
880
  `get-chats (without filter)`,
850
881
  () => sdk.api.chats.getSome({}),
851
882
  { shouldError: true, onError: () => true }
852
883
  )
853
- await async_test(
854
- `get-chat (with filter)`,
855
- () => sdk.api.chats.getOne(chat.id, { roomId: room.id }),
856
- { onResult: c => c?.id === chat.id }
857
- )
858
884
  await async_test(
859
885
  `get-chats (with filter)`,
860
886
  () => sdk.api.chats.getSome({ filter: { roomId: room.id } }),
861
887
  { onResult: c => c?.length === 2 }
862
888
  )
863
889
 
864
- await async_test(
865
- `get-chat not allowed`,
866
- () => sdk2.api.chats.getOne(chat.id, { roomId: room.id }),
867
- { shouldError: true, onError: e => e.message === 'You do not have permission to access this resource' }
868
- )
869
890
  await async_test(
870
891
  `get-chats not allowed`,
871
892
  () => sdk2.api.chats.getSome({ filter: { roomId: room.id } }),
@@ -894,12 +915,12 @@ const chat_tests = async() => {
894
915
  await wait(undefined, 25)
895
916
  await async_test(
896
917
  `get-chat (deleted as dependency of room 1)`,
897
- () => sdk.api.chats.getOne(chat.id, { roomId: room.id }),
918
+ () => sdk.api.chats.getOne(chat.id),
898
919
  { shouldError: true, onError: e => e.message === 'Could not find a record for the given id' }
899
920
  )
900
921
  await async_test(
901
922
  `get-chat (deleted as dependency of room 2)`,
902
- () => sdk.api.chats.getOne(chat2.id, { roomId: room.id }),
923
+ () => sdk.api.chats.getOne(chat2.id),
903
924
  { shouldError: true, onError: e => e.message === 'Could not find a record for the given id' }
904
925
  )
905
926
 
@@ -908,12 +929,12 @@ const chat_tests = async() => {
908
929
  const sharedChat2 = await sdk2.api.chats.createOne({ roomId: sharedRoom.id, message: "Hello there!", })
909
930
  await async_test(
910
931
  `get-chat (shared, user1)`,
911
- () => sdk.api.chats.getOne(sharedChat.id, { roomId: sharedRoom.id }),
932
+ () => sdk.api.chats.getOne(sharedChat.id),
912
933
  { onResult: r => r.id === sharedChat.id }
913
934
  )
914
935
  await async_test(
915
936
  `get-chat (shared, user2)`,
916
- () => sdk2.api.chats.getOne(sharedChat.id, { roomId: sharedRoom.id }),
937
+ () => sdk2.api.chats.getOne(sharedChat.id),
917
938
  { onResult: r => r.id === sharedChat.id }
918
939
  )
919
940
  await async_test(
@@ -936,7 +957,7 @@ const chat_tests = async() => {
936
957
  await sdk.api.chats.deleteOne(chatNull.id)
937
958
  await async_test(
938
959
  `get-chat (setNull working)`,
939
- () => sdk.api.chats.getOne(chat2Null.id, { roomId: roomNull.id }),
960
+ () => sdk.api.chats.getOne(chat2Null.id),
940
961
  { onResult: c => c.replyId === null }
941
962
  )
942
963
  }
@@ -1058,13 +1079,13 @@ const tests: { [K in keyof ClientModelForName]: () => void } = {
1058
1079
  };
1059
1080
 
1060
1081
  (async () => {
1061
- await sdk.authenticate(email, password, host)
1062
-
1063
1082
  log_header("API")
1064
-
1083
+
1065
1084
  try {
1085
+ await sdk.authenticate(email, password)
1066
1086
  await setup_tests()
1067
1087
  await multi_tenant_tests() // should come right after setup tests
1088
+ await badInputTests()
1068
1089
  await filterTests()
1069
1090
  await updatesTests()
1070
1091
  await threadKeyTests()