@bagelink/sdk 0.0.25 → 0.0.35
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 +1 -1
- package/src/index.ts +268 -271
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -15,304 +15,301 @@ export interface User {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
interface UploadOptions {
|
|
18
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
19
|
onUploadProgress?: (progressEvent: any) => void
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const axios = ax.create({
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
// withCredentials to true to send cookies with requests
|
|
24
|
+
withCredentials: true,
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
class DataRequest<T extends Tables = Tables> {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
data_table: T | Tables;
|
|
29
|
+
|
|
30
|
+
bagel: any;
|
|
31
|
+
|
|
32
|
+
itemID: string;
|
|
33
|
+
|
|
34
|
+
_filter: Record<string, any> = {};
|
|
35
|
+
|
|
36
|
+
constructor(table: T, bagel: Bagel) {
|
|
37
|
+
this.data_table = table;
|
|
38
|
+
this.bagel = bagel;
|
|
39
|
+
this.itemID = '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async post(item: Record<string, any>): Promise<Record<string, any>> {
|
|
43
|
+
if (!this.data_table) throw new Error('Data table not set');
|
|
44
|
+
const { data } = await axios.post(
|
|
41
45
|
`${this.bagel.host}/data/${this.data_table}`,
|
|
42
46
|
item,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
);
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
filter(filter: Record<string, any>) {
|
|
52
|
+
this._filter = filter;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
async get(): Promise<
|
|
53
57
|
TableToTypeMapping[T] | TableToTypeMapping[T][] | undefined
|
|
54
58
|
> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
? `?filter={${Object.entries(this._filter)
|
|
59
|
+
if (!this.data_table) throw new Error('Data table not set');
|
|
60
|
+
const filterStr = Object.keys(this._filter).length
|
|
61
|
+
? `?filter={${Object.entries(this._filter)
|
|
59
62
|
.map(([k, v]) => `${k}:${v}`)
|
|
60
63
|
.join(',')}}`
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
: '';
|
|
65
|
+
const url = `${this.bagel.host}/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ''
|
|
63
66
|
}${filterStr}`;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
throw new Error('Data table not set');
|
|
83
|
-
const { data } = await axios.delete(
|
|
67
|
+
try {
|
|
68
|
+
const { data } = await axios.get(url);
|
|
69
|
+
return data;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.log(err);
|
|
72
|
+
this.bagel.onError?.(err);
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
item(id: string) {
|
|
78
|
+
this.itemID = id;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async delete(): Promise<TableToTypeMapping[T][]> {
|
|
83
|
+
if (!this.data_table) throw new Error('Data table not set');
|
|
84
|
+
const { data } = await axios.delete(
|
|
84
85
|
`${this.bagel.host}/data/${this.data_table}/${this.itemID}`,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
throw new Error('Item ID not set');
|
|
95
|
-
const { data } = await axios.put(
|
|
86
|
+
);
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async put(updatedItem: Record<string, any>): Promise<Record<string, any>> {
|
|
91
|
+
const { data_table, itemID, bagel } = this;
|
|
92
|
+
if (!data_table) throw new Error('Data table not set');
|
|
93
|
+
if (!itemID) throw new Error('Item ID not set');
|
|
94
|
+
const { data } = await axios.put(
|
|
96
95
|
`${bagel.host}/data/${data_table}/${itemID}`,
|
|
97
96
|
updatedItem,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
);
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
function responses(key: string) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
const res: Record<string, string> = {
|
|
104
|
+
LOGIN_BAD_CREDENTIALS: 'Invalid username or password',
|
|
105
|
+
RESET_PASSWORD_BAD_TOKEN: 'This reset password link is invalid or expired.',
|
|
106
|
+
};
|
|
107
|
+
return res[key] || key;
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
class BagelAuth {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
throw err;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
111
|
+
constructor(private bagel: Bagel) {
|
|
112
|
+
this.bagel = bagel;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
user: User | null = null;
|
|
116
|
+
|
|
117
|
+
async validateUser(): Promise<User | null> {
|
|
118
|
+
try {
|
|
119
|
+
const usr = (await this.bagel.get<User>('/users/me'));
|
|
120
|
+
this.user = usr;
|
|
121
|
+
return usr;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
// this.bagel.onError?.(err);
|
|
124
|
+
console.log(err);
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async resetPassword(ctx: { token: string; password: string }) {
|
|
130
|
+
return this.bagel.post('auth/reset-password', ctx).catch((err) => {
|
|
131
|
+
throw responses(err.response?.data?.detail);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async forgotPassword(email: string) {
|
|
136
|
+
try {
|
|
137
|
+
await this.bagel.post('auth/forgot-password', { email });
|
|
138
|
+
} catch (err: any) {
|
|
139
|
+
throw responses(err?.response?.data?.detail);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async login(user: User): Promise<User | null> {
|
|
144
|
+
const formData = new FormData();
|
|
145
|
+
formData.append('username', user?.email || '');
|
|
146
|
+
formData.append('password', user?.password || '');
|
|
147
|
+
try {
|
|
148
|
+
await axios.post(`${this.bagel.host}/auth/cookie/login`, formData, {
|
|
149
|
+
headers: {
|
|
150
|
+
'Content-Type': 'multipart/form-data',
|
|
151
|
+
withCredentials: true,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
return this.validateUser();
|
|
155
|
+
} catch (err: any) {
|
|
156
|
+
throw responses(err.response?.data?.detail || 'LOGIN_BAD_CREDENTIALS');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async logout() {
|
|
161
|
+
try {
|
|
162
|
+
await axios.post(`${this.bagel.host}/auth/cookie/logout`);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
this.bagel.onError?.(err);
|
|
165
|
+
console.log(err);
|
|
166
|
+
}
|
|
167
|
+
this.user = null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async acceptInvite(token: string, user: Record<string, any>) {
|
|
171
|
+
await axios.post(`${this.bagel.host}/auth/accept-invite/${token}`, user);
|
|
172
|
+
await this.login(user as User);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async register(
|
|
176
|
+
user: Record<string, any>,
|
|
177
|
+
errors: Record<string, any>,
|
|
178
|
+
) {
|
|
179
|
+
try {
|
|
180
|
+
await axios.post<User>(`${this.bagel.host}/auth/register`, user);
|
|
181
|
+
return this.login(user as User);
|
|
182
|
+
} catch (err: any) {
|
|
183
|
+
console.error(err);
|
|
184
|
+
|
|
185
|
+
errors.email = err.response.data.detail;
|
|
186
|
+
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
195
190
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
191
|
export class Bagel {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
192
|
+
host: string;
|
|
193
|
+
|
|
194
|
+
// eslint-disable-next-line no-unused-vars
|
|
195
|
+
onError?: (err: any) => void;
|
|
196
|
+
|
|
197
|
+
constructor({ host, onError }: Record<string, any>) {
|
|
198
|
+
this.host = host;
|
|
199
|
+
this.onError = onError;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
read_table: Tables | null = null;
|
|
203
|
+
|
|
204
|
+
data(table: Tables): DataRequest<Tables> {
|
|
205
|
+
return new DataRequest(table, this);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
auth = new BagelAuth(this);
|
|
209
|
+
|
|
210
|
+
_endpointCleaner(endpoint: string) {
|
|
211
|
+
const url = `${endpoint.replace(/^\//, '').replace(/\/$/g, '')}`;
|
|
212
|
+
return url;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async api(
|
|
216
|
+
endpoint: string,
|
|
217
|
+
query?: Record<string, string>,
|
|
218
|
+
): Promise<Record<string, any>> {
|
|
219
|
+
if (query) {
|
|
220
|
+
const queryParams = Object.entries(query)
|
|
221
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
222
|
+
.join('&');
|
|
223
|
+
endpoint = `${endpoint}?${queryParams}`;
|
|
224
|
+
}
|
|
225
|
+
return axios.get(`${this.host}/api/${endpoint}`).then(({ data }: { data: any }) => data);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async get<T = Record<string, any>>(
|
|
229
|
+
endpoint: string,
|
|
230
|
+
query?: Record<string, any>,
|
|
231
|
+
): Promise<T> {
|
|
232
|
+
endpoint = this._endpointCleaner(endpoint);
|
|
233
|
+
if (endpoint.match(/undefined|null/)) throw new Error('Invalid endpoint');
|
|
234
|
+
if (query) {
|
|
235
|
+
const queryParams = Object.entries(query)
|
|
236
|
+
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
|
237
|
+
.filter(([_, value]) => !!value)
|
|
238
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
239
|
+
.join('&');
|
|
240
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
241
|
+
}
|
|
242
|
+
const url = `${this.host}/${endpoint}`;
|
|
243
|
+
return axios
|
|
244
|
+
.get(url)
|
|
245
|
+
.then(({ data }: { data: any }) => data)
|
|
246
|
+
.catch((err: any) => {
|
|
247
|
+
this.onError?.(err);
|
|
248
|
+
throw err;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async delete(endpoint: string): Promise<Record<string, any>> {
|
|
253
|
+
endpoint = this._endpointCleaner(endpoint);
|
|
254
|
+
return axios
|
|
255
|
+
.delete(`${this.host}/${endpoint}`)
|
|
256
|
+
.then(({ data }: { data: any }) => data)
|
|
257
|
+
.catch((err: any) => {
|
|
258
|
+
this.onError?.(err);
|
|
259
|
+
throw err;
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async put(endpoint: string, payload: any): Promise<Record<string, any>> {
|
|
264
|
+
endpoint = this._endpointCleaner(endpoint);
|
|
265
|
+
return axios
|
|
266
|
+
.put(`${this.host}/${endpoint}`, payload)
|
|
267
|
+
.then(({ data }: { data: any }) => data)
|
|
268
|
+
.catch((err: any) => {
|
|
269
|
+
this.onError?.(err);
|
|
270
|
+
throw err;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async patch(
|
|
275
|
+
endpoint: string,
|
|
279
276
|
payload: any = {},
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
277
|
+
): Promise<Record<string, any>> {
|
|
278
|
+
endpoint = this._endpointCleaner(endpoint);
|
|
279
|
+
return axios
|
|
280
|
+
.patch(`${this.host}/${endpoint}`, payload)
|
|
281
|
+
.then(({ data }: { data: any }) => data)
|
|
282
|
+
.catch((err: any) => {
|
|
283
|
+
this.onError?.(err);
|
|
284
|
+
throw err;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async post(
|
|
289
|
+
endpoint: string,
|
|
293
290
|
payload: any = {},
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
291
|
+
): Promise<Record<string, any>> {
|
|
292
|
+
endpoint = this._endpointCleaner(endpoint);
|
|
293
|
+
return axios
|
|
294
|
+
.post(`${this.host}/${endpoint}`, payload)
|
|
295
|
+
.then(({ data }: { data: any }) => data)
|
|
296
|
+
.catch((err: any) => {
|
|
297
|
+
this.onError?.(err);
|
|
298
|
+
throw err;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async uploadFile(file: File, options?: UploadOptions) {
|
|
303
|
+
const formData = new FormData();
|
|
304
|
+
formData.append('file', file);
|
|
305
|
+
// get an indication of the progress
|
|
306
|
+
|
|
307
|
+
const { data } = await axios.post(`${this.host}/files/upload`, formData, {
|
|
308
|
+
headers: {
|
|
309
|
+
'Content-Type': 'multipart/form-data',
|
|
310
|
+
},
|
|
311
|
+
onUploadProgress: options?.onUploadProgress,
|
|
312
|
+
});
|
|
313
|
+
return data;
|
|
314
|
+
}
|
|
318
315
|
}
|