@prisme.ai/sdk 0.0.2 → 1.0.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/Readme.md +3 -1
- package/dist/lib/api.d.ts +113 -32
- package/dist/lib/endpoints/users.d.ts +9 -0
- package/dist/lib/endpoints/workspaces.d.ts +9 -0
- package/dist/lib/endpoints/workspacesVersions.d.ts +10 -0
- package/dist/lib/events.d.ts +28 -4
- package/dist/lib/fetcher.d.ts +14 -2
- package/dist/lib/types.d.ts +5 -1
- package/dist/sdk/lib/api.js +490 -87
- package/dist/sdk/lib/endpoints/users.js +43 -0
- package/dist/sdk/lib/endpoints/workspaces.js +23 -0
- package/dist/sdk/lib/endpoints/workspacesVersions.js +40 -0
- package/dist/sdk/lib/events.js +86 -9
- package/dist/sdk/lib/fetcher.js +75 -21
- package/lib/api.test.ts +610 -69
- package/lib/api.ts +556 -124
- package/lib/endpoints/users.ts +22 -0
- package/lib/endpoints/workspaces.ts +18 -0
- package/lib/endpoints/workspacesVersions.ts +34 -0
- package/lib/events.test.ts +39 -7
- package/lib/events.ts +127 -16
- package/lib/fetcher.test.ts +59 -13
- package/lib/fetcher.ts +89 -23
- package/lib/types.ts +5 -1
- package/package.json +2 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Api } from '../api';
|
|
2
|
+
|
|
3
|
+
export class UsersEndpoint {
|
|
4
|
+
private id: string;
|
|
5
|
+
private api: Api;
|
|
6
|
+
|
|
7
|
+
constructor(id: string, api: Api) {
|
|
8
|
+
this.id = id;
|
|
9
|
+
this.api = api;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async setMeta(k: string, v: any) {
|
|
13
|
+
await this.api.post(`/user/meta`, {
|
|
14
|
+
[k]: v,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async deleteMeta(k: string) {
|
|
18
|
+
await this.api.delete(`/user/meta/${k}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default UsersEndpoint;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Api } from '../api';
|
|
2
|
+
import WorkspacesVersionsEndpoint from './workspacesVersions';
|
|
3
|
+
|
|
4
|
+
export class WorkspacesEndpoint {
|
|
5
|
+
private id: string;
|
|
6
|
+
private api: Api;
|
|
7
|
+
|
|
8
|
+
constructor(id: string, api: Api) {
|
|
9
|
+
this.id = id;
|
|
10
|
+
this.api = api;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get versions() {
|
|
14
|
+
return new WorkspacesVersionsEndpoint(this.id, this.api);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default WorkspacesEndpoint;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Api } from '../api';
|
|
2
|
+
|
|
3
|
+
export class WorkspacesVersionsEndpoint {
|
|
4
|
+
private workspaceId: string;
|
|
5
|
+
private api: Api;
|
|
6
|
+
|
|
7
|
+
constructor(workspaceId: string, api: Api) {
|
|
8
|
+
this.workspaceId = workspaceId;
|
|
9
|
+
this.api = api;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
create(version?: PrismeaiAPI.PublishWorkspaceVersion.RequestBody) {
|
|
13
|
+
this.api.post(`/workspaces/${this.workspaceId}/versions`, version);
|
|
14
|
+
}
|
|
15
|
+
rollback(
|
|
16
|
+
versionId: PrismeaiAPI.RollbackWorkspaceVersion.PathParameters['versionId']
|
|
17
|
+
) {
|
|
18
|
+
this.api.post(
|
|
19
|
+
`/workspaces/${this.workspaceId}/versions/${versionId}/rollback`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async export(version: PrismeaiAPI.ExportWorkspaceVersion.Parameters.VersionId = 'current') {
|
|
24
|
+
const res = await this.api.prepareRequest(
|
|
25
|
+
`/workspaces/${this.workspaceId}/versions/${version}/export`, {
|
|
26
|
+
method: 'post'
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
return new Blob([await res.arrayBuffer()], { type: 'application/zip' });
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default WorkspacesVersionsEndpoint;
|
package/lib/events.test.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import getConfig from 'next/config';
|
|
2
2
|
import Events from './events';
|
|
3
3
|
import io from 'socket.io-client';
|
|
4
|
-
|
|
5
|
-
const { publicRuntimeConfig } = getConfig();
|
|
4
|
+
import { Api } from './api';
|
|
6
5
|
|
|
7
6
|
jest.mock('socket.io-client', () => {
|
|
8
7
|
const mock = {
|
|
9
8
|
disconnect: jest.fn(),
|
|
10
9
|
onAny: jest.fn(),
|
|
11
10
|
offAny: jest.fn(),
|
|
11
|
+
on: jest.fn(),
|
|
12
12
|
once: jest.fn(),
|
|
13
13
|
};
|
|
14
14
|
const io = jest.fn(() => mock);
|
|
@@ -16,26 +16,54 @@ jest.mock('socket.io-client', () => {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
it('should connect to Websocket', () => {
|
|
19
|
-
|
|
19
|
+
new Events({ workspaceId: '1', token: 'abcde', api: {} as Api });
|
|
20
|
+
expect(io).toHaveBeenCalledWith(
|
|
21
|
+
`https://api.eda.prisme.ai/workspaces/1/events`,
|
|
22
|
+
{
|
|
23
|
+
extraHeaders: {
|
|
24
|
+
Authorization: 'Bearer abcde',
|
|
25
|
+
},
|
|
26
|
+
withCredentials: true,
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should connect to Websocket with apiKey', () => {
|
|
32
|
+
new Events({
|
|
33
|
+
workspaceId: '1',
|
|
34
|
+
token: 'abcde',
|
|
35
|
+
apiKey: 'fghij',
|
|
36
|
+
api: {} as Api,
|
|
37
|
+
});
|
|
20
38
|
expect(io).toHaveBeenCalledWith(
|
|
21
39
|
`https://api.eda.prisme.ai/workspaces/1/events`,
|
|
22
40
|
{
|
|
23
41
|
extraHeaders: {
|
|
24
|
-
|
|
42
|
+
Authorization: 'Bearer abcde',
|
|
43
|
+
'x-prismeai-api-key': 'fghij',
|
|
25
44
|
},
|
|
45
|
+
withCredentials: true,
|
|
26
46
|
}
|
|
27
47
|
);
|
|
28
48
|
});
|
|
29
49
|
|
|
30
50
|
it('should disconnect to Websocket', () => {
|
|
31
|
-
const client = new Events(
|
|
51
|
+
const client = new Events({
|
|
52
|
+
workspaceId: '1',
|
|
53
|
+
token: 'abcde',
|
|
54
|
+
api: {} as Api,
|
|
55
|
+
});
|
|
32
56
|
(client as any).client.connected = true;
|
|
33
57
|
client.destroy();
|
|
34
58
|
expect(io().disconnect).toHaveBeenCalled();
|
|
35
59
|
});
|
|
36
60
|
|
|
37
61
|
it('should wait before disconnecting Websocket', () => {
|
|
38
|
-
const client = new Events(
|
|
62
|
+
const client = new Events({
|
|
63
|
+
workspaceId: '1',
|
|
64
|
+
token: 'abcde',
|
|
65
|
+
api: {} as Api,
|
|
66
|
+
});
|
|
39
67
|
const ioInstance = io();
|
|
40
68
|
(client as any).client.connected = false;
|
|
41
69
|
((client as any).client.once as jest.Mock).mockClear();
|
|
@@ -48,7 +76,11 @@ it('should wait before disconnecting Websocket', () => {
|
|
|
48
76
|
});
|
|
49
77
|
|
|
50
78
|
it('should listen to all events', () => {
|
|
51
|
-
const client = new Events(
|
|
79
|
+
const client = new Events({
|
|
80
|
+
workspaceId: '1',
|
|
81
|
+
token: 'abcde',
|
|
82
|
+
api: {} as Api,
|
|
83
|
+
});
|
|
52
84
|
const listener = () => null;
|
|
53
85
|
const off = client.all(listener);
|
|
54
86
|
expect(io().onAny).toHaveBeenCalledWith(listener);
|
package/lib/events.ts
CHANGED
|
@@ -1,20 +1,91 @@
|
|
|
1
1
|
import io, { Socket } from 'socket.io-client';
|
|
2
2
|
|
|
3
|
+
import { Api } from './api';
|
|
4
|
+
|
|
5
|
+
export type PayloadQuery = Record<string, string | string[]>;
|
|
6
|
+
export type OrQuery = PayloadQuery[];
|
|
7
|
+
|
|
8
|
+
export type SearchOptions = Omit<
|
|
9
|
+
PrismeaiAPI.EventsLongpolling.QueryParameters,
|
|
10
|
+
'query' | 'types'
|
|
11
|
+
> & {
|
|
12
|
+
payloadQuery?: PayloadQuery | OrQuery;
|
|
13
|
+
types?: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
3
16
|
export class Events {
|
|
4
17
|
protected client: Socket;
|
|
5
18
|
public workspaceId: string;
|
|
19
|
+
private filters: Record<string, any>[];
|
|
20
|
+
private listenedUserTopics: Map<string, string[]>;
|
|
21
|
+
private listeners: Map<string, Function[]> = new Map();
|
|
22
|
+
private lastReceivedEventDate: Date;
|
|
6
23
|
|
|
7
|
-
constructor(
|
|
8
|
-
workspaceId
|
|
9
|
-
token
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
constructor({
|
|
25
|
+
workspaceId,
|
|
26
|
+
token,
|
|
27
|
+
legacyToken,
|
|
28
|
+
apiKey,
|
|
29
|
+
apiHost = 'https://api.eda.prisme.ai',
|
|
30
|
+
filters,
|
|
31
|
+
api,
|
|
32
|
+
}: {
|
|
33
|
+
workspaceId: string;
|
|
34
|
+
token: string;
|
|
35
|
+
legacyToken?: string;
|
|
36
|
+
apiKey?: string;
|
|
37
|
+
apiHost?: string;
|
|
38
|
+
filters?: Record<string, any>;
|
|
39
|
+
api: Api;
|
|
40
|
+
}) {
|
|
12
41
|
this.workspaceId = workspaceId;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
42
|
+
const queryString = new URLSearchParams(filters || {}).toString();
|
|
43
|
+
const fullQueryString = queryString ? `?${queryString}` : '';
|
|
44
|
+
const extraHeaders: any = token
|
|
45
|
+
? {
|
|
46
|
+
Authorization: `Bearer ${token}`,
|
|
47
|
+
}
|
|
48
|
+
: { 'x-prismeai-token': legacyToken };
|
|
49
|
+
this.lastReceivedEventDate = new Date();
|
|
50
|
+
if (apiKey) {
|
|
51
|
+
extraHeaders['x-prismeai-api-key'] = apiKey;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.client = io(
|
|
55
|
+
`${apiHost}/workspaces/${workspaceId}/events${fullQueryString}`,
|
|
56
|
+
{
|
|
57
|
+
extraHeaders,
|
|
58
|
+
withCredentials: true,
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const onConnect = () => {
|
|
63
|
+
// Reset last filters
|
|
64
|
+
this.updateFilters({
|
|
65
|
+
payloadQuery: this.filters,
|
|
66
|
+
});
|
|
67
|
+
setTimeout(async () => {
|
|
68
|
+
const events = await api.getEvents(workspaceId, {
|
|
69
|
+
...this.filters[this.filters.length - 1],
|
|
70
|
+
afterDate: this.lastReceivedEventDate.toISOString(),
|
|
71
|
+
});
|
|
72
|
+
events.reverse().forEach((event) => {
|
|
73
|
+
(this.listeners.get(event.type) || []).forEach((listener) =>
|
|
74
|
+
listener(event)
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
}, 2000);
|
|
78
|
+
};
|
|
79
|
+
this.client.on('disconnect', () => {
|
|
80
|
+
if (!this.lastReceivedEventDate) {
|
|
81
|
+
this.lastReceivedEventDate = new Date();
|
|
82
|
+
}
|
|
83
|
+
this.client.off('connect', onConnect);
|
|
84
|
+
this.client.on('connect', onConnect);
|
|
17
85
|
});
|
|
86
|
+
|
|
87
|
+
this.filters = [filters || {}];
|
|
88
|
+
this.listenedUserTopics = new Map();
|
|
18
89
|
}
|
|
19
90
|
|
|
20
91
|
get socket() {
|
|
@@ -34,31 +105,71 @@ export class Events {
|
|
|
34
105
|
}
|
|
35
106
|
|
|
36
107
|
all(listener: (eventName: string, eventData: Prismeai.PrismeEvent) => void) {
|
|
37
|
-
this.client.onAny(
|
|
108
|
+
this.client.onAny((eventName: string, eventData: Prismeai.PrismeEvent) => {
|
|
109
|
+
this.lastReceivedEventDate = new Date(eventData?.createdAt);
|
|
110
|
+
return listener(eventName, eventData);
|
|
111
|
+
});
|
|
38
112
|
|
|
39
113
|
return () => this.client.offAny(listener);
|
|
40
114
|
}
|
|
41
115
|
|
|
42
|
-
on(
|
|
43
|
-
ev
|
|
44
|
-
|
|
45
|
-
) {
|
|
116
|
+
on(ev: string, listener: (eventData: Prismeai.PrismeEvent) => void) {
|
|
117
|
+
this.listeners.set(ev, [...(this.listeners.get(ev) || []), listener]);
|
|
118
|
+
|
|
46
119
|
this.client.on(ev, listener);
|
|
47
|
-
return () =>
|
|
120
|
+
return () => {
|
|
121
|
+
this.listeners.set(
|
|
122
|
+
ev,
|
|
123
|
+
(this.listeners.get(ev) || []).filter((l) => l !== listener)
|
|
124
|
+
);
|
|
125
|
+
this.client.off(ev, listener);
|
|
126
|
+
};
|
|
48
127
|
}
|
|
49
128
|
|
|
50
|
-
emit(event: string, payload?: any) {
|
|
129
|
+
emit(event: string, payload?: any, options?: any) {
|
|
51
130
|
this.client.emit('event', {
|
|
52
131
|
type: event,
|
|
53
132
|
payload,
|
|
133
|
+
options,
|
|
54
134
|
});
|
|
55
135
|
}
|
|
56
136
|
|
|
137
|
+
listenTopics({
|
|
138
|
+
event,
|
|
139
|
+
topics,
|
|
140
|
+
}: {
|
|
141
|
+
event: string;
|
|
142
|
+
topics: string | string[];
|
|
143
|
+
}) {
|
|
144
|
+
topics = Array.isArray(topics) ? topics : [topics];
|
|
145
|
+
|
|
146
|
+
this.listenedUserTopics.set(event, topics);
|
|
147
|
+
|
|
148
|
+
this.filters = [
|
|
149
|
+
{ ...this.filters[0] },
|
|
150
|
+
{
|
|
151
|
+
'target.userTopic': Array.from(this.listenedUserTopics).flatMap(
|
|
152
|
+
([_event, topics]) => topics
|
|
153
|
+
),
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
this.updateFilters({
|
|
157
|
+
payloadQuery: this.filters,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
updateFilters(filters: SearchOptions) {
|
|
162
|
+
this.client.emit('filters', filters);
|
|
163
|
+
}
|
|
164
|
+
|
|
57
165
|
once(
|
|
58
166
|
ev: string,
|
|
59
167
|
listener: (eventName: string, eventData: Prismeai.PrismeEvent) => void
|
|
60
168
|
) {
|
|
61
169
|
this.client.once(ev, listener);
|
|
170
|
+
return () => {
|
|
171
|
+
this.client.off(ev, listener);
|
|
172
|
+
};
|
|
62
173
|
}
|
|
63
174
|
|
|
64
175
|
close() {
|
package/lib/fetcher.test.ts
CHANGED
|
@@ -7,16 +7,15 @@ it('should fetch', async () => {
|
|
|
7
7
|
// @ts-ignore
|
|
8
8
|
global.fetch = jest.fn(() => ({
|
|
9
9
|
ok: true,
|
|
10
|
-
headers: [['foo', 'bar']],
|
|
11
|
-
|
|
12
|
-
return
|
|
10
|
+
headers: new Headers([['foo', 'bar']]),
|
|
11
|
+
text() {
|
|
12
|
+
return '';
|
|
13
13
|
},
|
|
14
14
|
clone() {
|
|
15
15
|
return { ...this };
|
|
16
16
|
},
|
|
17
17
|
}));
|
|
18
18
|
const o = await fetcher.get('url');
|
|
19
|
-
expect(o.headers).toEqual({ foo: 'bar' });
|
|
20
19
|
expect(global.fetch).toHaveBeenCalledWith('http/url', {
|
|
21
20
|
headers: expect.any(Headers),
|
|
22
21
|
method: 'GET',
|
|
@@ -31,9 +30,9 @@ it('should fetch with auth', async () => {
|
|
|
31
30
|
// @ts-ignore
|
|
32
31
|
global.fetch = jest.fn(() => ({
|
|
33
32
|
ok: true,
|
|
34
|
-
headers:
|
|
35
|
-
|
|
36
|
-
return
|
|
33
|
+
headers: new Headers(),
|
|
34
|
+
text() {
|
|
35
|
+
return '';
|
|
37
36
|
},
|
|
38
37
|
clone() {
|
|
39
38
|
return { ...this };
|
|
@@ -47,7 +46,33 @@ it('should fetch with auth', async () => {
|
|
|
47
46
|
});
|
|
48
47
|
const headers = (global.fetch as jest.Mock).mock.calls[0][1].headers;
|
|
49
48
|
expect(headers.get('Access-Control-Allow-Origin')).toBe('*');
|
|
50
|
-
expect(headers.get('x-prismeai-
|
|
49
|
+
expect(headers.get('x-prismeai-token')).toBe('token');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should fetch with api key', async () => {
|
|
53
|
+
const fetcher = new Fetcher('http/');
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
global.fetch = jest.fn(() => ({
|
|
56
|
+
ok: true,
|
|
57
|
+
headers: new Headers(),
|
|
58
|
+
text() {
|
|
59
|
+
return '';
|
|
60
|
+
},
|
|
61
|
+
clone() {
|
|
62
|
+
return { ...this };
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
fetcher.token = 'token';
|
|
66
|
+
fetcher.apiKey = 'api-key';
|
|
67
|
+
await fetcher.get('url');
|
|
68
|
+
expect(global.fetch).toHaveBeenCalledWith('http/url', {
|
|
69
|
+
headers: expect.any(Headers),
|
|
70
|
+
method: 'GET',
|
|
71
|
+
});
|
|
72
|
+
const headers = (global.fetch as jest.Mock).mock.calls[0][1].headers;
|
|
73
|
+
expect(headers.get('Access-Control-Allow-Origin')).toBe('*');
|
|
74
|
+
expect(headers.get('x-prismeai-token')).toBe('token');
|
|
75
|
+
expect(headers.get('x-prismeai-api-key')).toBe('api-key');
|
|
51
76
|
});
|
|
52
77
|
|
|
53
78
|
it('should fail to fetch', async () => {
|
|
@@ -103,7 +128,7 @@ it('should post', async () => {
|
|
|
103
128
|
// @ts-ignore
|
|
104
129
|
global.fetch = jest.fn(() => ({
|
|
105
130
|
ok: true,
|
|
106
|
-
headers:
|
|
131
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
107
132
|
json() {
|
|
108
133
|
return {};
|
|
109
134
|
},
|
|
@@ -123,7 +148,7 @@ it('should post with body', async () => {
|
|
|
123
148
|
// @ts-ignore
|
|
124
149
|
global.fetch = jest.fn(() => ({
|
|
125
150
|
ok: true,
|
|
126
|
-
headers:
|
|
151
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
127
152
|
json() {
|
|
128
153
|
return {};
|
|
129
154
|
},
|
|
@@ -139,12 +164,33 @@ it('should post with body', async () => {
|
|
|
139
164
|
});
|
|
140
165
|
});
|
|
141
166
|
|
|
167
|
+
it('should put', async () => {
|
|
168
|
+
const fetcher = new Fetcher('http/');
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
global.fetch = jest.fn(() => ({
|
|
171
|
+
ok: true,
|
|
172
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
173
|
+
json() {
|
|
174
|
+
return {};
|
|
175
|
+
},
|
|
176
|
+
clone() {
|
|
177
|
+
return { ...this };
|
|
178
|
+
},
|
|
179
|
+
}));
|
|
180
|
+
await fetcher.put('url', {});
|
|
181
|
+
expect(global.fetch).toHaveBeenCalledWith('http/url', {
|
|
182
|
+
headers: expect.any(Headers),
|
|
183
|
+
method: 'PUT',
|
|
184
|
+
body: '{}',
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
142
188
|
it('should patch', async () => {
|
|
143
189
|
const fetcher = new Fetcher('http/');
|
|
144
190
|
// @ts-ignore
|
|
145
191
|
global.fetch = jest.fn(() => ({
|
|
146
192
|
ok: true,
|
|
147
|
-
headers:
|
|
193
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
148
194
|
json() {
|
|
149
195
|
return {};
|
|
150
196
|
},
|
|
@@ -165,7 +211,7 @@ it('should delete', async () => {
|
|
|
165
211
|
// @ts-ignore
|
|
166
212
|
global.fetch = jest.fn(() => ({
|
|
167
213
|
ok: true,
|
|
168
|
-
headers:
|
|
214
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
169
215
|
json() {
|
|
170
216
|
return {};
|
|
171
217
|
},
|
|
@@ -185,7 +231,7 @@ it('should use formData', async () => {
|
|
|
185
231
|
// @ts-ignore
|
|
186
232
|
global.fetch = jest.fn(() => ({
|
|
187
233
|
ok: true,
|
|
188
|
-
headers:
|
|
234
|
+
headers: new Headers([['content-type', 'application/json']]),
|
|
189
235
|
json() {
|
|
190
236
|
return {};
|
|
191
237
|
},
|
package/lib/fetcher.ts
CHANGED
|
@@ -10,22 +10,48 @@ const headersAsObject = (headers: Headers) =>
|
|
|
10
10
|
{}
|
|
11
11
|
);
|
|
12
12
|
|
|
13
|
+
export type Fetched<T> = T & {
|
|
14
|
+
headers?: Record<string, any>;
|
|
15
|
+
};
|
|
16
|
+
|
|
13
17
|
export class Fetcher {
|
|
14
18
|
public host: string;
|
|
15
19
|
public token: string | null = null;
|
|
20
|
+
public legacyToken: string | null = null;
|
|
21
|
+
public overwriteClientId?: string;
|
|
22
|
+
private clientIdHeader?: string;
|
|
23
|
+
protected _apiKey: string | null = null;
|
|
24
|
+
public language: string | undefined;
|
|
25
|
+
public lastReceivedHeaders?: Record<string, any>;
|
|
16
26
|
|
|
17
|
-
constructor(host: string) {
|
|
27
|
+
constructor(host: string, clientIdHeader?: string) {
|
|
18
28
|
this.host = host;
|
|
29
|
+
this.clientIdHeader = clientIdHeader;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
set apiKey(apiKey: string) {
|
|
33
|
+
this._apiKey = apiKey;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
prepareRequest(url: string, options: RequestInit = {}) {
|
|
25
37
|
const headers = new Headers(options.headers || {});
|
|
26
38
|
|
|
27
|
-
if (this.token && !headers.has('
|
|
28
|
-
headers.append('
|
|
39
|
+
if (this.token && !headers.has('Authorization')) {
|
|
40
|
+
headers.append('Authorization', `Bearer ${this.token}`);
|
|
41
|
+
} else if (this.legacyToken && !headers.has('Authorization')) {
|
|
42
|
+
headers.append('x-prismeai-token', this.legacyToken);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this._apiKey && !headers.has('x-prismeai-apikey')) {
|
|
46
|
+
headers.append('x-prismeai-api-key', this._apiKey);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (this.language) {
|
|
50
|
+
headers.append('accept-language', this.language);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (options.body instanceof URLSearchParams) {
|
|
54
|
+
headers.set('Content-Type', 'application/x-www-form-urlencoded');
|
|
29
55
|
}
|
|
30
56
|
|
|
31
57
|
if (
|
|
@@ -35,13 +61,30 @@ export class Fetcher {
|
|
|
35
61
|
headers.append('Content-Type', 'application/json');
|
|
36
62
|
}
|
|
37
63
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
const fullUrl =
|
|
65
|
+
url.startsWith('http://') || url.startsWith('https://')
|
|
66
|
+
? url
|
|
67
|
+
: `${this.host}${url}`;
|
|
68
|
+
return global.fetch(fullUrl, {
|
|
69
|
+
credentials: 'include',
|
|
41
70
|
...options,
|
|
42
71
|
headers,
|
|
43
72
|
});
|
|
73
|
+
}
|
|
44
74
|
|
|
75
|
+
protected async _fetch<T>(
|
|
76
|
+
url: string,
|
|
77
|
+
options: RequestInit = {}
|
|
78
|
+
): Promise<T> {
|
|
79
|
+
const res = await this.prepareRequest(url, options);
|
|
80
|
+
if (options.redirect === 'manual' && res.status === 0) {
|
|
81
|
+
return { redirected: true } as T;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.lastReceivedHeaders = headersAsObject(res.headers);
|
|
85
|
+
if (this.clientIdHeader && this.lastReceivedHeaders[this.clientIdHeader]) {
|
|
86
|
+
this.overwriteClientId = this.lastReceivedHeaders[this.clientIdHeader];
|
|
87
|
+
}
|
|
45
88
|
if (!res.ok) {
|
|
46
89
|
let error;
|
|
47
90
|
try {
|
|
@@ -52,18 +95,28 @@ export class Fetcher {
|
|
|
52
95
|
throw error;
|
|
53
96
|
}
|
|
54
97
|
|
|
55
|
-
const
|
|
98
|
+
const contentType = res.headers.get('content-type');
|
|
99
|
+
if (contentType && contentType.includes('application/json')) {
|
|
100
|
+
try {
|
|
101
|
+
const response = (await res.json()) || {};
|
|
102
|
+
Object.defineProperty(response, 'headers', {
|
|
103
|
+
value: headersAsObject(res.headers),
|
|
104
|
+
configurable: false,
|
|
105
|
+
enumerable: false,
|
|
106
|
+
writable: false,
|
|
107
|
+
});
|
|
108
|
+
return response as T;
|
|
109
|
+
} catch (e) {
|
|
110
|
+
return {} as T;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const text = await res.text();
|
|
115
|
+
|
|
56
116
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
configurable: false,
|
|
61
|
-
enumerable: false,
|
|
62
|
-
writable: false,
|
|
63
|
-
});
|
|
64
|
-
return response;
|
|
65
|
-
} catch (e) {
|
|
66
|
-
return ((await clone.text()) as unknown) as T;
|
|
117
|
+
return JSON.parse(text) as T;
|
|
118
|
+
} catch {
|
|
119
|
+
return text as T;
|
|
67
120
|
}
|
|
68
121
|
}
|
|
69
122
|
|
|
@@ -73,10 +126,23 @@ export class Fetcher {
|
|
|
73
126
|
});
|
|
74
127
|
}
|
|
75
128
|
|
|
76
|
-
async post<T>(url: string, body?: Record<string, any
|
|
129
|
+
async post<T>(url: string, body?: Record<string, any>, opts?: RequestInit) {
|
|
77
130
|
return this._fetch<T>(url, {
|
|
78
131
|
method: 'POST',
|
|
79
|
-
body:
|
|
132
|
+
body:
|
|
133
|
+
body &&
|
|
134
|
+
!(body instanceof FormData) &&
|
|
135
|
+
!(body instanceof URLSearchParams)
|
|
136
|
+
? JSON.stringify(body)
|
|
137
|
+
: body,
|
|
138
|
+
...opts,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async put<T>(url: string, body: Record<string, any>) {
|
|
143
|
+
return this._fetch<T>(url, {
|
|
144
|
+
method: 'PUT',
|
|
145
|
+
body: JSON.stringify(body),
|
|
80
146
|
});
|
|
81
147
|
}
|
|
82
148
|
|
package/lib/types.ts
CHANGED
|
@@ -2,6 +2,10 @@ import '@prisme.ai/types';
|
|
|
2
2
|
|
|
3
3
|
export interface Workspace extends Prismeai.Workspace {
|
|
4
4
|
id: string;
|
|
5
|
+
updatedAt: Date;
|
|
6
|
+
updatedBy: string;
|
|
7
|
+
createdAt: Date;
|
|
8
|
+
createdBy: string;
|
|
5
9
|
}
|
|
6
10
|
|
|
7
11
|
export interface Event<DateType extends Date | string>
|
|
@@ -9,7 +13,7 @@ export interface Event<DateType extends Date | string>
|
|
|
9
13
|
createdAt: DateType;
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
export type EventsFilters = {
|
|
16
|
+
export type EventsFilters = Record<string, string> & {
|
|
13
17
|
afterDate?: PrismeaiAPI.EventsLongpolling.Parameters.AfterDate;
|
|
14
18
|
beforeDate?: PrismeaiAPI.EventsLongpolling.Parameters.BeforeDate;
|
|
15
19
|
text?: PrismeaiAPI.EventsLongpolling.Parameters.Text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisme.ai/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Communicate with Prisme.ai API",
|
|
5
5
|
"main": "dist/sdk/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@prisme.ai/types": "^1.0.9",
|
|
13
|
+
"pkce-challenge": "^3.1.0",
|
|
13
14
|
"qs": "^6.10.3",
|
|
14
15
|
"socket.io-client": "^4.4.1"
|
|
15
16
|
}
|