@tellescope/sdk 0.0.14 → 0.0.18
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/lib/cjs/enduser.d.ts +34 -5
- package/lib/cjs/enduser.d.ts.map +1 -1
- package/lib/cjs/enduser.js +5 -4
- package/lib/cjs/enduser.js.map +1 -1
- package/lib/cjs/sdk.d.ts +51 -16
- package/lib/cjs/sdk.d.ts.map +1 -1
- package/lib/cjs/sdk.js +10 -10
- package/lib/cjs/sdk.js.map +1 -1
- package/lib/cjs/session.d.ts +5 -21
- package/lib/cjs/session.d.ts.map +1 -1
- package/lib/cjs/session.js +12 -0
- package/lib/cjs/session.js.map +1 -1
- package/lib/cjs/tests/public_endpoint_tests.js +4 -4
- package/lib/cjs/tests/public_endpoint_tests.js.map +1 -1
- package/lib/cjs/tests/socket_tests.d.ts +1 -1
- package/lib/cjs/tests/socket_tests.d.ts.map +1 -1
- package/lib/cjs/tests/socket_tests.js +125 -8
- package/lib/cjs/tests/socket_tests.js.map +1 -1
- package/lib/cjs/tests/tests.js +207 -97
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/enduser.d.ts +34 -5
- package/lib/esm/enduser.d.ts.map +1 -1
- package/lib/esm/enduser.js +5 -4
- package/lib/esm/enduser.js.map +1 -1
- package/lib/esm/sdk.d.ts +51 -16
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/sdk.js +10 -10
- package/lib/esm/sdk.js.map +1 -1
- package/lib/esm/session.d.ts +5 -21
- package/lib/esm/session.d.ts.map +1 -1
- package/lib/esm/session.js +12 -0
- package/lib/esm/session.js.map +1 -1
- package/lib/esm/tests/public_endpoint_tests.js +4 -4
- package/lib/esm/tests/public_endpoint_tests.js.map +1 -1
- package/lib/esm/tests/socket_tests.d.ts +1 -1
- package/lib/esm/tests/socket_tests.d.ts.map +1 -1
- package/lib/esm/tests/socket_tests.js +123 -8
- package/lib/esm/tests/socket_tests.js.map +1 -1
- package/lib/esm/tests/tests.js +188 -97
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/enduser.ts +12 -8
- package/src/sdk.ts +31 -20
- package/src/session.ts +8 -18
- package/src/tests/public_endpoint_tests.ts +4 -4
- package/src/tests/socket_tests.ts +68 -5
- package/src/tests/tests.ts +116 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Code for interacting with the Tellescope API",
|
|
5
5
|
"main": "./lib/cjs/sdk.js",
|
|
6
6
|
"module": "./lib/esm/sdk.js",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/tellescope-os/tellescope#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@tellescope/constants": "^0.0.
|
|
34
|
-
"@tellescope/schema": "^0.0.
|
|
35
|
-
"@tellescope/testing": "^0.0.
|
|
36
|
-
"@tellescope/types-client": "^0.0.
|
|
37
|
-
"@tellescope/types-models": "^0.0.
|
|
38
|
-
"@tellescope/types-utilities": "^0.0.
|
|
39
|
-
"@tellescope/utilities": "^0.0.
|
|
40
|
-
"@tellescope/validation": "^0.0.
|
|
33
|
+
"@tellescope/constants": "^0.0.18",
|
|
34
|
+
"@tellescope/schema": "^0.0.18",
|
|
35
|
+
"@tellescope/testing": "^0.0.18",
|
|
36
|
+
"@tellescope/types-client": "^0.0.18",
|
|
37
|
+
"@tellescope/types-models": "^0.0.18",
|
|
38
|
+
"@tellescope/types-utilities": "^0.0.18",
|
|
39
|
+
"@tellescope/utilities": "^0.0.18",
|
|
40
|
+
"@tellescope/validation": "^0.0.18",
|
|
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": "
|
|
56
|
+
"gitHead": "8019bedb3e6f90e2d26ee71ee989bd05fc1b7ee6"
|
|
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
|
|
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: (
|
|
34
|
-
|
|
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
|
}
|
|
@@ -42,7 +43,7 @@ type EnduserQueries = { [K in EnduserAccessibleModels]: APIQuery<K> } & {
|
|
|
42
43
|
logout: () => Promise<void>;
|
|
43
44
|
},
|
|
44
45
|
users: {
|
|
45
|
-
|
|
46
|
+
display_info: () => Promise<{ fname?: string, lname?: string, id: string, lastActive?: Date, lastLogout?: Date }[]>
|
|
46
47
|
},
|
|
47
48
|
files: {
|
|
48
49
|
prepare_file_upload: (args: { name: string, size: number, type: string }) => Promise<{ presignedUpload: S3PresignedPost, file: File }>,
|
|
@@ -76,7 +77,7 @@ export class EnduserSession extends Session {
|
|
|
76
77
|
logout: () => this._POST('/v1/logout-enduser'),
|
|
77
78
|
}
|
|
78
79
|
this.api.users = {
|
|
79
|
-
|
|
80
|
+
display_info: () => this._GET<{}, { fname: string, lname: string, id: string }[] >(`/v1/user-display-info`),
|
|
80
81
|
}
|
|
81
82
|
this.api.meetings = {
|
|
82
83
|
attendee_info: a => this._GET('/v1/attendee-info', a),
|
|
@@ -124,8 +125,11 @@ export class EnduserSession extends Session {
|
|
|
124
125
|
return { authToken, enduser }
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
authenticate = async (email: string, password: string) => this.handle_new_session(
|
|
128
|
-
await this.POST<
|
|
128
|
+
authenticate = async (email: string, password: string, o?: { expirationInSeconds?: number }) => this.handle_new_session(
|
|
129
|
+
await this.POST<
|
|
130
|
+
{email: string, password: string, expirationInSeconds?: number },
|
|
131
|
+
{ authToken: string, enduser: Enduser }
|
|
132
|
+
>('/v1/login-enduser', { email, password, ...o })
|
|
129
133
|
)
|
|
130
134
|
|
|
131
135
|
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,11 +19,19 @@ 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
|
|
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?: {
|
|
28
|
+
lastId?: string,
|
|
29
|
+
limit?: number,
|
|
30
|
+
sort?: SortOption,
|
|
31
|
+
threadKey?: string,
|
|
32
|
+
filter?: ReadFilter<T>,
|
|
33
|
+
}) => Promise<T[]>
|
|
34
|
+
|
|
27
35
|
export interface APIQuery<
|
|
28
36
|
N extends keyof ClientModelForName,
|
|
29
37
|
T=ClientModelForName[N],
|
|
@@ -34,8 +42,8 @@ export interface APIQuery<
|
|
|
34
42
|
{
|
|
35
43
|
createOne: (t: CREATE) => Promise<T>;
|
|
36
44
|
createSome: (ts: CREATE[]) => Promise<{ created: T[], errors: object[] }>;
|
|
37
|
-
getOne: (
|
|
38
|
-
getSome:
|
|
45
|
+
getOne: (argument: string | ReadFilter<T>) => Promise<T>;
|
|
46
|
+
getSome: LoadFunction<T>;
|
|
39
47
|
updateOne: (id: string, updates: UPDATE, options?: CustomUpdateOptions) => Promise<T>;
|
|
40
48
|
deleteOne: (id: string) => Promise<void>;
|
|
41
49
|
}
|
|
@@ -50,7 +58,8 @@ export const defaultQueries = <N extends keyof ClientModelForName>(
|
|
|
50
58
|
return {
|
|
51
59
|
createOne: o => s._POST(`/v1/${singularName}`, o),
|
|
52
60
|
createSome: os => s._POST(`/v1/${safeName}`, { create: os }),
|
|
53
|
-
getOne: (
|
|
61
|
+
getOne: (argument) => typeof argument === 'string' ? s._GET(`/v1/${singularName}/${argument}`)
|
|
62
|
+
: s._GET(`/v1/${singularName}`, { filter: argument }),
|
|
54
63
|
getSome: (o) => s._GET(`/v1/${safeName}`, o),
|
|
55
64
|
updateOne: (id, updates, options) => s._PATCH(`/v1/${singularName}/${id}`, { updates, options }),
|
|
56
65
|
deleteOne: id => s._DELETE(`/v1/${singularName}/${id}`),
|
|
@@ -72,16 +81,17 @@ const loadDefaultQueries = (s: Session): { [K in keyof ClientModelForName] : API
|
|
|
72
81
|
files: defaultQueries(s, 'files'),
|
|
73
82
|
tickets: defaultQueries(s, 'tickets'),
|
|
74
83
|
meetings: defaultQueries(s, 'meetings'),
|
|
84
|
+
notes: defaultQueries(s, 'notes'),
|
|
75
85
|
})
|
|
76
86
|
|
|
77
87
|
type Queries = { [K in keyof ClientModelForName]: APIQuery<K> } & {
|
|
78
88
|
journeys: {
|
|
79
|
-
|
|
89
|
+
update_state: (args: { id: string, name: string, updates: JourneyState }) => Promise<void>
|
|
80
90
|
},
|
|
81
91
|
endusers: {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
set_password: (args: { id: string, password: string }) => Promise<void>,
|
|
93
|
+
is_authenticated: (args: { id: string, authToken: string }) => Promise<{ isAuthenticated: boolean, enduser: Enduser }>
|
|
94
|
+
generate_auth_token: (args: { id?: string, phone?: string, email?: string, externalId?: string }) => Promise<{ authToken: string, enduser: Enduser }>
|
|
85
95
|
},
|
|
86
96
|
users: {
|
|
87
97
|
display_names: () => Promise<{ fname: string, lname: string, id: string }[]>,
|
|
@@ -110,10 +120,10 @@ export class Session extends SessionManager {
|
|
|
110
120
|
super({ ...o, cacheKey: o?.cacheKey || "tellescope_user" })
|
|
111
121
|
const queries = loadDefaultQueries(this) as Queries
|
|
112
122
|
|
|
113
|
-
queries.journeys.
|
|
114
|
-
queries.endusers.
|
|
115
|
-
queries.endusers.
|
|
116
|
-
queries.endusers.
|
|
123
|
+
queries.journeys.update_state = ({id, name, updates}) => this._PATCH(`/v1/journey/${id}/state/${name}`, { updates })
|
|
124
|
+
queries.endusers.set_password = ({id, password}) => this._POST(`/v1/set-enduser-password`, { id, password })
|
|
125
|
+
queries.endusers.is_authenticated = ({id, authToken}) => this._GET(`/v1/enduser-is-authenticated`, { id, authToken })
|
|
126
|
+
queries.endusers.generate_auth_token = args => this._GET(`/v1/generate-enduser-auth-token`, args)
|
|
117
127
|
queries.users.display_names = () => this._GET<{}, { fname: string, lname: string, id: string }[]>(`/v1/user-display-names`),
|
|
118
128
|
queries.files.prepare_file_upload = (args) => this._POST(`/v1/prepare-file-upload`, args),
|
|
119
129
|
queries.files.file_download_URL = a => this._GET('/v1/file-download-URL', a),
|
|
@@ -170,13 +180,14 @@ export class Session extends SessionManager {
|
|
|
170
180
|
if (this.AUTO_REFRESH_MS < elapsedSessionMS) { return await this.refresh_session()}
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
authenticate = async (email: string, password: string,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
authenticate = async (email: string, password: string, o?: { expirationInSeconds?: number }) => (
|
|
184
|
+
this.handle_new_session(
|
|
185
|
+
await this.POST<
|
|
186
|
+
{email: string, password: string, expirationInSeconds?: number },
|
|
187
|
+
UserSession & { authToken: string }
|
|
188
|
+
>('/submit-login', { email, password, ...o })
|
|
189
|
+
)
|
|
190
|
+
)
|
|
180
191
|
logout = async () => {
|
|
181
192
|
this.clearState()
|
|
182
193
|
await this.POST('/logout-api').catch(console.error)
|
package/src/session.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface SessionOptions {
|
|
|
22
22
|
authToken?: string;
|
|
23
23
|
host?: string;
|
|
24
24
|
cacheKey?: string;
|
|
25
|
+
expirationInSeconds?: number,
|
|
25
26
|
handleUnauthenticated?: () => Promise<void>;
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -29,24 +30,6 @@ interface RequestOptions {
|
|
|
29
30
|
refresh_session?: () => Promise<any>,
|
|
30
31
|
}
|
|
31
32
|
|
|
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
33
|
const generateBearer = (authToken: string) => `Bearer ${authToken}`
|
|
51
34
|
|
|
52
35
|
const parseError = (err: any) => {
|
|
@@ -71,6 +54,7 @@ export class Session {
|
|
|
71
54
|
apiKey?: string;
|
|
72
55
|
socket?: Socket;
|
|
73
56
|
handleUnauthenticated?: SessionOptions['handleUnauthenticated']
|
|
57
|
+
expirationInSeconds?: number;
|
|
74
58
|
socketAuthenticated: boolean;
|
|
75
59
|
userInfo: { businessId?: string };
|
|
76
60
|
sessionStart = Date.now();
|
|
@@ -81,6 +65,7 @@ export class Session {
|
|
|
81
65
|
constructor(o={} as SessionOptions & RequestOptions) {
|
|
82
66
|
this.host= o.host ?? DEFAULT_HOST
|
|
83
67
|
this.apiKey = o.apiKey ?? '';
|
|
68
|
+
this.expirationInSeconds = o.expirationInSeconds
|
|
84
69
|
this.socket = undefined as Socket | undefined
|
|
85
70
|
this.socketAuthenticated = false
|
|
86
71
|
this.handleUnauthenticated = o.handleUnauthenticated
|
|
@@ -195,6 +180,11 @@ export class Session {
|
|
|
195
180
|
catch(err) { console.error(err); throw err }
|
|
196
181
|
}
|
|
197
182
|
|
|
183
|
+
DOWNLOAD = async (downloadURL: string) => {
|
|
184
|
+
const content = await axios.get(downloadURL)
|
|
185
|
+
return content.data
|
|
186
|
+
}
|
|
187
|
+
|
|
198
188
|
EMIT = async (route: string, args: object, authenticated=true, options={} as RequestOptions) => {
|
|
199
189
|
this.socket?.emit(route, { ...args, ...authenticated ? { authToken: this.authToken } : {} } )
|
|
200
190
|
}
|
|
@@ -32,14 +32,14 @@ const enduser_login_tests = async () => {
|
|
|
32
32
|
)
|
|
33
33
|
await async_test(
|
|
34
34
|
'setPassword',
|
|
35
|
-
() => sdk.api.endusers.
|
|
35
|
+
() => sdk.api.endusers.set_password({ id: e.id, password }),
|
|
36
36
|
{ onResult: _ => true }
|
|
37
37
|
)
|
|
38
38
|
|
|
39
39
|
let authToken = 'placeholder'
|
|
40
40
|
await async_test(
|
|
41
41
|
'isAuthenticated (no)',
|
|
42
|
-
() => sdk.api.endusers.
|
|
42
|
+
() => sdk.api.endusers.is_authenticated({ id: e.id, authToken }),
|
|
43
43
|
{ onResult: ({ isAuthenticated, enduser }) => isAuthenticated === false && enduser === null }
|
|
44
44
|
)
|
|
45
45
|
await async_test(
|
|
@@ -49,7 +49,7 @@ const enduser_login_tests = async () => {
|
|
|
49
49
|
)
|
|
50
50
|
await async_test(
|
|
51
51
|
'isAuthenticated (yes)',
|
|
52
|
-
() => sdk.api.endusers.
|
|
52
|
+
() => sdk.api.endusers.is_authenticated({ id: e.id, authToken }),
|
|
53
53
|
{ onResult: ({ isAuthenticated, enduser }) => isAuthenticated === true && enduser?.id === e.id }
|
|
54
54
|
)
|
|
55
55
|
}
|
|
@@ -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
|
|
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]
|
|
@@ -133,7 +135,7 @@ const access_tests = async () => {
|
|
|
133
135
|
|
|
134
136
|
const enduser_tests = async () => {
|
|
135
137
|
const enduser = await user1.api.endusers.createOne({ email: "enduser@tellescope.com" })
|
|
136
|
-
await user1.api.endusers.
|
|
138
|
+
await user1.api.endusers.set_password({ id: enduser.id, password: 'enduserPassword!' })
|
|
137
139
|
|
|
138
140
|
await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!')
|
|
139
141
|
await wait(undefined, 25)
|
|
@@ -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
|
|
263
|
+
await user1.authenticate(email, password)
|
|
206
264
|
await user1.reset_db()
|
|
207
|
-
await user2.authenticate(email2, password2
|
|
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
|
-
|
|
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
|
}
|